Внедрить Autocomplete в проекте JS, но без "триггера", такого как "@",

Я хочу реализовать что-то вроде редактора тегов. Тем не менее, это означало только для этих тегов, поэтому я хочу, чтобы пользователь видел всплывающие подсказки автозаполнения, не набирая что-то вроде @или #, как раз сам текст.

У меня есть что-то подобное, но всплывающее окно отображается в странных положениях на экране:

  • когда я сначала что-то печатаю и появляется всплывающее окно, оно появляется где-то рядом с верхним левым углом экрана
  • после создания первого объекта, когда нажимают SPACE и начинают печатать снова, всплывающее окно появляется на пару пикселей справа от него интуитивно понятным положением (то есть под первой буквой слова)

Вот пример известного редактора такого рода (хотя он не реализован в проекте), поэтому вы можете лучше понять, что я хочу реализовать.

Gmail email composer

Прежде всего, это функция, которая запускает всплывающие подсказки:

private onChange(editorState: EditorState) {
  const content = editorState.getCurrentContent();
  const selection = editorState.getSelection();
  const currentBlock = content.getBlockForKey(selection.getAnchorKey());

  if (selection.isCollapsed()) {
    const blockText = currentBlock.getText();
    const wordMeta = getWordAt(blockText, selection.getAnchorOffset());
    const categoryRegex = /([\w]*)/;
    const matches = wordMeta.word.match(categoryRegex);
    const existingEntity = currentBlock.getEntityAt(wordMeta.begin);

    if (!existingEntity && matches) {
      const categorySearch = matches[1];
      const selection = window.getSelection();
      if (this.state.autoComplete.search !== categorySearch && selection.rangeCount > 0) {
        const range = selection.getRangeAt(0);
        const boundingRect = getRangeBoundingClientRect(range);

        this.setState((prevState: StateType) => {
          let state = {
            autoComplete: {
              active: true,
              search: categorySearch,
              searchMeta: {
                begin: wordMeta.begin,
                end: wordMeta.end,
              },
            },
            selectionRect: prevState.selectionRect,
          };

          if (prevState.autoComplete.active === false) {
            state.selectionRect = boundingRect;
          }

          return state;
        });
      }
    }
  }

  this.props.onChange(editorState);
}

Вот функция getWordAt:

function getWordAt(text: string, pos: number): WordMeta
{
  const left = text.slice(0, pos + 1).search(/\S+$/);
  const right = text.slice(pos).search(/\s/);

  if (right < 0) {
    return {
      word: text.slice(left),
      begin: left,
      end: text.length,
    };
  }

  return {
    word: text.slice(left, right + pos),
    begin: left,
    end: right + pos,
  };
}

Что было бы лучшим способом обработки позиции всплывающего окна, а может быть, и стратегии для автозавершения такого рода? Спасибо!

Ответ 1

Вместо draft-js-typeahead - TypeaheadEditor - это компонент реакции, который обертывает редактор проекта. Вы можете использовать компонент React-Autosuggest, соответствующий требованиям. Он имеет настраиваемый рендеринг, который работает с элементами React. Это быстро и легко настраивается. Полностью контролировать рендеринг предложений.

Мы можем заставить его обрабатывать объекты JS вместо простых строк.

  1. реквизиты onSuggestionSelected - это обратный вызов, чтобы получить выбранное предложение
  2. Метод suggestionRenderer принимает предложение и возвращает разницу React

Проверьте React-Autosuggest.

Вы можете использовать вышеуказанный компонент с помощью настраиваемого блока рендеринга, в рамках вашего редактора можно вводить сложные богатые взаимодействия.

Вы должны сломать себе голову, чтобы достичь того, чего хотите, а не сразу. Это было мое предложение, благодаря которому вы могли бы достичь этого, но это было не так просто.