/** * Transitions Components - Lynx 版 MUI Transitions * * 使用 CSS animations 和 transitions 实现过渡动画 * 包含: * - Fade: 淡入淡出 * - Collapse: 折叠展开 * - Grow: 放大出现 * - Slide: 滑动 * - Zoom: 缩放 */ import './transitions.css' // ============================================= // 通用过渡属性 // ============================================= export interface TransitionProps { /** 是否显示 */ in?: boolean /** 子元素 */ children?: any /** 过渡时长 (ms) */ timeout?: number | { enter?: number; exit?: number } /** 缓动函数 */ easing?: string | { enter?: string; exit?: string } /** 首次渲染时是否执行动画 */ appear?: boolean /** 进入回调 */ onEnter?: () => void /** 进入完成回调 */ onEntered?: () => void /** 退出回调 */ onExit?: () => void /** 退出完成回调 */ onExited?: () => void /** 自定义类名 */ className?: string /** 内联样式 */ style?: Record } // ============================================= // Fade 组件 - 淡入淡出 // ============================================= export interface FadeProps extends TransitionProps {} export function Fade(props: FadeProps) { const { in: inProp = false, children, timeout = 300, className, style, ...other } = props const duration = typeof timeout === 'number' ? timeout : timeout.enter || 300 const computedStyle: Record = { opacity: inProp ? 1 : 0, transition: `opacity ${duration}ms ease-in-out`, ...style, } const classes = [ 'MuiTransition-root', 'MuiFade-root', inProp ? 'MuiFade-entered' : 'MuiFade-exited', className, ].filter(Boolean).join(' ') return ( {children} ) } // ============================================= // Collapse 组件 - 折叠展开 // ============================================= export interface CollapseProps extends TransitionProps { /** 折叠方向 */ orientation?: 'vertical' | 'horizontal' /** 折叠后的尺寸 */ collapsedSize?: number | string } export function Collapse(props: CollapseProps) { const { in: inProp = false, children, timeout = 300, orientation = 'vertical', collapsedSize = 0, className, style, ...other } = props const duration = typeof timeout === 'number' ? timeout : timeout.enter || 300 const isVertical = orientation === 'vertical' const computedStyle: Record = { overflow: 'hidden', transition: `${isVertical ? 'height' : 'width'} ${duration}ms ease-in-out`, ...(isVertical ? { height: inProp ? 'auto' : collapsedSize, } : { width: inProp ? 'auto' : collapsedSize, }), ...style, } const classes = [ 'MuiTransition-root', 'MuiCollapse-root', `MuiCollapse-${orientation}`, inProp ? 'MuiCollapse-entered' : 'MuiCollapse-hidden', className, ].filter(Boolean).join(' ') return ( {children} ) } // ============================================= // Grow 组件 - 放大出现 // ============================================= export interface GrowProps extends TransitionProps {} export function Grow(props: GrowProps) { const { in: inProp = false, children, timeout = 300, className, style, ...other } = props const duration = typeof timeout === 'number' ? timeout : timeout.enter || 300 const computedStyle: Record = { opacity: inProp ? 1 : 0, transform: inProp ? 'scale(1)' : 'scale(0.75)', transition: `opacity ${duration}ms ease-in-out, transform ${duration}ms ease-in-out`, ...style, } const classes = [ 'MuiTransition-root', 'MuiGrow-root', inProp ? 'MuiGrow-entered' : 'MuiGrow-exited', className, ].filter(Boolean).join(' ') return ( {children} ) } // ============================================= // Slide 组件 - 滑动 // ============================================= export interface SlideProps extends TransitionProps { /** 滑动方向 */ direction?: 'left' | 'right' | 'up' | 'down' } export function Slide(props: SlideProps) { const { in: inProp = false, children, timeout = 300, direction = 'down', className, style, ...other } = props const duration = typeof timeout === 'number' ? timeout : timeout.enter || 300 // 滑动偏移量 const getTransform = () => { if (inProp) return 'translate(0, 0)' switch (direction) { case 'left': return 'translateX(100%)' case 'right': return 'translateX(-100%)' case 'up': return 'translateY(100%)' case 'down': return 'translateY(-100%)' default: return 'translate(0, 0)' } } const computedStyle: Record = { transform: getTransform(), transition: `transform ${duration}ms ease-in-out`, ...style, } const classes = [ 'MuiTransition-root', 'MuiSlide-root', `MuiSlide-direction-${direction}`, inProp ? 'MuiSlide-entered' : 'MuiSlide-exited', className, ].filter(Boolean).join(' ') return ( {children} ) } // ============================================= // Zoom 组件 - 缩放 // ============================================= export interface ZoomProps extends TransitionProps {} export function Zoom(props: ZoomProps) { const { in: inProp = false, children, timeout = 300, className, style, ...other } = props const duration = typeof timeout === 'number' ? timeout : timeout.enter || 300 const computedStyle: Record = { transform: inProp ? 'scale(1)' : 'scale(0)', transition: `transform ${duration}ms ease-in-out`, ...style, } const classes = [ 'MuiTransition-root', 'MuiZoom-root', inProp ? 'MuiZoom-entered' : 'MuiZoom-exited', className, ].filter(Boolean).join(' ') return ( {children} ) } // 导出所有 export default { Fade, Collapse, Grow, Slide, Zoom, }