You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

71 lines
1.9 KiB

2 months ago
  1. // @flow
  2. import type { Placement } from '../enums';
  3. import type { ModifierArguments, Modifier, Rect, Offsets } from '../types';
  4. import getBasePlacement from '../utils/getBasePlacement';
  5. import { top, left, right, placements } from '../enums';
  6. // eslint-disable-next-line import/no-unused-modules
  7. export type OffsetsFunction = ({
  8. popper: Rect,
  9. reference: Rect,
  10. placement: Placement,
  11. }) => [?number, ?number];
  12. type Offset = OffsetsFunction | [?number, ?number];
  13. // eslint-disable-next-line import/no-unused-modules
  14. export type Options = {
  15. offset: Offset,
  16. };
  17. export function distanceAndSkiddingToXY(
  18. placement: Placement,
  19. rects: { popper: Rect, reference: Rect },
  20. offset: Offset
  21. ): Offsets {
  22. const basePlacement = getBasePlacement(placement);
  23. const invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;
  24. let [skidding, distance] =
  25. typeof offset === 'function'
  26. ? offset({
  27. ...rects,
  28. placement,
  29. })
  30. : offset;
  31. skidding = skidding || 0;
  32. distance = (distance || 0) * invertDistance;
  33. return [left, right].indexOf(basePlacement) >= 0
  34. ? { x: distance, y: skidding }
  35. : { x: skidding, y: distance };
  36. }
  37. function offset({ state, options, name }: ModifierArguments<Options>) {
  38. const { offset = [0, 0] } = options;
  39. const data = placements.reduce((acc, placement) => {
  40. acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);
  41. return acc;
  42. }, {});
  43. const { x, y } = data[state.placement];
  44. if (state.modifiersData.popperOffsets != null) {
  45. state.modifiersData.popperOffsets.x += x;
  46. state.modifiersData.popperOffsets.y += y;
  47. }
  48. state.modifiersData[name] = data;
  49. }
  50. // eslint-disable-next-line import/no-unused-modules
  51. export type OffsetModifier = Modifier<'offset', Options>;
  52. export default ({
  53. name: 'offset',
  54. enabled: true,
  55. phase: 'main',
  56. requires: ['popperOffsets'],
  57. fn: offset,
  58. }: OffsetModifier);