Как по клику на элемент (динамически) определить - нужен ли элемент по середине экрана либо его невозможно отобразить целиком и скроллить страницу нужно до фрагмента, когда его можно начать читать (в топ видимой области).

Factory pattern in action

const scrollToIdCreator = ({ timeout, offsetTop, elementHeightLimit }: {
  timeout: number;
  offsetTop: number;
  elementHeightLimit: number;
}) => {
  let _timeout: NodeJS.Timeout | undefined = undefined

  return ({ id }: { id: string }) => {
    try {
      const nodeId = id
      const targetElm = document.getElementById(nodeId)
      if (!!targetElm) {
        if (!!_timeout) clearTimeout(_timeout)
        _timeout = setTimeout(() => {
          const curHeight = targetElm.getBoundingClientRect().height
          if (curHeight <= elementHeightLimit) {
            // NOTE: Скроллить до середины контента
            targetElm?.scrollIntoView({
              behavior: 'smooth',
              block: 'center',
              inline: 'nearest',
            })
          } else {
            // NOTE: Скроллить в начало контента
            const elementPosition = targetElm.getBoundingClientRect().top
            const offsetPosition = elementPosition + window.pageYOffset - offsetTop
            window.scrollTo({
              top: offsetPosition,
              behavior: 'smooth',
            });
          }
        }, timeout)

      }
      else
        console.log(`⚠️ Node not found nodeId=${id}`)
    } catch (err) {
      console.warn(err)
    }
  }
}

Usage (abstractions principle in action)

// STEP 1: Создаем обработчик с настройками
const scrollToId = scrollToIdCreator({
  // NOTE: Таймаут (и он же будет работать как дебаунс)
  timeout: 200,

  // NOTE: Настройка поведения скролла в зависимости от
  // высоты элемента: Если элемент меньше (или равен) лимиту высоты,
  // то скролл будет произведен так, чтоб элемент оказался
  // посередине высоты Viewport (область которую видит пользователь
  // на экране), иначе ориентиром будет верхняя граница Viewport
  elementHeightLimit: 300,

  // NOTE: Отступ от верхней границы (если элемент слишком большой
  // и не помещается в те рамки, которые мы указали
  // в параметре elementHeightLimit выше)
  offsetTop: 16,
})

// STEP 2: Вызываем обработчик, передаем id элемента
scrollToId({ id: 'element_id' })

Если нужна более гибкая настройка поведения скролла - можем легко дописать этот код: К примеру, вместо настройки elementHeightLimit мы можем передать коллбэк, который получит все интересующие параметры текущего элемента и функции для вызова двух вариантов скролла - которые могут быть вызваны в зависимости от проверок внутри коллбэка.