# Modal 组件迁移指南

## 🎯 问题背景

项目中多个组件使用了 `fixed inset-0` 的遮罩实现，这在某些情况下会遇到问题：

1. **父级容器有 transform 属性**时，会创建新的层叠上下文，导致 fixed 定位相对于该容器而不是视口
2. **iOS Safari 的地址栏变化**会影响视口高度
3. **复杂布局容器**可能会限制 fixed 元素的定位
4. **滚动条处理不一致**，用户体验不统一

## 🔧 解决方案

使用统一的 `Modal` 组件，它包含以下优化：

- ✅ **智能 fixed 定位检测**：自动检测并修复定位问题
- ✅ **完善的滚动条处理**：保存/恢复滚动位置，防止背景滚动
- ✅ **iOS Safari 优化**：防止橡皮筋效果
- ✅ **统一的样式系统**：一致的动画、阴影、圆角
- ✅ **可访问性支持**：ESC 键、焦点管理、屏幕阅读器

## 📋 需要迁移的组件

### 1. CreateDynamicModal ✅ 已完成
- **原实现**: `fixed inset-0 bg-black/50`
- **新实现**: 使用 Modal 组件
- **状态**: 已迁移完成

### 2. ProjectTemplateBindingForm
- **位置**: `apps/desktop/src/components/ProjectTemplateBindingForm.tsx:146`
- **原实现**: `fixed inset-0 bg-black bg-opacity-50`
- **状态**: 待迁移

### 3. ResetUsageDialog
- **位置**: `apps/desktop/src/components/ResetUsageDialog.tsx:94`
- **原实现**: `fixed inset-0 bg-black bg-opacity-50`
- **状态**: 待迁移

### 4. MaterialImportDialog
- **位置**: `apps/desktop/src/components/MaterialImportDialog.tsx:245`
- **原实现**: `fixed inset-0 bg-black bg-opacity-50`
- **状态**: 待迁移

### 5. MaterialEditDialog
- **位置**: `apps/desktop/src/components/MaterialEditDialog.tsx:101`
- **原实现**: `fixed inset-0 bg-black bg-opacity-60`
- **状态**: 待迁移

### 6. MaterialSegmentDetailModal
- **位置**: `apps/desktop/src/components/MaterialSegmentDetailModal.tsx:84`
- **原实现**: `fixed inset-0 bg-black bg-opacity-50`
- **状态**: 待迁移

### 7. DeleteConfirmDialog
- **位置**: `apps/desktop/src/components/DeleteConfirmDialog.tsx:38-42`
- **原实现**: 复杂的 fixed 实现
- **状态**: 待迁移

## 🚀 迁移步骤

### 步骤 1: 导入 Modal 组件
```tsx
import { Modal } from './Modal';
```

### 步骤 2: 替换遮罩层结构
**原代码**:
```tsx
<div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
  <div className="bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4">
    {/* 内容 */}
  </div>
</div>
```

**新代码**:
```tsx
<Modal
  isOpen={true}
  onClose={onClose}
  title="标题"
  size="lg"
  variant="default"
>
  {/* 内容 */}
</Modal>
```

### 步骤 3: 配置 Modal 属性
- `size`: 'sm' | 'md' | 'lg' | 'xl' | 'full'
- `variant`: 'default' | 'danger' | 'success' | 'warning' | 'info'
- `closeOnBackdropClick`: 是否点击遮罩关闭
- `closeOnEscape`: 是否 ESC 键关闭

### 步骤 4: 移除原有的头部和关闭按钮
Modal 组件会自动处理头部和关闭按钮。

### 步骤 5: 测试验证
- 在不同父级容器中测试
- 验证滚动条处理
- 检查键盘导航
- 测试移动端表现

## 📝 迁移模板

```tsx
// 迁移前
const OldModal = ({ onClose, children }) => (
  <div className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50">
    <div className="bg-white rounded-lg shadow-xl max-w-2xl w-full mx-4">
      <div className="flex items-center justify-between p-6 border-b">
        <h2>标题</h2>
        <button onClick={onClose}>×</button>
      </div>
      <div className="p-6">
        {children}
      </div>
    </div>
  </div>
);

// 迁移后
const NewModal = ({ onClose, children }) => (
  <Modal
    isOpen={true}
    onClose={onClose}
    title="标题"
    size="lg"
  >
    <div className="p-6">
      {children}
    </div>
  </Modal>
);
```

## ✅ 迁移检查清单

- [ ] 导入 Modal 组件
- [ ] 替换遮罩层结构
- [ ] 配置 Modal 属性
- [ ] 移除原有头部实现
- [ ] 更新样式类名
- [ ] 测试功能完整性
- [ ] 验证响应式表现
- [ ] 检查可访问性
- [ ] 更新相关文档
