<commit_before>// @ts-check
import documentOffset from 'document-offset';
import placementStrategies from './placementStrategies';
import PLACEMENT from './constants/placement';

export { PLACEMENT };
const { TOP, BOTTOM, LEFT, RIGHT } = PLACEMENT;
const verticalPlacements = [TOP, BOTTOM];
const horizontalPlacements = [LEFT, RIGHT];

/**
 * @typedef {typeof TOP| typeof BOTTOM} Placement
 *
 * @typedef {Object} SelfPosition
 * @prop {number} [top]
 * @prop {number} [left]
 *
 * @typedef {Object} ArrowPosition
 * @prop {number} [left]
 *
 * @typedef {SelfPosition} DocumentOffset
 *
 * @typedef {Object} ResultState
 * @prop {Placement} placement
 * @prop {SelfPosition} position
 * @prop {ArrowPosition} arrowPosition
 */

/**
 * Determine whether *wrapped component* should be placed above or below
 * its *anchor*.
 *
 * @returns {{ placement: Placement, remainingSpace: number }}
 */
export function getPlacementAndRemainingSpaceImpl({
  possiblePlacements,
  defaultPlacement,
  anchorRect,
  selfRect,
  distanceFromAnchor,
}) {
  const {
    canPlace,
    remainingSpace,
  } = placementStrategies[defaultPlacement].canPlace({
    anchorRect,
    selfRect,
    distanceFromAnchor,
  });
  if (canPlace) {
    return {
      placement: defaultPlacement,
      remainingSpace,
    };
  }
  const oppositePlacement = possiblePlacements.find(placement => placement !== defaultPlacement);
  const {
    canPlace: canPlaceInOpposite,
    remainingSpace: remainingSpaceInOpposite,
  } = placementStrategies[oppositePlacement].canPlace({
    anchorRect,
    selfRect,
    distanceFromAnchor,
  });
  if (canPlaceInOpposite) {
    return {
      placement: oppositePlacement,
      remainingSpace: remainingSpaceInOpposite,
    };
  }
  const placementWithLargerRemaingSpace = (
    remainingSpace >= remainingSpaceInOpposite
      ? defaultPlacement
      : oppositePlacement
  );
  return {
    placement: placementWithLargerRemaingSpace,
    remainingSpace: (
      placementWithLargerRemaingSpace === defaultPlacement
        ? remainingSpace
        : remainingSpaceInOpposite
    ),
  };
}

/**
 * Determine whether *wrapped component* should be placed above or below
 * its *anchor*.
 *
 * @returns {{ placement: Placement, remainingSpace: number }}
 */
export function getPlacementAndRemainingSpace({
  defaultPlacement,
  anchorRect,
  selfRect,
  distanceFromAnchor,
}) {
  const possiblePlacements = (
    verticalPlacements.includes(defaultPlacement)
      ? verticalPlacements
      : horizontalPlacements
  );
  return getPlacementAndRemainingSpaceImpl({
    possiblePlacements,
    defaultPlacement,
    anchorRect,
    selfRect,
    distanceFromAnchor,
  });
}

/**
 * Get position of *wrapped component* based on spacing around
 * the *anchor element*.
 *
 * It returns another getter function, taking `anchorNode` and `selfNode`
 * for computation, so it's possible to memoize it.
 *
 * ClientRect: element's positions related to browser window viewport.
 * Offset: element's position related to document.
 *
 * @param {Placement} defaultPlacement
 * @param {number} edgePadding<commit_msg>feat: simplify logic<commit_after>// @ts-check
import documentOffset from 'document-offset';
import placementStrategies from './placementStrategies';
import PLACEMENT from './constants/placement';

export { PLACEMENT };
const { TOP, BOTTOM, LEFT, RIGHT } = PLACEMENT;
const verticalPlacements = [TOP, BOTTOM];
const horizontalPlacements = [LEFT, RIGHT];

/**
 * @typedef {typeof TOP| typeof BOTTOM} Placement
 *
 * @typedef {Object} SelfPosition
 * @prop {number} [top]
 * @prop {number} [left]
 *
 * @typedef {Object} ArrowPosition
 * @prop {number} [left]
 *
 * @typedef {SelfPosition} DocumentOffset
 *
 * @typedef {Object} ResultState
 * @prop {Placement} placement
 * @prop {SelfPosition} position
 * @prop {ArrowPosition} arrowPosition
 */

/**
 * Determine whether *wrapped component* should be placed above or below
 * its *anchor*.
 *
 * @returns {{ placement: Placement, remainingSpace: number }}
 */
export function getPlacementAndRemainingSpace({
  defaultPlacement,
  anchorRect,
  selfRect,
  distanceFromAnchor,
}) {
  const possiblePlacements = (
    verticalPlacements.includes(defaultPlacement)
      ? verticalPlacements
      : horizontalPlacements
  );
  const defaultPlacementResult = placementStrategies[defaultPlacement].canPlace({
    anchorRect,
    selfRect,
    distanceFromAnchor,
  });
  if (defaultPlacementResult.canPlace) {
    return {
      placement: defaultPlacement,
      remainingSpace: defaultPlacementResult.remainingSpace,
    };
  }
  const oppositePlacement = possiblePlacements.find(placement => placement !== defaultPlacement);
  const oppositePlacementResult = placementStrategies[oppositePlacement].canPlace({
    anchorRect,
    selfRect,
    distanceFromAnchor,
  });
  const placement = (
    defaultPlacementResult.remainingSpace >= oppositePlacementResult.remainingSpace
      ? defaultPlacement
      : oppositePlacement
  );
  return {
    placement,
    remainingSpace: (
      placement === defaultPlacement
        ? defaultPlacementResult.remainingSpace
        : oppositePlacementResult.remainingSpace
    ),
  };
}

/**
 * Get position of *wrapped component* based on spacing around
 * the *anchor element*.
 *
 * It returns another getter function, taking `anchorNode` and `selfNode`
 * for computation, so it's possible to memoize it.
 *
 * ClientRect: element's positions related to browser window viewport.
 * Offset: element's position related to document.
 *
 * @param {Placement} defaultPlacement
 * @param {number} edgePadding
{'fraction_non_alphanumeric': 0.10114163396361042, 'fraction_numerical': 0.0, 'mean_word_length': 4.206128133704736, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3014308', 'n_tokens_mistral': 1633, 'n_tokens_neox': 1567, 'n_words': 406}