Skip to content

feat: IndexBar 序列#1466

Open
lqr131115 wants to merge 2 commits intoant-design:masterfrom
lqr131115:feat/index-bar
Open

feat: IndexBar 序列#1466
lqr131115 wants to merge 2 commits intoant-design:masterfrom
lqr131115:feat/index-bar

Conversation

@lqr131115
Copy link
Contributor

@lqr131115 lqr131115 commented Feb 3, 2026

First of all, thank you for your contribution! :-)

Please makes sure that these checkboxes are checked before submitting your PR, thank you!

  • Make sure that you follow antd's code convention.
  • Run npm run lint and fix those errors before submitting in order to keep consistent code style.
  • Rebase before creating a PR to keep commit history clear.
  • Add some descriptions and refer relative issues for you PR.

Extra checklist:

if isBugFix :

  • Make sure that you add at least one unit test for the bug which you had fixed.

elif isNewFeature :

  • Update API docs for the component.
  • Update/Add demo to demonstrate new feature.
  • Update TypeScript definition for the component.
  • Add unit tests for the feature.

Summary by CodeRabbit

  • 新功能
    • 新增 IndexBar 组件,支持按字母快速导航、滚动到分区及可选指示器覆盖层与交互手势。
  • 样式
    • 提供完整可定制的样式接口与主题友好样式实现。
  • 文档
    • 增补中英文使用文档与示例说明。
  • 示例
    • 增加演示示例(含基本用法)并加入演示列表入口。
  • 测试
    • 添加示例测试以覆盖组件演示场景。

@coderabbitai
Copy link

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

引入完整的 IndexBar 组件:包含 SectionList 集成、手势驱动的 Indicator(触摸映射到索引并触发回调)、主题化样式、文档、演示与测试文件,并将组件与类型导出到公共 API。

Changes

Cohort / File(s) Summary
核心组件实现
components/index-bar/index.tsx, components/index-bar/Indicator.tsx, components/index-bar/PropsType.tsx
新增 IndexBar 主组件与 Indicator 子组件;Indicator 使用手势(PanResponder)将垂直触摸位置映射到索引并通过回调上报;PropsType 新增并导出 IndexBarSectionDataIndicatorPropsIndexBarProps
样式定义
components/index-bar/style/index.tsx
新增 IndexBarStyle 接口并导出样式工厂,基于主题令牌创建所有组件子部件的样式。
文档与演示
components/index-bar/index.en-US.md, components/index-bar/index.zh-CN.md, components/index-bar/demo/basic.tsx, components/index-bar/demo/basic.md, components/index-bar/__tests__/demo.test.js
新增中英文文档、TSX 与 Markdown 演示(A–Z 分段示例)以及对应的 demo 测试文件。
导出与集成
components/index.tsx, components/types.ts, rn-kitchen-sink/demoList.js
将 IndexBar 及其类型添加到组件入口导出,并在 demo 列表中新增 IndexBar 项目。

Sequence Diagram

sequenceDiagram
    participant User as User
    participant Indicator as Indicator (组件)
    participant Pan as PanResponder
    participant IndexBar as IndexBar (组件)
    participant SectionList as SectionList

    User->>Indicator: 触摸/拖动(locationY)
    Indicator->>Pan: 转交手势事件
    Pan->>Indicator: 返回 locationY
    Indicator->>Indicator: 计算并更新 activeIndex/isInteracting
    Indicator->>IndexBar: 调用 onChange(selectedKey)
    IndexBar->>IndexBar: 计算目标 section 索引
    IndexBar->>SectionList: scrollToLocation(目标 section)
    SectionList->>SectionList: 渲染并定位到该 section
    Indicator->>Indicator: 高亮选中项并显示缩放文本
    User->>Indicator: 松手
    Indicator->>Indicator: 延迟取消 isInteracting
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 新索引竖栏上线,轻触指尖寻字母,
手划映成一行光,列表瞬间跳到家,
兔子鼓掌说好用,嗷呜欢呼又跳跃! 🥕✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰明确地总结了主要变更——添加了IndexBar(序列)组件,与pull request中的所有文件变更直接相关。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @lqr131115, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

