# Tour

新手引导组件，用于分步骤高亮页面元素并展示引导说明。

## 适用场景

- 新功能上线后的用户功能引导
- 页面重要区域的分步骤介绍
- 需要高亮特定元素并附带说明卡片的场景

## Props

### Tour Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `""` | 否 | 自定义 class |
| visible | `boolean` | `-` | 否 | 控制是否显示 |
| steps | `TourStepItem[]` | `-` | 否 | 步骤列表 |
| activeIndex | `number` | `-` | 否 | 当前步骤 index 控制值，需配合 `onChange` 使用 |
| onChange | `(activeIndex: number) => void` | `-` | 否 | 当前步骤发生变化时的回调 |
| onClose | `(activeIndex: number) => void` | `-` | 否 | 关闭时的回调，参数为关闭时所在的步骤 index |

### TourStepItem Props

| 名称 | 类型 | 默认值 | 必填 | 说明 |
|------|------|--------|------|------|
| className | `string` | `-` | 否 | 自定义 class |
| cover | `ReactNode` | `-` | 否 | 封面内容 |
| headline | `ReactNode` | `-` | 否 | 步骤标题 |
| content | `ReactNode` | `-` | 否 | 步骤内容 |
| actions | `ReactNode` | `-` | 否 | 自定义操作按钮区域，`null` 表示不显示操作按钮 |
| pagination | `ReactNode` | `-` | 否 | 自定义页码，`null` 表示不显示页码且不参与页码计算 |
| backLabel | `string` | `-` | 否 | 自定义"上一步"按钮文本 |
| forwardLabel | `string` | `-` | 否 | 自定义"下一步"按钮文本 |
| finishLabel | `string` | `-` | 否 | 自定义"完成"按钮文本 |
| target | `() => Element` | `-` | 否 | 目标元素，为 `null` 时卡片居中展示 |
| spotlights | `() => Element[]` | `-` | 否 | 额外高亮的元素列表 |
| placement | `Placement` | `-` | 否 | 卡片相对 target 元素的位置，详见 Popper placement |

## 典型用法

### 基础用法

```tsx
import { useRef, useState } from 'react'
import { Tour, Button } from '@befe/brick'

const [visible, setVisible] = useState(false)
const refStep1 = useRef<HTMLDivElement>(null)
const refStep2 = useRef<HTMLDivElement>(null)
const refStep3 = useRef<HTMLDivElement>(null)

const steps = [
    { headline: 'S-1', content: 'step_1', target: () => refStep1.current },
    { headline: 'S-2', content: 'step_2', target: () => refStep2.current },
    { headline: 'S-3', content: 'step_3', target: () => refStep3.current },
]

<Button type="important" onClick={() => setVisible(true)}>开始引导</Button>
<div ref={refStep1}><Button>Step 1</Button></div>
<div ref={refStep2}><Button>Step 2</Button></div>
<div ref={refStep3}><Button>Step 3</Button></div>
<Tour
    visible={visible}
    steps={steps}
    onClose={index => { console.log(`close at index ${index}`); setVisible(false) }}
/>
```

### 指定位置

> - 可使用 `placement` 指定卡片相对目标元素的位置
> - 当 `target` 为 `null` 时，卡片将居中展示

```tsx
const steps: TourStepItem[] = [
    { headline: 'Intro', content: '这是一个简介', target: null },  // 居中展示
    { headline: 'S-1', content: 'step_1', target: () => ref1.current, placement: 'top' },
    { headline: 'S-2', content: 'step_2', target: () => ref2.current, placement: 'bottom-start' },
    { headline: 'S-3', content: 'step_3', target: () => ref3.current, placement: 'right' },
]
```

### 自定义内容与操作

> - 通过 `actions: null` 可隐藏操作按钮；自定义 `actions` 将完全替换标准按钮，需用 `activeIndex` 控制步骤流转
> - `pagination: null` 表示该步骤不显示页码，且不参与页码计数

```tsx
const [activeIndex, setActiveIndex] = useState(0)

const steps: TourStepItem[] = [
    {
        className: 'tour-step-intro',
        headline: null,
        content: <CustomIntroContent onStart={() => setActiveIndex(1)} />,
        target: null,
        actions: null,    // 隐藏操作按钮
        pagination: null, // 隐藏页码，且不参与计算
    },
    {
        cover: <img src={coverSrc} alt="cover" />,
        headline: 'S-1',
        content: 'step_1',
        target: () => ref1.current,
    },
    {
        headline: 'S-3',
        content: 'step_3',
        finishLabel: '进入新版',
        target: () => ref3.current,
    },
]

<Tour
    visible={visible}
    steps={steps}
    activeIndex={activeIndex}
    onChange={setActiveIndex}
    onClose={close}
/>
```

## 注意事项

- `target` 为 `null` 时，引导卡片居中展示，适合作为引导的首页介绍步骤
- 自定义 `actions` 会完全替换默认的"上一步/下一步/完成"按钮，需手动通过 `activeIndex` + `onChange` 控制步骤流转
- `pagination: null` 的步骤不参与页码计算，即总步骤数不包含此步骤
- `placement` 可选值参考 Popper 组件的 placement 说明
