71 lines
2.1 KiB
TypeScript
71 lines
2.1 KiB
TypeScript
import React, { memo } from 'react'
|
||
import { Path, Skia } from '@shopify/react-native-skia'
|
||
|
||
export type ParallelogramShadowProps = {
|
||
width: number
|
||
height: number
|
||
skewOffset: number
|
||
padding: number
|
||
/** 平行四边形主体的高度(即底边所在的 y),不传则等于 height */
|
||
baseHeight?: number
|
||
/** 阴影整体偏移量,默认 2 像素 */
|
||
offset?: number
|
||
/** 阴影颜色,默认 #323232 */
|
||
color?: string
|
||
/** 阴影线粗细,默认 3 像素 */
|
||
strokeWidth?: number
|
||
}
|
||
|
||
/**
|
||
* 通用平行四边形按钮/卡片的底部 + 右侧硬阴影
|
||
*
|
||
* 约定:
|
||
* - 与主体外侧的黑色描边紧贴
|
||
* - 整体向右下偏移 offset 像素
|
||
*/
|
||
const ParallelogramShadow = memo<ParallelogramShadowProps>(function ParallelogramShadow({
|
||
width,
|
||
height,
|
||
skewOffset,
|
||
padding,
|
||
baseHeight,
|
||
offset = 2,
|
||
color = '#323232',
|
||
strokeWidth = 3,
|
||
}) {
|
||
const skiaColor = Skia.Color(color)
|
||
const h = baseHeight ?? height
|
||
// 只有在提供 baseHeight(即有额外画布空间)时才再往外多挪 1 像素,避免压住原始边框又不被裁剪
|
||
const extraOffsetY = baseHeight ? 1 : 0
|
||
|
||
return (
|
||
<>
|
||
{/* 底部阴影线 */}
|
||
<Path
|
||
path={Skia.Path.Make()
|
||
// 当有 baseHeight 时:相对于主体底边再向下挪 1px;否则保持在 canvas 内部
|
||
.moveTo(padding + offset, h - padding + offset + extraOffsetY)
|
||
.lineTo(width - skewOffset - padding + offset, h - padding + offset + extraOffsetY)}
|
||
color={skiaColor}
|
||
style="stroke"
|
||
strokeWidth={strokeWidth}
|
||
/>
|
||
{/* 右侧阴影线 */}
|
||
<Path
|
||
path={Skia.Path.Make()
|
||
// 右侧阴影:仅在垂直方向多挪 1px,水平方向仍保持在 canvas 内
|
||
.moveTo(width - skewOffset - padding + offset, h - padding + offset + extraOffsetY)
|
||
.lineTo(width - padding + offset, padding + offset + extraOffsetY)}
|
||
color={skiaColor}
|
||
style="stroke"
|
||
strokeWidth={strokeWidth}
|
||
/>
|
||
</>
|
||
)
|
||
})
|
||
|
||
ParallelogramShadow.displayName = 'ParallelogramShadow'
|
||
|
||
export default ParallelogramShadow
|
||
|