antd-tiny-vue/components/style/placementArrow.ts

192 lines
5.7 KiB
TypeScript

import type { CSSInterpolation, CSSObject } from '@antd-tiny-vue/cssinjs'
import type { AliasToken } from '../theme/internal'
import type { TokenWithCommonCls } from '../theme/util/genComponentStyleHook'
import { roundedArrow } from './roundedArrow'
export const MAX_VERTICAL_CONTENT_RADIUS = 8
export function getArrowOffset(options: { contentRadius: number; limitVerticalRadius?: boolean }) {
const maxVerticalContentRadius = MAX_VERTICAL_CONTENT_RADIUS
const { contentRadius, limitVerticalRadius } = options
const dropdownArrowOffset = contentRadius > 12 ? contentRadius + 2 : 12
const dropdownArrowOffsetVertical = limitVerticalRadius ? maxVerticalContentRadius : dropdownArrowOffset
return { dropdownArrowOffset, dropdownArrowOffsetVertical }
}
function isInject(valid: boolean, code: CSSObject): CSSObject {
if (!valid) return {}
return code
}
export default function getArrowStyle<Token extends TokenWithCommonCls<AliasToken>>(
token: Token,
options: {
colorBg: string
showArrowCls?: string
contentRadius?: number
limitVerticalRadius?: boolean
arrowDistance?: number
arrowPlacement?: {
left?: boolean
right?: boolean
top?: boolean
bottom?: boolean
}
}
): CSSInterpolation {
const { componentCls, sizePopupArrow, borderRadiusXS, borderRadiusOuter, boxShadowPopoverArrow } = token
const {
colorBg,
contentRadius = token.borderRadiusLG,
limitVerticalRadius,
arrowDistance = 0,
arrowPlacement = {
left: true,
right: true,
top: true,
bottom: true
}
} = options
const { dropdownArrowOffsetVertical, dropdownArrowOffset } = getArrowOffset({
contentRadius,
limitVerticalRadius
})
return {
[componentCls]: {
// ============================ Basic ============================
[`${componentCls}-arrow`]: [
{
position: 'absolute',
zIndex: 1, // lift it up so the menu wouldn't cask shadow on it
display: 'block',
...roundedArrow(sizePopupArrow, borderRadiusXS, borderRadiusOuter, colorBg, boxShadowPopoverArrow),
'&:before': {
background: colorBg
}
}
],
// ========================== Placement ==========================
// Here handle the arrow position and rotate stuff
// >>>>> Top
...isInject(!!arrowPlacement.top, {
[[`&-placement-top ${componentCls}-arrow`, `&-placement-topLeft ${componentCls}-arrow`, `&-placement-topRight ${componentCls}-arrow`].join(',')]: {
bottom: arrowDistance,
transform: 'translateY(100%) rotate(180deg)'
},
[`&-placement-top ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: '50%'
},
transform: 'translateX(-50%) translateY(100%) rotate(180deg)'
},
[`&-placement-topLeft ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: dropdownArrowOffset
}
},
[`&-placement-topRight ${componentCls}-arrow`]: {
right: {
_skip_check_: true,
value: dropdownArrowOffset
}
}
}),
// >>>>> Bottom
...isInject(!!arrowPlacement.bottom, {
[[`&-placement-bottom ${componentCls}-arrow`, `&-placement-bottomLeft ${componentCls}-arrow`, `&-placement-bottomRight ${componentCls}-arrow`].join(',')]: {
top: arrowDistance,
transform: `translateY(-100%)`
},
[`&-placement-bottom ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: '50%'
},
transform: `translateX(-50%) translateY(-100%)`
},
[`&-placement-bottomLeft ${componentCls}-arrow`]: {
left: {
_skip_check_: true,
value: dropdownArrowOffset
}
},
[`&-placement-bottomRight ${componentCls}-arrow`]: {
right: {
_skip_check_: true,
value: dropdownArrowOffset
}
}
}),
// >>>>> Left
...isInject(!!arrowPlacement.left, {
[[`&-placement-left ${componentCls}-arrow`, `&-placement-leftTop ${componentCls}-arrow`, `&-placement-leftBottom ${componentCls}-arrow`].join(',')]: {
right: {
_skip_check_: true,
value: arrowDistance
},
transform: 'translateX(100%) rotate(90deg)'
},
[`&-placement-left ${componentCls}-arrow`]: {
top: {
_skip_check_: true,
value: '50%'
},
transform: 'translateY(-50%) translateX(100%) rotate(90deg)'
},
[`&-placement-leftTop ${componentCls}-arrow`]: {
top: dropdownArrowOffsetVertical
},
[`&-placement-leftBottom ${componentCls}-arrow`]: {
bottom: dropdownArrowOffsetVertical
}
}),
// >>>>> Right
...isInject(!!arrowPlacement.right, {
[[`&-placement-right ${componentCls}-arrow`, `&-placement-rightTop ${componentCls}-arrow`, `&-placement-rightBottom ${componentCls}-arrow`].join(',')]: {
left: {
_skip_check_: true,
value: arrowDistance
},
transform: 'translateX(-100%) rotate(-90deg)'
},
[`&-placement-right ${componentCls}-arrow`]: {
top: {
_skip_check_: true,
value: '50%'
},
transform: 'translateY(-50%) translateX(-100%) rotate(-90deg)'
},
[`&-placement-rightTop ${componentCls}-arrow`]: {
top: dropdownArrowOffsetVertical
},
[`&-placement-rightBottom ${componentCls}-arrow`]: {
bottom: dropdownArrowOffsetVertical
}
})
}
}
}