2023-02-15 10:21:28 +08:00
|
|
|
/* eslint-disable default-case */
|
|
|
|
import type { AlignType, BuildInPlacements } from '@rc-component/trigger';
|
|
|
|
import { getArrowOffset } from '../style/placementArrow';
|
2016-03-09 17:23:10 +08:00
|
|
|
|
2017-06-30 17:22:01 +08:00
|
|
|
export interface AdjustOverflow {
|
|
|
|
adjustX?: 0 | 1;
|
|
|
|
adjustY?: 0 | 1;
|
|
|
|
}
|
|
|
|
|
2016-11-30 16:43:35 +08:00
|
|
|
export interface PlacementsConfig {
|
2023-01-19 11:21:05 +08:00
|
|
|
arrowWidth: number;
|
2016-08-31 15:00:13 +08:00
|
|
|
arrowPointAtCenter?: boolean;
|
2019-06-16 20:51:47 +08:00
|
|
|
autoAdjustOverflow?: boolean | AdjustOverflow;
|
2023-01-19 11:21:05 +08:00
|
|
|
offset: number;
|
2023-02-15 10:21:28 +08:00
|
|
|
borderRadius: number;
|
2023-05-16 15:19:39 +08:00
|
|
|
visibleFirst?: boolean;
|
2016-07-29 14:45:06 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
export function getOverflowOptions(
|
|
|
|
placement: string,
|
|
|
|
arrowOffset: ReturnType<typeof getArrowOffset>,
|
|
|
|
arrowWidth: number,
|
|
|
|
autoAdjustOverflow?: boolean | AdjustOverflow,
|
|
|
|
) {
|
|
|
|
if (autoAdjustOverflow === false) {
|
|
|
|
return {
|
|
|
|
adjustX: false,
|
|
|
|
adjustY: false,
|
|
|
|
};
|
2016-08-31 13:50:50 +08:00
|
|
|
}
|
2017-06-30 17:22:01 +08:00
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
const overflow =
|
|
|
|
autoAdjustOverflow && typeof autoAdjustOverflow === 'object' ? autoAdjustOverflow : {};
|
2023-01-19 11:21:05 +08:00
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
const baseOverflow: AlignType['overflow'] = {};
|
|
|
|
|
|
|
|
switch (placement) {
|
2023-01-19 11:21:05 +08:00
|
|
|
case 'top':
|
|
|
|
case 'bottom':
|
2023-02-15 10:21:28 +08:00
|
|
|
baseOverflow.shiftX = arrowOffset.dropdownArrowOffset * 2 + arrowWidth;
|
|
|
|
break;
|
|
|
|
|
2023-01-19 11:21:05 +08:00
|
|
|
case 'left':
|
|
|
|
case 'right':
|
2023-02-15 10:21:28 +08:00
|
|
|
baseOverflow.shiftY = arrowOffset.dropdownArrowOffsetVertical * 2 + arrowWidth;
|
|
|
|
break;
|
2023-01-19 11:21:05 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
const mergedOverflow = {
|
|
|
|
...baseOverflow,
|
|
|
|
...overflow,
|
|
|
|
};
|
|
|
|
|
|
|
|
// Support auto shift
|
|
|
|
if (!mergedOverflow.shiftX) {
|
|
|
|
mergedOverflow.adjustX = true;
|
|
|
|
}
|
|
|
|
if (!mergedOverflow.shiftY) {
|
|
|
|
mergedOverflow.adjustY = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return mergedOverflow;
|
2023-01-19 11:21:05 +08:00
|
|
|
}
|
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
type PlacementType = keyof BuildInPlacements;
|
|
|
|
|
|
|
|
const PlacementAlignMap: BuildInPlacements = {
|
|
|
|
left: {
|
|
|
|
points: ['cr', 'cl'],
|
|
|
|
},
|
|
|
|
right: {
|
|
|
|
points: ['cl', 'cr'],
|
|
|
|
},
|
|
|
|
top: {
|
|
|
|
points: ['bc', 'tc'],
|
|
|
|
},
|
|
|
|
bottom: {
|
|
|
|
points: ['tc', 'bc'],
|
|
|
|
},
|
|
|
|
topLeft: {
|
|
|
|
points: ['bl', 'tl'],
|
|
|
|
},
|
|
|
|
leftTop: {
|
|
|
|
points: ['tr', 'tl'],
|
|
|
|
},
|
|
|
|
topRight: {
|
|
|
|
points: ['br', 'tr'],
|
|
|
|
},
|
|
|
|
rightTop: {
|
|
|
|
points: ['tl', 'tr'],
|
|
|
|
},
|
|
|
|
bottomRight: {
|
|
|
|
points: ['tr', 'br'],
|
|
|
|
},
|
|
|
|
rightBottom: {
|
|
|
|
points: ['bl', 'br'],
|
|
|
|
},
|
|
|
|
bottomLeft: {
|
|
|
|
points: ['tl', 'bl'],
|
|
|
|
},
|
|
|
|
leftBottom: {
|
|
|
|
points: ['br', 'bl'],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const ArrowCenterPlacementAlignMap: BuildInPlacements = {
|
|
|
|
topLeft: {
|
|
|
|
points: ['bl', 'tc'],
|
|
|
|
},
|
|
|
|
leftTop: {
|
|
|
|
points: ['tr', 'cl'],
|
|
|
|
},
|
|
|
|
topRight: {
|
|
|
|
points: ['br', 'tc'],
|
|
|
|
},
|
|
|
|
rightTop: {
|
|
|
|
points: ['tl', 'cr'],
|
|
|
|
},
|
|
|
|
bottomRight: {
|
|
|
|
points: ['tr', 'bc'],
|
|
|
|
},
|
|
|
|
rightBottom: {
|
|
|
|
points: ['bl', 'cr'],
|
|
|
|
},
|
|
|
|
bottomLeft: {
|
|
|
|
points: ['tl', 'bc'],
|
|
|
|
},
|
|
|
|
leftBottom: {
|
|
|
|
points: ['br', 'cl'],
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const DisableAutoArrowList: Set<keyof BuildInPlacements> = new Set([
|
|
|
|
'topLeft',
|
|
|
|
'topRight',
|
|
|
|
'bottomLeft',
|
|
|
|
'bottomRight',
|
|
|
|
'leftTop',
|
|
|
|
'leftBottom',
|
|
|
|
'rightTop',
|
|
|
|
'rightBottom',
|
|
|
|
]);
|
|
|
|
|
2020-03-04 21:03:08 +08:00
|
|
|
export default function getPlacements(config: PlacementsConfig) {
|
2023-05-16 15:19:39 +08:00
|
|
|
const { arrowWidth, autoAdjustOverflow, arrowPointAtCenter, offset, borderRadius, visibleFirst } =
|
|
|
|
config;
|
2023-01-19 11:21:05 +08:00
|
|
|
const halfArrowWidth = arrowWidth / 2;
|
|
|
|
|
2023-02-15 10:21:28 +08:00
|
|
|
const placementMap: BuildInPlacements = {};
|
|
|
|
|
|
|
|
Object.keys(PlacementAlignMap).forEach((key: PlacementType) => {
|
|
|
|
const template =
|
|
|
|
(arrowPointAtCenter && ArrowCenterPlacementAlignMap[key]) || PlacementAlignMap[key];
|
|
|
|
|
|
|
|
const placementInfo = {
|
|
|
|
...template,
|
|
|
|
offset: [0, 0],
|
|
|
|
};
|
|
|
|
placementMap[key] = placementInfo;
|
|
|
|
|
|
|
|
// Disable autoArrow since design is fixed position
|
|
|
|
if (DisableAutoArrowList.has(key)) {
|
|
|
|
placementInfo.autoArrow = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Static offset
|
|
|
|
switch (key) {
|
|
|
|
case 'top':
|
|
|
|
case 'topLeft':
|
|
|
|
case 'topRight':
|
|
|
|
placementInfo.offset[1] = -halfArrowWidth - offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'bottom':
|
|
|
|
case 'bottomLeft':
|
|
|
|
case 'bottomRight':
|
|
|
|
placementInfo.offset[1] = halfArrowWidth + offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'left':
|
|
|
|
case 'leftTop':
|
|
|
|
case 'leftBottom':
|
|
|
|
placementInfo.offset[0] = -halfArrowWidth - offset;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'right':
|
|
|
|
case 'rightTop':
|
|
|
|
case 'rightBottom':
|
|
|
|
placementInfo.offset[0] = halfArrowWidth + offset;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dynamic offset
|
|
|
|
const arrowOffset = getArrowOffset({
|
|
|
|
contentRadius: borderRadius,
|
|
|
|
limitVerticalRadius: true,
|
|
|
|
});
|
|
|
|
|
|
|
|
if (arrowPointAtCenter) {
|
|
|
|
switch (key) {
|
|
|
|
case 'topLeft':
|
|
|
|
case 'bottomLeft':
|
|
|
|
placementInfo.offset[0] = -arrowOffset.dropdownArrowOffset - halfArrowWidth;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'topRight':
|
|
|
|
case 'bottomRight':
|
|
|
|
placementInfo.offset[0] = arrowOffset.dropdownArrowOffset + halfArrowWidth;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'leftTop':
|
|
|
|
case 'rightTop':
|
|
|
|
placementInfo.offset[1] = -arrowOffset.dropdownArrowOffset - halfArrowWidth;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'leftBottom':
|
|
|
|
case 'rightBottom':
|
|
|
|
placementInfo.offset[1] = arrowOffset.dropdownArrowOffset + halfArrowWidth;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Overflow
|
|
|
|
placementInfo.overflow = getOverflowOptions(key, arrowOffset, arrowWidth, autoAdjustOverflow);
|
2023-05-16 15:19:39 +08:00
|
|
|
|
|
|
|
// VisibleFirst
|
|
|
|
if (visibleFirst) {
|
|
|
|
placementInfo.htmlRegion = 'visibleFirst';
|
|
|
|
}
|
2017-06-30 17:22:01 +08:00
|
|
|
});
|
2023-02-15 10:21:28 +08:00
|
|
|
|
2017-06-30 17:22:01 +08:00
|
|
|
return placementMap;
|
2016-03-09 17:23:10 +08:00
|
|
|
}
|