此拉取请求引入了一个全新的 IndexBar 组件,旨在为长列表提供高效的索引导航功能。它通过一个可交互的侧边索引指示器,允许用户快速定位到列表中的特定分组,极大地提升了用户在处理大量数据时的体验。该组件基于 React Native 的 SectionList 实现,并提供了丰富的自定义选项。

Highlights

  • 新增 IndexBar 组件: 引入了一个全新的 IndexBar 组件,用于实现长列表的快速索引定位功能。
  • 交互式索引指示器: 包含一个 Indicator 子组件,支持通过点击或滑动右侧的索引条来快速跳转到列表的相应部分,并提供交互反馈。
  • 完善的类型定义和文档: 为 IndexBar 及其相关属性提供了详细的 TypeScript 类型定义,并新增了中英文 API 文档和使用示例,方便开发者理解和使用。
  • 集成到组件库: 将 IndexBar 组件集成到主组件导出文件和演示应用中,确保其可被发现、使用和测试。

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • components/index-bar/Indicator.tsx
    • 新增了索引指示器组件,处理触摸事件并更新活动索引。
  • components/index-bar/PropsType.tsx
    • 新增了 IndexBarIndicator 组件的 TypeScript 类型定义和 IndexBarSectionData 接口。
  • components/index-bar/tests/snapshots/demo.test.js.snap
    • 新增了 IndexBar 演示组件的 Jest 快照测试。
  • components/index-bar/tests/demo.test.js
    • 新增了 IndexBar 演示组件的测试文件。
  • components/index-bar/demo/basic.md
    • 新增了 IndexBar 基本用法的 Markdown 文档。
  • components/index-bar/demo/basic.tsx
    • 新增了 IndexBar 组件的基本用法演示。
  • components/index-bar/index.en-US.md
    • 新增了 IndexBar 组件的英文 API 文档。
  • components/index-bar/index.tsx
    • 新增了 IndexBar 主组件,集成了 SectionListIndicator
  • components/index-bar/index.zh-CN.md
    • 新增了 IndexBar 组件的中文 API 文档。
  • components/index-bar/style/index.tsx
    • 新增了 IndexBar 组件的默认样式定义。
  • components/index.tsx
    • 导出了新增的 IndexBar 组件。
  • components/types.ts
    • 导出了 IndexBar 相关的 TypeScript 类型。
  • rn-kitchen-sink/demoList.js
    • 在演示列表中添加了 IndexBar 组件。
  • tests/snapshots/index.test.js.snap
    • 更新了组件导出快照,包含了 IndexBar
Activity
  • 作者 lqr131115 创建了此拉取请求,旨在添加 IndexBar 组件。
  • PR 描述中包含了 Ant Design 代码规范、Lint 检查、Rebase 和文档更新等新功能开发所需的标准检查项,且均已勾选。
  • 新增了多个文件,包括组件实现、类型定义、样式、测试和多语言文档,表明该功能已全面开发并集成。
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@lqr131115
Copy link
Contributor Author

lqr131115 commented Feb 3, 2026

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new IndexBar component, which is a great addition for navigating long lists. The implementation is well-structured, with separate components for the main list and the indicator. I've found a few issues to address:

  • A critical bug that causes scrolling to the wrong section when the provided sections are not sorted.
  • An incorrect type definition that leads to a conflict.
  • Some opportunities for improving type safety and preventing potential memory leaks in the Indicator component.

After these changes are addressed, this will be a solid new feature. Good work!

