/** * OmniMotion — 抽屉弹层 / Drawer (React 18+ · 纯 CSS 版本) * 复刻来源: apple.com — 侧边面板滑入 + 遮罩 * 用法: */ import { useEffect, useState } from "react"; export default function Drawer({ side = "right", open = false, onClose, children }) { const [mounted, setMounted] = useState(open); useEffect(() => { setMounted(open); }, [open]); return (
); } /* 样式(可直接放入全局 CSS) .mk-drawer { position: fixed; inset: 0; z-index: 60; pointer-events: none; } .mk-drawer[data-open="true"] { pointer-events: auto; } .mk-drawer__scrim { position: absolute; inset: 0; background: rgba(0, 0, 0, 0.34); opacity: 0; transition: opacity 280ms cubic-bezier(0.2, 0.8, 0.2, 1); } .mk-drawer[data-open="true"] .mk-drawer__scrim { opacity: 1; } .mk-drawer__panel { position: absolute; top: 0; bottom: 0; width: min(420px, 86vw); padding: 20px; background: var(--mk-card); border-left: 1px solid var(--mk-border); box-shadow: var(--mk-shadow-float-modal); transform: translateX(105%); transition: transform 280ms cubic-bezier(0.3, 0, 0, 1); } .mk-drawer--right .mk-drawer__panel { right: 0; } .mk-drawer--left .mk-drawer__panel { left: 0; border-left: 0; border-right: 1px solid var(--mk-border); transform: translateX(-105%); } .mk-drawer[data-open="true"] .mk-drawer__panel { transform: translateX(0); } @media (prefers-reduced-motion: reduce) { .mk-drawer__panel, .mk-drawer__scrim { transition: none } } */