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