/** * MetonaToast Styles - 样式管理 * @module styles * @version 2.0.0 * @description 样式注入、更新和主题管理 */ import { THEMES } from './constants.js'; // 样式缓存 let injectedStyles = null; let styleElement = null; /** * 生成CSS样式 * @param {Object} theme - 主题配置 * @returns {string} CSS字符串 */ const generateCSS = (theme) => { return ` /* MetonaToast 基础样式 */ .met-container { pointer-events: none; display: flex; flex-direction: column; gap: 12px; box-sizing: border-box; padding: 24px; max-width: 100vw; position: fixed; z-index: 9999; } /* 位置样式 — 顶部位置用 column-reverse,新 toast 出现在最上方 */ .met-container.top-left { top: 0; left: 0; align-items: flex-start; flex-direction: column-reverse; } .met-container.top-center { top: 0; left: 0; right: 0; align-items: center; flex-direction: column-reverse; } .met-container.top-right { top: 0; right: 0; align-items: flex-end; flex-direction: column-reverse; } .met-container.bottom-left { bottom: 0; left: 0; align-items: flex-start; flex-direction: column-reverse; } .met-container.bottom-center { bottom: 0; left: 0; right: 0; align-items: center; flex-direction: column-reverse; } .met-container.bottom-right { bottom: 0; right: 0; align-items: flex-end; flex-direction: column-reverse; } /* Toast基础样式 */ .met-toast { position: relative; display: flex; align-items: flex-start; gap: 12px; padding: 14px 16px; border-radius: 12px; box-sizing: border-box; backdrop-filter: blur(14px) saturate(180%); -webkit-backdrop-filter: blur(14px) saturate(180%); font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Microsoft YaHei", sans-serif; user-select: none; -webkit-user-select: none; transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.25s ease, opacity 0.25s ease; will-change: transform, opacity; flex-shrink: 0; pointer-events: auto; min-width: 240px; max-width: calc(100vw - 48px); width: 360px; border: 1px solid var(--met-border, rgba(0,0,0,0.06)); background: var(--met-bg, rgba(255,255,255,0.96)); color: var(--met-text, #1f2937); box-shadow: var(--met-shadow, 0 10px 36px -10px rgba(0,0,0,0.18), 0 4px 14px -4px rgba(0,0,0,0.08)); } /* 悬停效果 */ .met-toast:hover { box-shadow: var(--met-hover-shadow, 0 14px 48px -10px rgba(0,0,0,0.22), 0 6px 18px -4px rgba(0,0,0,0.10)) !important; } /* 可点击状态 */ .met-toast.met-clickable { cursor: pointer; } /* 图标样式 */ .met-icon { flex-shrink: 0; display: flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-top: 1px; } /* 内容样式 */ .met-content { flex: 1; min-width: 0; word-wrap: break-word; overflow-wrap: break-word; } /* 标题样式 */ .met-title { font-weight: 600; font-size: 14px; letter-spacing: 0.1px; } /* 消息样式 */ .met-message { font-size: 13px; opacity: 0.85; margin-top: 2px; } /* 关闭按钮样式 */ .met-close { flex-shrink: 0; background: transparent; border: 0; padding: 4px; cursor: pointer; display: flex; align-items: center; justify-content: center; border-radius: 6px; transition: background 0.2s, color 0.2s; line-height: 0; color: inherit; opacity: 0.5; } .met-close:hover { opacity: 1; background: var(--met-close-hover-bg, rgba(0,0,0,0.06)); } /* 进度条样式 - 水平 */ .met-progress { position: absolute; left: 0; right: 0; bottom: 0; height: 3px; overflow: hidden; background: var(--met-progress-bg, rgba(0,0,0,0.06)); border-radius: 0 0 12px 12px; } /* 进度条样式 - 垂直 */ .met-progress-v { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; overflow: hidden; background: var(--met-progress-bg, rgba(0,0,0,0.06)); border-radius: 12px 0 0 12px; } /* 进度条指示器 - 水平 */ .met-bar { position: absolute; left: 0; top: 0; height: 100%; width: 100%; transform-origin: left; transform: scaleX(1); } /* 进度条指示器 - 垂直 */ .met-bar-v { position: absolute; left: 0; bottom: 0; width: 100%; height: 100%; transform-origin: bottom; transform: scaleY(1); } /* 侧边指示器 */ .met-side { position: absolute; left: 0; top: 0; bottom: 0; width: 4px; border-radius: 12px 0 0 12px; } /* 加载动画 */ .met-spin { animation: met-rot 1s linear infinite; transform-origin: 50% 50%; } /* 离开状态 */ .met-toast.met-leaving { pointer-events: none; z-index: 1; } /* 动画关键帧 */ @keyframes met-rot { to { transform: rotate(360deg); } } /* === 进入动画:初始隐藏态 === */ .met-anim-slide.met-toast, .met-anim-fade.met-toast, .met-anim-scale.met-toast, .met-anim-bounce.met-toast, .met-anim-flip.met-toast, .met-anim-rotate.met-toast, .met-anim-zoom.met-toast, .met-anim-slideUp.met-toast, .met-anim-slideDown.met-toast, .met-anim-slideLeft.met-toast, .met-anim-slideRight.met-toast { opacity: 0; } /* === 进入动画:@keyframes 定义 === */ @keyframes met-slide-in { 0% { transform: translateX(80px); opacity: 0; } 65% { transform: translateX(-6px); opacity: 1; } 100% { transform: translateX(0); opacity: 1; } } @keyframes met-fade-in { 0% { opacity: 0; filter: blur(3px); } 100% { opacity: 1; filter: blur(0); } } @keyframes met-scale-in { 0% { transform: scale(0.55); opacity: 0; } 65% { transform: scale(1.07); opacity: 1; } 100% { transform: scale(1); opacity: 1; } } @keyframes met-bounce-in { 0% { transform: translateY(-80px); opacity: 0; animation-timing-function: ease-in; } 45% { transform: translateY(14px); opacity: 1; animation-timing-function: ease-out; } 65% { transform: translateY(-12px); animation-timing-function: ease-in; } 82% { transform: translateY(4px); animation-timing-function: ease-out; } 100% { transform: translateY(0); opacity: 1; } } @keyframes met-flip-in { 0% { transform: perspective(500px) rotateX(-90deg); opacity: 0; } 60% { transform: perspective(500px) rotateX(8deg); opacity: 1; } 85% { transform: perspective(500px) rotateX(-2deg); } 100% { transform: perspective(500px) rotateX(0); opacity: 1; } } @keyframes met-rotate-in { 0% { transform: rotate(-25deg) scale(0.6); opacity: 0; } 60% { transform: rotate(4deg) scale(1.05); opacity: 1; } 85% { transform: rotate(-1deg) scale(0.98); } 100% { transform: rotate(0) scale(1); opacity: 1; } } @keyframes met-zoom-in { 0% { transform: scale(0.1); opacity: 0; } 50% { transform: scale(1.12); opacity: 1; } 75% { transform: scale(0.94); } 100% { transform: scale(1); opacity: 1; } } @keyframes met-slideUp-in { 0% { transform: translateY(60px); opacity: 0; } 70% { transform: translateY(-6px); opacity: 1; } 100% { transform: translateY(0); opacity: 1; } } @keyframes met-slideDown-in { 0% { transform: translateY(-60px); opacity: 0; } 70% { transform: translateY(6px); opacity: 1; } 100% { transform: translateY(0); opacity: 1; } } @keyframes met-slideLeft-in { 0% { transform: translateX(-90px); opacity: 0; } 65% { transform: translateX(6px); opacity: 1; } 100% { transform: translateX(0); opacity: 1; } } @keyframes met-slideRight-in { 0% { transform: translateX(90px); opacity: 0; } 65% { transform: translateX(-6px); opacity: 1; } 100% { transform: translateX(0); opacity: 1; } } /* === 进入动画:绑定到 .met-show === */ .met-anim-slide.met-toast.met-show { animation: met-slide-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-fade.met-toast.met-show { animation: met-fade-in 0.50s ease forwards; } .met-anim-scale.met-toast.met-show { animation: met-scale-in 0.45s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; } .met-anim-bounce.met-toast.met-show { animation: met-bounce-in 0.65s ease forwards; } .met-anim-flip.met-toast.met-show { animation: met-flip-in 0.50s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-rotate.met-toast.met-show { animation: met-rotate-in 0.50s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-zoom.met-toast.met-show { animation: met-zoom-in 0.50s cubic-bezier(0.34, 1.56, 0.64, 1) forwards; } .met-anim-slideUp.met-toast.met-show { animation: met-slideUp-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-slideDown.met-toast.met-show { animation: met-slideDown-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-slideLeft.met-toast.met-show { animation: met-slideLeft-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } .met-anim-slideRight.met-toast.met-show { animation: met-slideRight-in 0.40s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; } /* 响应式设计 */ @media (prefers-reduced-motion: reduce) { .met-toast { transition: opacity 0.15s !important; } .met-toast.met-show { animation: none !important; opacity: 1 !important; } .met-spin { animation-duration: 2.5s !important; } } @media (max-width: 480px) { .met-container { padding: 12px !important; } .met-toast { width: 100% !important; min-width: 0 !important; } } /* 暗色主题特定样式 */ .met-toast.met-theme-dark { background: rgba(28, 32, 40, 0.94); color: #e6e8eb; border-color: rgba(255, 255, 255, 0.08); box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.6), 0 4px 14px -4px rgba(0, 0, 0, 0.4); } .met-toast.met-theme-dark:hover { box-shadow: 0 14px 48px -8px rgba(0, 0, 0, 0.6), 0 6px 18px -4px rgba(0, 0, 0, 0.4) !important; } .met-toast.met-theme-dark .met-close:hover { background: rgba(255, 255, 255, 0.08); } .met-toast.met-theme-dark .met-progress, .met-toast.met-theme-dark .met-progress-v { background: rgba(255, 255, 255, 0.08); } /* 亮色主题特定样式 */ .met-toast.met-theme-light { background: rgba(255, 255, 255, 0.96); color: #1f2937; border-color: rgba(0, 0, 0, 0.06); box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.18), 0 4px 14px -4px rgba(0, 0, 0, 0.08); } .met-toast.met-theme-light:hover { box-shadow: 0 14px 48px -10px rgba(0, 0, 0, 0.22), 0 6px 18px -4px rgba(0, 0, 0, 0.10) !important; } .met-toast.met-theme-light .met-close:hover { background: rgba(0, 0, 0, 0.06); } .met-toast.met-theme-light .met-progress, .met-toast.met-theme-light .met-progress-v { background: rgba(0, 0, 0, 0.06); } /* 自定义主题支持 */ .met-toast[data-theme] { --met-bg: var(--met-theme-bg); --met-text: var(--met-theme-text); --met-border: var(--met-theme-border); --met-shadow: var(--met-theme-shadow); } /* 动画性能优化 */ .met-toast { backface-visibility: hidden; -webkit-backface-visibility: hidden; perspective: 1000; } /* 滚动条样式 */ .met-container::-webkit-scrollbar { width: 6px; height: 6px; } .met-container::-webkit-scrollbar-track { background: transparent; } .met-container::-webkit-scrollbar-thumb { background: rgba(0, 0, 0, 0.2); border-radius: 3px; } .met-container::-webkit-scrollbar-thumb:hover { background: rgba(0, 0, 0, 0.3); } /* 打印样式 */ @media print { .met-container { display: none !important; } .met-toast { display: none !important; } } /* 高对比度模式 */ @media (forced-colors: active) { .met-toast { border: 2px solid ButtonText; } .met-close { border: 1px solid ButtonText; } } /* 焦点样式 */ .met-toast:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; } .met-close:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; } /* 禁用状态 */ .met-toast:disabled, .met-toast[disabled] { opacity: 0.5; cursor: not-allowed; } /* 加载状态 */ .met-toast.met-loading { cursor: wait; } /* 成功状态 */ .met-toast.met-success { border-left: 4px solid #10b981; } /* 错误状态 */ .met-toast.met-error { border-left: 4px solid #ef4444; } /* 警告状态 */ .met-toast.met-warning { border-left: 4px solid #f59e0b; } /* 信息状态 */ .met-toast.met-info { border-left: 4px solid #3b82f6; } /* 加载状态 */ .met-toast.met-loading { border-left: 4px solid #6366f1; } /* 进度条动画 */ .met-bar, .met-bar-v { transition: transform 0.1s linear; } /* 容器动画 */ .met-container { transition: all 0.3s ease; } /* Toast进入动画 */ .met-toast.met-enter { animation: met-enter 0.3s ease forwards; } /* Toast离开动画 */ .met-toast.met-leave { animation: met-leave 0.3s ease forwards; } @keyframes met-enter { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } @keyframes met-leave { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(-20px); } } /* 响应式字体大小 */ @media (max-width: 768px) { .met-toast { font-size: 13px; } .met-title { font-size: 13px; } .met-message { font-size: 12px; } } @media (max-width: 480px) { .met-toast { font-size: 12px; padding: 12px 14px; } .met-title { font-size: 12px; } .met-message { font-size: 11px; } } /* 无障碍支持 */ .met-toast[role="alert"] { /* 警告类型Toast的特殊样式 */ } .met-toast[role="status"] { /* 状态类型Toast的特殊样式 */ } /* 高对比度模式增强 */ @media (prefers-contrast: high) { .met-toast { border-width: 2px; } .met-close { border: 1px solid currentColor; } } /* 暗色模式自动检测 */ @media (prefers-color-scheme: dark) { .met-theme-auto .met-toast { background: rgba(28, 32, 40, 0.94); color: #e6e8eb; border-color: rgba(255, 255, 255, 0.08); box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.6), 0 4px 14px -4px rgba(0, 0, 0, 0.4); } .met-theme-auto .met-toast:hover { box-shadow: 0 14px 48px -8px rgba(0, 0, 0, 0.6), 0 6px 18px -4px rgba(0, 0, 0, 0.4) !important; } .met-theme-auto .met-close:hover { background: rgba(255, 255, 255, 0.08); } .met-theme-auto .met-progress, .met-theme-auto .met-progress-v { background: rgba(255, 255, 255, 0.08); } } /* 亮色模式自动检测 */ @media (prefers-color-scheme: light) { .met-theme-auto .met-toast { background: rgba(255, 255, 255, 0.96); color: #1f2937; border-color: rgba(0, 0, 0, 0.06); box-shadow: 0 10px 36px -10px rgba(0, 0, 0, 0.18), 0 4px 14px -4px rgba(0, 0, 0, 0.08); } .met-theme-auto .met-toast:hover { box-shadow: 0 14px 48px -10px rgba(0, 0, 0, 0.22), 0 6px 18px -4px rgba(0, 0, 0, 0.10) !important; } .met-theme-auto .met-close:hover { background: rgba(0, 0, 0, 0.06); } .met-theme-auto .met-progress, .met-theme-auto .met-progress-v { background: rgba(0, 0, 0, 0.06); } } /* 动画性能优化 */ .met-toast { transform: translateZ(0); -webkit-transform: translateZ(0); } /* 触摸设备优化 */ @media (hover: none) { .met-toast:hover { box-shadow: inherit; } } /* 滚动时固定位置 */ .met-container { position: fixed; z-index: 9999; } /* 全屏模式 */ :fullscreen .met-container { z-index: 2147483647; } /* 画中画模式 */ :picture-in-picture .met-container { z-index: 2147483647; } /* 安全区域适配 */ @supports (padding: max(0px)) { .met-container { padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left)); } } /* 暗色模式安全区域 */ @media (prefers-color-scheme: dark) { @supports (padding: max(0px)) { .met-container { padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left)); } } } /* 高分辨率屏幕优化 */ @media (-webkit-min-device-pixel-ratio: 2), (min-resolution: 192dpi) { .met-toast { border-width: 0.5px; } } /* 触摸设备优化 */ @media (hover: none) and (pointer: coarse) { .met-toast { min-height: 48px; } .met-close { min-width: 48px; min-height: 48px; } } /* 键盘导航优化 */ .met-toast:focus { outline: 2px solid #3b82f6; outline-offset: 2px; } .met-toast:focus:not(:focus-visible) { outline: none; } .met-toast:focus-visible { outline: 2px solid #3b82f6; outline-offset: 2px; } /* 减少动画模式 */ @media (prefers-reduced-motion: reduce) { .met-toast { transition: opacity 0.15s ease !important; animation: none !important; } .met-bar, .met-bar-v { transition: none !important; } .met-container { transition: none !important; } } /* 高对比度模式 */ @media (prefers-contrast: high) { .met-toast { border-width: 3px; border-style: solid; } .met-close { border: 2px solid currentColor; border-radius: 4px; } .met-progress, .met-progress-v { height: 4px; } .met-bar, .met-bar-v { height: 100%; } } /* 低分辨率屏幕优化 */ @media (max-resolution: 1dppx) { .met-toast { border-width: 1px; } } /* 触摸设备优化 */ @media (hover: none) and (pointer: coarse) { .met-toast { min-height: 52px; padding: 16px 18px; } .met-close { min-width: 52px; min-height: 52px; padding: 8px; } .met-icon { width: 28px; height: 28px; } } /* 大屏幕优化 */ @media (min-width: 1200px) { .met-toast { width: 400px; } } /* 超大屏幕优化 */ @media (min-width: 1920px) { .met-toast { width: 440px; } } /* 小屏幕优化 */ @media (max-width: 320px) { .met-toast { width: 100%; min-width: 0; padding: 12px 14px; } .met-container { padding: 8px; } } /* 横屏优化 */ @media (orientation: landscape) and (max-height: 500px) { .met-container { padding: 12px 24px; } .met-toast { min-height: 44px; padding: 10px 14px; } } /* 竖屏优化 */ @media (orientation: portrait) and (max-width: 500px) { .met-container { padding: 12px; } .met-toast { width: 100%; min-width: 0; } } /* 无障碍支持 */ .met-toast[aria-live="assertive"] { /* 紧急通知样式 */ } .met-toast[aria-live="polite"] { /* 普通通知样式 */ } /* 焦点陷阱 */ .met-toast:focus-within { /* 包含焦点元素的Toast样式 */ } /* 加载状态 */ .met-toast[aria-busy="true"] { cursor: wait; } /* 禁用状态 */ .met-toast[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; pointer-events: none; } /* 隐藏状态 */ .met-toast[aria-hidden="true"] { display: none; } /* 展开状态 */ .met-toast[aria-expanded="true"] { /* 展开状态样式 */ } /* 选中状态 */ .met-toast[aria-selected="true"] { /* 选中状态样式 */ } /* 按下状态 */ .met-toast:active { transform: scale(0.98); } /* 加载状态动画 */ .met-toast.met-loading::after { content: ''; position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: linear-gradient( 90deg, transparent, rgba(255, 255, 255, 0.1), transparent ); animation: met-loading 1.5s infinite; } @keyframes met-loading { 0% { transform: translateX(-100%); } 100% { transform: translateX(100%); } } /* 成功状态动画 */ .met-toast.met-success::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #10b981; border-radius: 12px 0 0 12px; animation: met-success 0.3s ease; } @keyframes met-success { from { transform: scaleY(0); } to { transform: scaleY(1); } } /* 错误状态动画 */ .met-toast.met-error::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #ef4444; border-radius: 12px 0 0 12px; animation: met-error 0.3s ease; } @keyframes met-error { from { transform: scaleY(0); } to { transform: scaleY(1); } } /* 警告状态动画 */ .met-toast.met-warning::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #f59e0b; border-radius: 12px 0 0 12px; animation: met-warning 0.3s ease; } @keyframes met-warning { from { transform: scaleY(0); } to { transform: scaleY(1); } } /* 信息状态动画 */ .met-toast.met-info::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #3b82f6; border-radius: 12px 0 0 12px; animation: met-info 0.3s ease; } @keyframes met-info { from { transform: scaleY(0); } to { transform: scaleY(1); } } /* 加载状态动画 */ .met-toast.met-loading::before { content: ''; position: absolute; top: 0; left: 0; width: 4px; height: 100%; background: #6366f1; border-radius: 12px 0 0 12px; animation: met-loading-bar 1s infinite; } @keyframes met-loading-bar { 0% { transform: scaleY(0); transform-origin: top; } 50% { transform: scaleY(1); transform-origin: top; } 51% { transform-origin: bottom; } 100% { transform: scaleY(0); transform-origin: bottom; } } /* 进度条脉冲动画 */ .met-bar, .met-bar-v { animation: met-pulse 2s infinite; } @keyframes met-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.8; } } /* Toast堆叠效果 */ .met-toast + .met-toast { margin-top: 8px; } /* Toast分组 */ .met-toast-group { display: flex; flex-direction: column; gap: 8px; } /* Toast头部 */ .met-toast-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; } /* Toast底部 */ .met-toast-footer { display: flex; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 12px; } /* Toast操作按钮 */ .met-toast-action { background: transparent; border: 1px solid currentColor; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 12px; opacity: 0.7; transition: opacity 0.2s; } .met-toast-action:hover { opacity: 1; } /* Toast进度文本 */ .met-toast-progress-text { font-size: 12px; opacity: 0.7; margin-left: 8px; } /* Toast时间戳 */ .met-toast-timestamp { font-size: 11px; opacity: 0.5; margin-left: auto; } /* Toast头像 */ .met-toast-avatar { width: 32px; height: 32px; border-radius: 50%; object-fit: cover; flex-shrink: 0; } /* Toast图片 */ .met-toast-image { max-width: 100%; max-height: 200px; border-radius: 8px; margin-top: 8px; object-fit: cover; } /* Toast视频 */ .met-toast-video { max-width: 100%; max-height: 200px; border-radius: 8px; margin-top: 8px; } /* Toast音频 */ .met-toast-audio { width: 100%; margin-top: 8px; } /* Toast代码块 */ .met-toast-code { background: rgba(0, 0, 0, 0.05); padding: 8px 12px; border-radius: 6px; font-family: 'SFMono-Regular', Consolas, 'Liberation Mono', Menlo, monospace; font-size: 12px; margin-top: 8px; overflow-x: auto; } .met-theme-dark .met-toast-code { background: rgba(255, 255, 255, 0.05); } /* Toast引用 */ .met-toast-quote { border-left: 3px solid currentColor; padding-left: 12px; margin-top: 8px; opacity: 0.8; } /* Toast列表 */ .met-toast-list { margin: 8px 0 0 0; padding-left: 20px; } .met-toast-list li { margin-bottom: 4px; } /* Toast表格 */ .met-toast-table { width: 100%; border-collapse: collapse; margin-top: 8px; font-size: 12px; } .met-toast-table th, .met-toast-table td { border: 1px solid rgba(0, 0, 0, 0.1); padding: 6px 8px; text-align: left; } .met-theme-dark .met-toast-table th, .met-theme-dark .met-toast-table td { border-color: rgba(255, 255, 255, 0.1); } .met-toast-table th { background: rgba(0, 0, 0, 0.05); font-weight: 600; } .met-theme-dark .met-toast-table th { background: rgba(255, 255, 255, 0.05); } /* Toast分割线 */ .met-toast-divider { height: 1px; background: rgba(0, 0, 0, 0.1); margin: 12px 0; } .met-theme-dark .met-toast-divider { background: rgba(255, 255, 255, 0.1); } /* Toast标签 */ .met-toast-tag { display: inline-block; background: rgba(0, 0, 0, 0.05); padding: 2px 8px; border-radius: 4px; font-size: 11px; margin-right: 4px; margin-bottom: 4px; } .met-theme-dark .met-toast-tag { background: rgba(255, 255, 255, 0.05); } /* Toast徽章 */ .met-toast-badge { display: inline-flex; align-items: center; justify-content: center; background: #3b82f6; color: white; padding: 2px 8px; border-radius: 10px; font-size: 11px; font-weight: 600; min-width: 20px; height: 20px; } /* Toast进度环 */ .met-toast-progress-ring { width: 40px; height: 40px; transform: rotate(-90deg); } .met-toast-progress-ring circle { fill: none; stroke-width: 3; stroke-linecap: round; } .met-toast-progress-ring .met-progress-ring-bg { stroke: rgba(0, 0, 0, 0.1); } .met-theme-dark .met-toast-progress-ring .met-progress-ring-bg { stroke: rgba(255, 255, 255, 0.1); } .met-toast-progress-ring .met-progress-ring-fill { stroke: #3b82f6; stroke-dasharray: 100; stroke-dashoffset: 100; transition: stroke-dashoffset 0.3s ease; } /* Toast滑块 */ .met-toast-slider { width: 100%; height: 4px; background: rgba(0, 0, 0, 0.1); border-radius: 2px; margin-top: 8px; position: relative; } .met-theme-dark .met-toast-slider { background: rgba(255, 255, 255, 0.1); } .met-toast-slider-fill { position: absolute; left: 0; top: 0; height: 100%; background: #3b82f6; border-radius: 2px; transition: width 0.3s ease; } /* Toast开关 */ .met-toast-switch { position: relative; display: inline-block; width: 36px; height: 20px; margin-top: 8px; } .met-toast-switch input { opacity: 0; width: 0; height: 0; } .met-toast-switch-slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background: rgba(0, 0, 0, 0.1); border-radius: 20px; transition: 0.3s; } .met-theme-dark .met-toast-switch-slider { background: rgba(255, 255, 255, 0.1); } .met-toast-switch-slider:before { content: ''; position: absolute; height: 16px; width: 16px; left: 2px; bottom: 2px; background: white; border-radius: 50%; transition: 0.3s; } .met-toast-switch input:checked + .met-toast-switch-slider { background: #3b82f6; } .met-toast-switch input:checked + .met-toast-switch-slider:before { transform: translateX(16px); } /* Toast复选框 */ .met-toast-checkbox { display: flex; align-items: center; gap: 8px; margin-top: 8px; cursor: pointer; } .met-toast-checkbox input { width: 16px; height: 16px; cursor: pointer; } /* Toast单选框 */ .met-toast-radio { display: flex; align-items: center; gap: 8px; margin-top: 8px; cursor: pointer; } .met-toast-radio input { width: 16px; height: 16px; cursor: pointer; } /* Toast输入框 */ .met-toast-input { width: 100%; padding: 8px 12px; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 6px; font-size: 13px; margin-top: 8px; background: transparent; color: inherit; } .met-theme-dark .met-toast-input { border-color: rgba(255, 255, 255, 0.1); } .met-toast-input:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); } /* Toast文本域 */ .met-toast-textarea { width: 100%; padding: 8px 12px; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 6px; font-size: 13px; margin-top: 8px; background: transparent; color: inherit; resize: vertical; min-height: 80px; } .met-theme-dark .met-toast-textarea { border-color: rgba(255, 255, 255, 0.1); } .met-toast-textarea:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); } /* Toast选择框 */ .met-toast-select { width: 100%; padding: 8px 12px; border: 1px solid rgba(0, 0, 0, 0.1); border-radius: 6px; font-size: 13px; margin-top: 8px; background: transparent; color: inherit; cursor: pointer; } .met-theme-dark .met-toast-select { border-color: rgba(255, 255, 255, 0.1); } .met-toast-select:focus { outline: none; border-color: #3b82f6; box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); } /* Toast下拉菜单 */ .met-toast-dropdown { position: relative; display: inline-block; } .met-toast-dropdown-content { display: none; position: absolute; background: ${theme.bg}; min-width: 160px; box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); border-radius: 8px; z-index: 1; padding: 8px 0; margin-top: 4px; } .met-theme-dark .met-toast-dropdown-content { box-shadow: 0 8px 16px rgba(0, 0, 0, 0.3); } .met-toast-dropdown:hover .met-toast-dropdown-content { display: block; } .met-toast-dropdown-item { padding: 8px 16px; cursor: pointer; font-size: 13px; } .met-toast-dropdown-item:hover { background: rgba(0, 0, 0, 0.05); } .met-theme-dark .met-toast-dropdown-item:hover { background: rgba(255, 255, 255, 0.05); } /* Toast工具提示 */ .met-toast-tooltip { position: relative; display: inline-block; } .met-toast-tooltip .met-toast-tooltip-text { visibility: hidden; width: 120px; background: ${theme.bg}; color: ${theme.text}; text-align: center; border-radius: 6px; padding: 6px 8px; position: absolute; z-index: 1; bottom: 125%; left: 50%; margin-left: -60px; opacity: 0; transition: opacity 0.3s; font-size: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); } .met-theme-dark .met-toast-tooltip .met-toast-tooltip-text { box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); } .met-toast-tooltip:hover .met-toast-tooltip-text { visibility: visible; opacity: 1; } /* Toast弹出框 */ .met-toast-popover { position: relative; display: inline-block; } .met-toast-popover .met-toast-popover-content { visibility: hidden; background: ${theme.bg}; color: ${theme.text}; border-radius: 8px; padding: 12px 16px; position: absolute; z-index: 1; bottom: 125%; left: 50%; transform: translateX(-50%); opacity: 0; transition: opacity 0.3s; min-width: 200px; box-shadow: 0 8px 24px rgba(0, 0, 0, 0.15); } .met-theme-dark .met-toast-popover .met-toast-popover-content { box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4); } .met-toast-popover:hover .met-toast-popover-content { visibility: visible; opacity: 1; } /* Toast模态框 */ .met-toast-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; z-index: 10000; } .met-toast-modal-content { background: ${theme.bg}; color: ${theme.text}; border-radius: 12px; padding: 24px; max-width: 500px; width: 90%; max-height: 80vh; overflow-y: auto; } /* Toast抽屉 */ .met-toast-drawer { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.5); z-index: 10000; } .met-toast-drawer-content { position: absolute; top: 0; right: 0; width: 300px; height: 100%; background: ${theme.bg}; color: ${theme.text}; padding: 24px; transform: translateX(100%); transition: transform 0.3s ease; } .met-toast-drawer.open .met-toast-drawer-content { transform: translateX(0); } /* Toast通知栏 */ .met-toast-notification-bar { position: fixed; top: 0; left: 0; right: 0; background: ${theme.bg}; color: ${theme.text}; padding: 12px 24px; display: flex; align-items: center; justify-content: space-between; z-index: 9999; box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); } /* Toast状态栏 */ .met-toast-status-bar { position: fixed; bottom: 0; left: 0; right: 0; background: ${theme.bg}; color: ${theme.text}; padding: 8px 24px; display: flex; align-items: center; justify-content: space-between; z-index: 9999; font-size: 12px; box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.1); } `; }; /** * 注入样式 * @param {Object} theme - 主题配置 */ export const injectStyles = (theme = THEMES.light) => { // 检查是否在浏览器环境 if (typeof document === 'undefined') return; // 检查是否已注入 if (styleElement && document.getElementById('metona-toast-styles')) { return; } // 生成CSS const css = generateCSS(theme); // 创建样式元素 styleElement = document.createElement('style'); styleElement.id = 'metona-toast-styles'; styleElement.textContent = css.replace(/\s+/g, ' '); // 添加到文档头 document.head.appendChild(styleElement); // 缓存样式 injectedStyles = css; }; /** * 更新样式 * @param {Object} theme - 新主题配置 */ export const updateStyles = (theme) => { if (!styleElement) { injectStyles(theme); return; } const css = generateCSS(theme); styleElement.textContent = css.replace(/\s+/g, ' '); injectedStyles = css; }; /** * 移除样式 */ export const removeStyles = () => { if (styleElement && styleElement.parentNode) { styleElement.parentNode.removeChild(styleElement); } styleElement = null; injectedStyles = null; }; /** * 获取当前样式 * @returns {string|null} 当前CSS字符串 */ export const getStyles = () => { return injectedStyles; }; /** * 检查样式是否已注入 * @returns {boolean} 是否已注入 */ export const isStylesInjected = () => { return !!styleElement && !!document.getElementById('metona-toast-styles'); }; /** * 重置样式 */ export const resetStyles = () => { removeStyles(); injectStyles(); }; /** * 添加自定义CSS * @param {string} css - CSS字符串 */ export const addCustomCSS = (css) => { if (!styleElement) { injectStyles(); } const customStyle = document.createElement('style'); customStyle.id = 'metona-toast-custom-styles'; customStyle.textContent = css; document.head.appendChild(customStyle); }; /** * 移除自定义CSS */ export const removeCustomCSS = () => { const customStyle = document.getElementById('metona-toast-custom-styles'); if (customStyle && customStyle.parentNode) { customStyle.parentNode.removeChild(customStyle); } }; /** * 生成主题变量 * @param {Object} theme - 主题配置 * @returns {string} CSS变量字符串 */ export const generateThemeVariables = (theme) => { return ` :root { --met-theme-bg: ${theme.bg}; --met-theme-text: ${theme.text}; --met-theme-border: ${theme.border}; --met-theme-shadow: ${theme.shadow}; --met-theme-hover-shadow: ${theme.hoverShadow}; --met-theme-progress-bg: ${theme.progressBg}; --met-theme-close-hover-bg: ${theme.closeHoverBg}; } `; }; /** * 应用主题变量 * @param {Object} theme - 主题配置 */ export const applyThemeVariables = (theme) => { const css = generateThemeVariables(theme); addCustomCSS(css); }; /** * 清除主题变量 */ export const clearThemeVariables = () => { removeCustomCSS(); }; /** * 获取系统主题 * @returns {string} 系统主题 */ export const getSystemTheme = () => { if (typeof window === 'undefined') return 'light'; return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; }; /** * 监听系统主题变化 * @param {Function} callback - 回调函数 * @returns {Function} 取消监听函数 */ export const watchSystemTheme = (callback) => { if (typeof window === 'undefined' || !window.matchMedia) { return () => {}; } const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); const handler = (e) => { callback(e.matches ? 'dark' : 'light'); }; mediaQuery.addEventListener('change', handler); return () => { mediaQuery.removeEventListener('change', handler); }; }; /** * 自动应用系统主题 * @returns {Function} 取消监听函数 */ export const autoApplySystemTheme = () => { const applyTheme = (theme) => { updateStyles(THEMES[theme]); applyThemeVariables(THEMES[theme]); }; // 应用当前系统主题 applyTheme(getSystemTheme()); // 监听系统主题变化 return watchSystemTheme(applyTheme); };