ant-design/components/style/roundedArrow.ts
2024-08-06 00:04:28 +08:00

95 lines
2.8 KiB
TypeScript

/* eslint-disable import/prefer-default-export */
import type { CSSObject } from '@ant-design/cssinjs';
import { unit } from '@ant-design/cssinjs';
import type { AliasToken } from '../theme/interface';
import type { CSSUtil } from '../theme/internal';
export interface ArrowToken {
/** @internal */
arrowShadowWidth: number;
/** @internal */
arrowPath: string;
/** @internal */
arrowPolygon: string;
}
export function getArrowToken(token: AliasToken): ArrowToken {
const { sizePopupArrow, borderRadiusXS, borderRadiusOuter } = token;
const unitWidth = sizePopupArrow / 2;
const ax = 0;
const ay = unitWidth;
const bx = (borderRadiusOuter * 1) / Math.sqrt(2);
const by = unitWidth - borderRadiusOuter * (1 - 1 / Math.sqrt(2));
const cx = unitWidth - borderRadiusXS * (1 / Math.sqrt(2));
const cy = borderRadiusOuter * (Math.sqrt(2) - 1) + borderRadiusXS * (1 / Math.sqrt(2));
const dx = 2 * unitWidth - cx;
const dy = cy;
const ex = 2 * unitWidth - bx;
const ey = by;
const fx = 2 * unitWidth - ax;
const fy = ay;
const shadowWidth = unitWidth * Math.sqrt(2) + borderRadiusOuter * (Math.sqrt(2) - 2);
const polygonOffset = borderRadiusOuter * (Math.sqrt(2) - 1);
const arrowPolygon = `polygon(${polygonOffset}px 100%, 50% ${polygonOffset}px, ${
2 * unitWidth - polygonOffset
}px 100%, ${polygonOffset}px 100%)`;
const arrowPath = `path('M ${ax} ${ay} A ${borderRadiusOuter} ${borderRadiusOuter} 0 0 0 ${bx} ${by} L ${cx} ${cy} A ${borderRadiusXS} ${borderRadiusXS} 0 0 1 ${dx} ${dy} L ${ex} ${ey} A ${borderRadiusOuter} ${borderRadiusOuter} 0 0 0 ${fx} ${fy} Z')`;
return {
arrowShadowWidth: shadowWidth,
arrowPath,
arrowPolygon,
};
}
export const genRoundedArrow = <T extends AliasToken & ArrowToken & CSSUtil>(
token: T,
bgColor: string,
boxShadow: string,
): CSSObject => {
const { sizePopupArrow, arrowPolygon, arrowPath, arrowShadowWidth, borderRadiusXS, calc } = token;
return {
pointerEvents: 'none',
width: sizePopupArrow,
height: sizePopupArrow,
overflow: 'hidden',
'&::before': {
position: 'absolute',
bottom: 0,
insetInlineStart: 0,
width: sizePopupArrow,
height: calc(sizePopupArrow).div(2).equal(),
background: bgColor,
clipPath: {
_multi_value_: true,
value: [arrowPolygon, arrowPath],
},
content: '""',
},
'&::after': {
content: '""',
position: 'absolute',
width: arrowShadowWidth,
height: arrowShadowWidth,
bottom: 0,
insetInline: 0,
margin: 'auto',
borderRadius: {
_skip_check_: true,
value: `0 0 ${unit(borderRadiusXS)} 0`,
},
transform: 'translateY(50%) rotate(-135deg)',
boxShadow,
zIndex: 0,
background: 'transparent',
},
};
};