goblindegook/littlefoot

View on GitHub
src/dom/layout.ts

Summary

Maintainability
A
0 mins
Test Coverage
import { getStyle } from '@pacote/get-style'
import { pixels } from '@pacote/pixels'
import { addClass, removeClass } from './element'

export const CLASS_TOOLTIP = 'littlefoot__tooltip'

export type Position = 'above' | 'below'

function getLeftRelative(element: HTMLElement): number {
  const marginLeft = Number.parseFloat(getStyle(element, 'marginLeft'))
  const width = element.offsetWidth - marginLeft
  const left = element.getBoundingClientRect().left + width / 2

  return left / window.innerWidth
}

export function getLeftInPixels(
  content: HTMLElement,
  button: HTMLElement,
): number {
  const maxWidth = content.offsetWidth
  const leftRelative = getLeftRelative(button)
  const buttonMarginLeft = Number.parseInt(getStyle(button, 'marginLeft'), 10)
  return -leftRelative * maxWidth + buttonMarginLeft + button.offsetWidth / 2
}

export function getMaxHeight(element: HTMLElement) {
  return Math.round(pixels(getStyle(element, 'maxHeight'), element))
}

function getFootnotePosition(
  button: HTMLElement,
  popover: HTMLElement,
): [Position, number] {
  const marginSize = Number.parseInt(getStyle(popover, 'marginTop'), 10)
  const popoverHeight = 2 * marginSize + popover.offsetHeight
  const roomAbove = button.getBoundingClientRect().top + button.offsetHeight / 2
  const roomBelow = window.innerHeight - roomAbove

  return roomBelow >= popoverHeight || roomBelow >= roomAbove
    ? ['below', roomBelow - marginSize - 15]
    : ['above', roomAbove - marginSize - 15]
}

export function repositionPopover(
  popover: HTMLElement,
  button: HTMLElement,
  current: Position,
): [Position, number] {
  const [next, room] = getFootnotePosition(button, popover)

  if (current !== next) {
    removeClass(popover, 'is-' + current)
    addClass(popover, 'is-' + next)
    const transformX = getLeftRelative(button) * 100 + '%'
    const transformY = next === 'above' ? '100%' : '0'
    popover.style.transformOrigin = transformX + ' ' + transformY
  }

  return [next, room]
}

export function repositionTooltip(
  popover: HTMLElement,
  button: HTMLElement,
): void {
  const tooltip = popover.querySelector<HTMLElement>('.' + CLASS_TOOLTIP)

  if (tooltip) {
    tooltip.style.left = getLeftRelative(button) * 100 + '%'
  }
}