Как найти, какой чип был перенесен в следующую строку в автозаполнении пользовательского интерфейса материала

#javascript #reactjs #react-redux #react-hooks #material-ui

Вопрос:

У меня есть автозаполнение пользовательского интерфейса материала, подобное этому

автозаполнение

Я хочу вычислить, что четвертая микросхема перенесена на следующую строку, чтобы я мог выполнить дальнейшие вычисления. Есть ли способ сделать это в javascript/реагировать с помощью этого автозаполнения пользовательского интерфейса материала.

До сих пор документация пользовательского интерфейса материала автозаполнения не помогает в этом случае.

В основном то, что мне нужно сделать, это сделать число limitTags динамическим, чтобы при изменении ширины автозаполнения ограничения были установлены соответствующим образом и не были статическим числом. До сих пор моя идея состояла в том, чтобы рассчитать ширину каждого тега, добавить его в целом и сравнить с шириной контейнера. Это было сделано, но оно все еще вызывает ошибки, потому что, как вы можете видеть на прикрепленном изображении, несмотря на то, что общая длина тегов меньше ширины контейнера, ограничение равно 4, но должно быть 3, потому что последний переносится в следующую строку. А теперь я снова застрял. Как я могу определить, какой из самых первых тегов переносится в следующую строку, чтобы вычислить limitTags значение

Вот что я сделал до сих пор

 const DEFAULT_LIMIT_TAGS = -1;

const useLimitTags = (value, autoCompleteContainerRef, tagRef) => {
  const [limitTags, setLimitTags] = useState(DEFAULT_LIMIT_TAGS);
  const [autoCompleteContainerWidth, setAutoCompleteContainerWidth] = useState(0);
  const parentNode = useRef(null);

  useOnResize(autoCompleteContainerRef, setAutoCompleteContainerWidth);

  useLayoutEffect(() => {
    if (!parentNode.current amp;amp; tagRef?.current) {
      parentNode.current = tagRef.current.parentNode;
    }

    if (parentNode?.current) {
      const children = [...parentNode.current.children];
      const tags = children.slice(0, value.length);
      const endAdornmentWidth = children[children.length - 2].offsetWidth;
      const containerWidth = autoCompleteContainerWidth - endAdornmentWidth - 20; // 20 is the margin around the last closing icon and the dropd own icon

      const tagsCombinedWidth = tags.reduce((sum, child, index, arr) => {
        const tagsWidth = sum   child.offsetWidth;

        if (tagsWidth > containerWidth) {
          setLimitTags(index - 1);
          arr.splice(0, index   1); // break
        }

        return tagsWidth;
      }, 0);

      if (tagsCombinedWidth <= containerWidth) {
        setLimitTags(DEFAULT_LIMIT_TAGS);
      }
    }
  }, [value, autoCompleteContainerWidth, tagRef]);

  return limitTags;
};
 

And useOnResize is using Resize Observer API to calculate width of the changing autocomplete container

 import { useEffect } from 'react';
import isFunction from 'lodash-es/isFunction';

const useOnResize = (componentRef, callback) => {
  const shouldMountObserver = isFunction(callback) amp;amp; componentRef?.current;
  const resizeObserver =
    shouldMountObserver amp;amp;
    new ResizeObserver((entries) => {
      for (const entry of entries) {
        const { width: detectedWidth } = entry.contentRect;
        callback(detectedWidth);
      }
    });
  useEffect(() => {
    const savedRef = componentRef?.current;
    shouldMountObserver amp;amp; resizeObserver?.observe(componentRef.current);

    return () => {
      if (savedRef) {
        resizeObserver?.unobserve(savedRef);
      }
    }; // Resized observer omitted in deps array on purpose as it is not supposed to change between rerender
  }, [componentRef?.current]); // eslint-disable-line react-hooks/exhaustive-deps
};

export default useOnResize;