# 容器与覆层组件

## `<view>`

基础布局容器，最常用。

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| className | string | - | 样式类名 |
| style | CSSProperties | - | 内联样式 |
| flatten | boolean | true | 扁平化节点，避免创建真实渲染对象，提升性能 |
| onClick | (e: TouchEvent) => void | - | 点击 |
| onLongPress | (e: TouchEvent) => void | - | 长按 |
| onTouchStart / onTouchEnd / onTouchMove | (e: TouchEvent) => void | - | 触摸事件 |
| onAppear | (e: UIAppearanceEvent) => void | - | 进入可视区域 |
| onDisappear | (e: UIAppearanceEvent) => void | - | 离开可视区域 |

---

## `<popup>`

支持拖拽、多位置停靠的弹窗。

```tsx
import type { PopupRef } from '@doubao-dev/framework/components';
import { useRef } from '@doubao-dev/framework';

const popupRef = useRef<PopupRef>(null);

// 打开弹窗
popupRef.current?.open();   // 默认中心
popupRef.current?.open(1);  // 顶部
popupRef.current?.open(-1); // 底部
popupRef.current?.close();

<popup
  ref={popupRef}
  scrollContainerId="popup-scroll"
  maxHeight={lynx.__globalProps.screenHeight}
  closeOnMaskClick
  enableDrag
  onPopupPositionChange={(pos) => {
    // 0=中心, 1=顶部, -1=底部, 4=关闭
  }}
>
  {({ 'main-thread:gesture': gesture }) => (
    <view id="popup-scroll" style={{ height: '100%' }}>
      <text>弹窗内容</text>
    </view>
  )}
</popup>
```

### PopupRef 方法

| 方法 | 参数 | 说明 |
|------|------|------|
| open | position?: 0 \| 1 \| -1 | 打开弹窗。0 中心 / 1 顶部 / -1 底部，默认中心 |
| close | - | 关闭弹窗 |
| translateTo | position: number \| string | 移动到指定位置，支持数字或 "px" / "%" / "rpx" |

### PopupProps

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| scrollContainerId | string | - | **必填**，内部滚动容器 ID |
| children | (prop: RenderFunction) => ReactElement | - | 渲染函数 |
| autoHeight | boolean | false | 根据内容高度自动调整 |
| contentId | string | - | autoHeight 为 true 时需要设置 |
| enableDrag | boolean | true | 启用拖拽 |
| enableBounces | boolean | true | 松手回弹 |
| closeOnMaskClick | boolean | true | 点击遮罩关闭 |
| maxHeight | number | screenHeight | 最大高度 |
| heightPercent | HeightPercent | - | `{ init, top, bottom, boundaryArea, flingThreshold }` |
| bottomNode | ReactElement | - | 固定在弹窗底部的节点，不受拖动影响 |
| enterDuration / exitDuration | number | 300 | 进入/退出动画时长 (ms) |
| onPopupPositionChange | (position: number) => void | - | 位置变化回调 |
| onPopupTopChange | (height: number) => void | - | 高度变化回调 |

---

## `<movable-area>` / `<movable-view>`

```tsx
<movable-area style={{ width: '100%', height: '300px' }}>
  <movable-view direction="all" scale outOfBounds inertia friction={2} damping={20}>
    <text>拖我 / 双指缩放</text>
  </movable-view>
</movable-area>
```

### movable-view 属性

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| direction | `'all' \| 'vertical' \| 'horizontal' \| 'none'` | `'all'` | 移动方向 |
| disabled | boolean | false | 禁用 |
| x / y | number | 0 | 初始偏移 |
| scale | boolean | false | 双指缩放 |
| scaleValue | number | 1 | 初始缩放值 |
| scaleMin / scaleMax | number | 0.5 / 10 | 缩放范围 |
| outOfBounds | boolean | false | 允许超出区域（松手回弹） |
| animation | boolean | true | 回弹动画 |
| damping | number | 20 | 阻尼系数，值越大回弹越快 |
| inertia | boolean | false | 惯性滑动 |
| friction | number | 2 | 摩擦系数，值越大越快停止（必须 > 0） |
| onDrag | (x: number, y: number) => void | - | 拖拽回调 |
| onScale | (scale: number) => void | - | 缩放回调 |

---

## `<theme-provider>`

让子树消费 `--bg-*` / `--neutral-*` / `--primary-*` 等 CSS 变量时跟随宿主主题（light/dark）。

内置组件会自动应用主题，只在业务自定义内容需要主题变量时才需要包裹。

```tsx
<theme-provider>
  <view style={{ background: 'var(--bg-1)' }}>
    <text style={{ color: 'var(--neutral-text-1)' }}>跟随主题的文字</text>
  </view>
</theme-provider>
```

| 属性 | 类型 | 默认值 | 说明 |
|------|------|--------|------|
| children | ReactNode | - | 子元素 |
| className | string | - | 样式类名 |
| style | CSSProperties | - | 内联样式 |
| flatten | boolean | false | 默认 false，因为该容器需作为 CSS 变量作用域 |