export interface IndexBarSectionData {
key: string
title: string
data: string[]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The IndexBarSectionData interface includes a data: string[] property. This conflicts with the data property from React Native's SectionListData type. A section object ends up with two data properties of incompatible types, which is a type error and can cause confusion. The data property should be removed from IndexBarSectionData as it's already defined in SectionListData.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@components/index-bar/demo/basic.tsx`:
- Around line 6-18: The demo's `sections` generation uses Math.random (in the
const sections block in components/index-bar/demo/basic.tsx), which makes
snapshot tests flaky; replace the non-deterministic randomization with a
deterministic approach (e.g., a fixed dataset, a simple pseudo-random generator
with a hard-coded seed, or an array of predetermined counts) so that `data` and
`randomCount` are stable across renders and rnDemoTest snapshots; ensure the
change targets the `sections` creation logic so titles/keys remain the same
shape but deterministic.

In `@components/index-bar/index.en-US.md`:
- Line 36: 文档中 `data` 字段的类型标注不正确:将文档里第 36 行的 `data` 类型从 `any[]` 更新为 `string[]`
so it matches the implementation of `IndexBarSectionData.data` in
`PropsType.tsx`; ensure the doc entry for the `data` field (labelled "Section
data list") uses `string[]` and restore parity with the
`IndexBarSectionData.data` type.

In `@components/index-bar/index.tsx`:
- Around line 35-42: memoAvailableIndexes currently sorts section keys but
_onIndexChange uses the clicked index as if it were the original sections order,
causing wrong target indices; fix by preserving mapping to the original section
index (e.g., have memoAvailableIndexes produce items with { key, originalIndex }
or keep the sorted keys but in _onIndexChange resolve the clicked key to the
original section index via sections.findIndex(s => s.key === clickedKey)) and
then use that originalIndex when calling the scroll/section change logic; update
references to memoAvailableIndexes and _onIndexChange accordingly so clicks
always map to the correct sections entry.

In `@components/index-bar/PropsType.tsx`:
- Around line 4-9: The interface IndexBarSectionData currently types the data
field as string[] but the documentation (index.zh-CN.md) says any[]; update
IndexBarSectionData to use a more general type (e.g., data: any[] or make the
interface generic like IndexBarSectionData<T> { data: T[] }) so the type matches
docs and supports flexible item types; ensure related usages of
IndexBarSectionData (and any function/type declarations referencing it) are
updated to the chosen generic or any[] form.

In `@components/index-bar/style/index.tsx`:
- Around line 77-90: The styles activeIndicatorTextContainer and
indicatorScaleTextContainer currently use borderRadius: '50%' which is ignored
on native; change them to use numeric widths/heights and set borderRadius to
half the size (e.g. set width and height and borderRadius = width/2) so the
containers render as circles on iOS/Android; remove the // `@ts-ignore` comments
and ensure indicatorScaleTextContainer’s padding/transform and right offset
still produce the intended layout after you pick the explicit size.
- Around line 59-64: The inline style uses transform: [{ translateY: '-50%' }]
with a `@ts-ignore` which is unsupported on native RN 0.67; remove the `@ts-ignore`
and replace the percentage translate with a numeric approach (either compute the
pixel offset via onLayout and set translateY to a number, or use absolute
positioning with top and height-based calculation) in the same style object
where transform is defined (the style containing top: '50%', justifyContent,
alignItems); leave borderRadius: '50%' as-is since string percentages are
allowed.
🧹 Nitpick comments (6)
components/index-bar/index.zh-CN.md (1)

20-27: 表格格式不一致

表头行(第20-21行)没有首尾管道符,但数据行(第22-27行)有首尾管道符。建议统一格式。

📝 建议的修复
-属性 | 说明 | 类型 | 默认值
-----|-----|------|------
-| sections | 分组数据,必需 | `SectionListData<any, IndexBarSectionData>[]` | - |
-| onIndexChange | 索引变化时的回调函数 | `(key: string, index: number) => void` | - |
-| animated | 滚动时是否使用动画 | `boolean` | `false` |
-| showIndicator | 是否显示索引指示器 | `boolean` | `true` |
-| style | 自定义容器样式 | `StyleProp<ViewStyle>` | - |
-| styles | 语义化结构 style | [IndexBarStyle](`#indexbarstyle-语义化样式`) | - |
+| 属性 | 说明 | 类型 | 默认值 |
+| ---- | ---- | ---- | ------ |
+| sections | 分组数据,必需 | `SectionListData<any, IndexBarSectionData>[]` | - |
+| onIndexChange | 索引变化时的回调函数 | `(key: string, index: number) => void` | - |
+| animated | 滚动时是否使用动画 | `boolean` | `false` |
+| showIndicator | 是否显示索引指示器 | `boolean` | `true` |
+| style | 自定义容器样式 | `StyleProp<ViewStyle>` | - |
+| styles | 语义化结构 style | [IndexBarStyle](`#indexbarstyle-语义化样式`) | - |
components/index-bar/Indicator.tsx (2)

7-7: 使用具体类型替代 any

activeIndex 的类型应该是 number 而不是 any,以获得更好的类型安全性。

♻️ 建议的修复
-  const [activeIndex, setActiveIndex] = useState<any>(0)
+  const [activeIndex, setActiveIndex] = useState<number>(0)

46-55: 建议将魔法数字提取为常量

200 毫秒的延迟时间在 onPanResponderReleaseonPanResponderTerminate 中重复使用,建议提取为命名常量以提高可读性和可维护性。

♻️ 建议的修复
+const INTERACTION_END_DELAY = 200
+
 const Indicator: React.FC<IndicatorProps> = ({ indexes, styles, onChange }) => {
   // ...
       onPanResponderRelease: () => {
         setTimeout(() => {
           setInteracting(false)
-        }, 200)
+        }, INTERACTION_END_DELAY)
       },
       onPanResponderTerminate: () => {
         setTimeout(() => {
           setInteracting(false)
-        }, 200)
+        }, INTERACTION_END_DELAY)
       },
