@clayui/shared
Version:
ClayShared component
104 lines (103 loc) • 2.84 kB
JavaScript
/**
* SPDX-FileCopyrightText: © 2022 Liferay, Inc. <https://liferay.com>
* SPDX-License-Identifier: BSD-3-Clause
*/
import { useCallback, useEffect, useLayoutEffect } from 'react';
import { doAlign } from "./doAlign.js";
import { observeRect } from "./observeRect.js";
const ALIGN_INVERSE = {
0: 'TopCenter',
1: 'TopRight',
2: 'RightCenter',
3: 'BottomRight',
4: 'BottomCenter',
5: 'BottomLeft',
6: 'LeftCenter',
7: 'TopLeft',
8: 'RightTop',
9: 'RightBottom',
10: 'LeftTop',
11: 'LeftBottom'
};
const ALIGN_MAP = {
BottomCenter: ['tc', 'bc'],
BottomLeft: ['tl', 'bl'],
BottomRight: ['tr', 'br'],
LeftBottom: ['br', 'bl'],
LeftCenter: ['cr', 'cl'],
LeftTop: ['tr', 'tl'],
RightBottom: ['bl', 'br'],
RightCenter: ['cl', 'cr'],
RightTop: ['tl', 'tr'],
TopCenter: ['bc', 'tc'],
TopLeft: ['bl', 'tl'],
TopRight: ['br', 'tr']
};
/**
* For backwards compatability, we are creating a util here so that `metal-position`
* number values are used in the same manner and result in the same alignment direction.
*/
const getAlignPoints = val => ALIGN_MAP[ALIGN_INVERSE[val]];
const BOTTOM_OFFSET = [0, 4];
const LEFT_OFFSET = [-4, 0];
const RIGHT_OFFSET = [4, 0];
const TOP_OFFSET = [0, -4];
const OFFSET_MAP = {
bctc: TOP_OFFSET,
blbr: RIGHT_OFFSET,
bltl: TOP_OFFSET,
brbl: LEFT_OFFSET,
brtr: TOP_OFFSET,
clcr: RIGHT_OFFSET,
crcl: LEFT_OFFSET,
tcbc: BOTTOM_OFFSET,
tlbl: BOTTOM_OFFSET,
tltr: RIGHT_OFFSET,
trbr: BOTTOM_OFFSET,
trtl: LEFT_OFFSET
};
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect;
const defaultOffset = points => OFFSET_MAP[points.join('')];
export function useOverlayPosition(_ref) {
let {
alignmentByViewport,
alignmentPosition = 5,
autoBestAlign = true,
getOffset = defaultOffset,
isOpen,
ref,
triggerRef
} = _ref;
let deps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [isOpen];
const alignElement = useCallback(() => {
if (triggerRef.current && ref.current) {
let points = alignmentPosition;
if (typeof points === 'number') {
points = getAlignPoints(points);
}
doAlign({
offset: getOffset(points),
overflow: {
adjustX: autoBestAlign,
adjustY: autoBestAlign,
alwaysByViewport: alignmentByViewport
},
points,
sourceElement: ref.current,
targetElement: triggerRef.current
});
}
}, []);
useIsomorphicLayoutEffect(() => {
if (isOpen && triggerRef.current) {
alignElement();
return observeRect(triggerRef.current, alignElement);
}
}, deps);
useIsomorphicLayoutEffect(() => {
if (isOpen && ref.current) {
alignElement();
return observeRect(ref.current, alignElement);
}
}, deps);
}