components/index-bar/demo/basic.md (2)

17-26: 变量名遮蔽问题

第 20 行的 index 参数遮蔽了第 17 行外层的 index 变量。建议使用不同的变量名以提高可读性:

♻️ 建议修改
-    const sections = Array.from({length: 26}, (_, index) => {
+    const sections = Array.from({length: 26}, (_, i) => {
-      const key = String.fromCharCode(65 + index);
+      const key = String.fromCharCode(65 + i);
       const randomCount = Math.floor(Math.random() * 3) + 3;
-      const data = Array.from({length: randomCount}, (_, index) => `Content ${key}${index}`);
+      const data = Array.from({length: randomCount}, (_, j) => `Content ${key}${j}`);

27-28: 分号位置异常

return 语句后的分号被放在了单独一行,这是不常见的格式。建议将其移到同一行:

♻️ 建议修改
-    return <IndexBar sections={sections}/>
-    ;
+    return <IndexBar sections={sections} />;
components/index-bar/index.tsx (1)

102-110: keyExtractor 对非字符串 item 的处理

item 不是字符串类型时(例如对象),item + index 会产生 "[object Object]0" 这样的键值,可能导致重复键或难以调试的问题。

建议增加类型安全处理:

♻️ 建议修改
  const memoKeyExtractor = useCallback(
    (item: string, index: number) => {
      if (typeof keyExtractor === 'function') {
        return keyExtractor(item, index)
      }
-     return item + index
+     return typeof item === 'string' ? `${item}-${index}` : `item-${index}`
    },
    [keyExtractor],
  )

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@components/index-bar/index.zh-CN.md`:
- Line 38: The docs list the prop "data" as `any[]` but the code's PropsType.tsx
defines IndexBarSectionData.data as `string[]`; update the Chinese index-bar
docs (components/index-bar/index.zh-CN.md) to reflect `string[]` for the data
column, and make the same change in the English counterpart so documentation
matches the implementation (search for IndexBarSectionData and the "data" row in
the table to locate the entry).
🧹 Nitpick comments (1)
components/index-bar/Indicator.tsx (1)

6-7: timeRef 类型定义可以更精确

setTimeout 在 React Native 环境中返回的是 ReturnType<typeof setTimeout> 类型。使用 number 类型虽然在运行时工作正常,但类型不够精确。

♻️ 建议的优化
- const timeRef = useRef<number>(0)
+ const timeRef = useRef<ReturnType<typeof setTimeout> | null>(null)

同时更新 clearTimeout 调用:

  const _onPanResponderFinish = useCallback(() => {
    if (timeRef.current) {
      clearTimeout(timeRef.current)
    }
-   timeRef.current = setTimeout(() => {
+   timeRef.current = setTimeout(() => {
      setInteracting(false)
    }, 200)
  }, [])

@1uokun
Copy link
Collaborator

1uokun commented Feb 5, 2026

建议使用 FlatList + react-native-gesture-handler 方案替换 SectionList + PanResponder

@lqr131115 老弟要上生产线的代码就会要求高一些 加油🫶

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants