Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(Tabs): Separate Tabs into Tabs and VerticalTabs #2699

Open
wants to merge 9 commits into
base: V3.0
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/nutui-taro-demo/src/app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ const subPackages = [
"pages/navbar/index",
"pages/sidenavbar/index",
"pages/tabbar/index",
"pages/tabs/index"
"pages/tabs/index",
"pages/verticaltabs/index"
Comment on lines +35 to +36
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

需要添加垂直标签页面的具体实现

根据验证结果,虽然在 app.config.ts 中添加了页面配置,但是在 packages/nutui-taro-demo/src/pages/verticaltabs/ 目录下尚未找到对应的页面实现文件。

建议:

  • packages/nutui-taro-demo/src/pages/verticaltabs/ 目录下创建 index.tsx 文件
  • 参考现有的 tabs demo 页面实现垂直标签的演示页面
  • 确保新页面正确引用并展示 VerticalTabs 组件
🔗 Analysis chain

新增垂直标签页面配置正确!

页面配置的位置合理,与现有的标签页面放在同一个导航子包中,保持了良好的组织结构。

请运行以下脚本验证新页面的实现:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:验证垂直标签页面的实现文件是否存在

# 测试:检查页面实现文件是否存在
fd "index\.(tsx|jsx|ts|js)$" -p "nav/pages/verticaltabs"

# 测试:检查页面是否已在演示文档中添加
rg "verticaltabs" -t md

Length of output: 190


Script:

#!/bin/bash
# 检查正确的页面路径
fd "index\.(tsx|jsx|ts|js)$" "pages/verticaltabs"

# 检查是否有相关的文档或引用
rg -g "!*.{lock,svg}" "verticaltabs"

# 检查Tabs相关组件的实现
fd "tabs" -t f "src"

Length of output: 1081


Script:

#!/bin/bash
# 检查demo目录下的页面实现
fd "index\.(tsx|jsx|ts|js)$" "packages/nutui-taro-demo"

# 检查verticaltabs的具体实现
rg -A 5 "const VerticalTabs" src/packages/verticaltabs/

Length of output: 1112

Comment on lines +35 to +36
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

需要创建垂直选项卡示例页面

在app.config.ts中添加了路由配置,但是对应的页面文件夹和组件尚未创建。请注意:

  • 需要在 packages/nutui-taro-demo/src/pages/verticaltabs/ 创建相关页面文件
  • 确保创建 index.tsxindex.config.ts 文件
  • 参考现有的Tabs示例页面实现VerticalTabs的展示
🔗 Analysis chain

页面路由配置正确添加

新增的垂直选项卡页面路由配置符合现有规范,且放置在正确的导航组件子包中。

执行以下脚本以验证页面路由的唯一性:

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:检查是否存在重复的页面路由配置
# 预期结果:不应该有重复的页面路由

# 搜索所有可能包含页面路由配置的文件
rg "pages/verticaltabs/index" 

Length of output: 105


Script:

#!/bin/bash
# 检查垂直选项卡页面文件是否存在
fd "index\.(tsx?|jsx?)" -p packages/nutui-taro-demo/src/pages/verticaltabs/

# 检查其他配置文件中是否有相关路由
rg -g "*.config.*" "verticaltabs"

# 检查是否有相关的组件引用
rg "VerticalTabs" -A 2

Length of output: 9849


Script:

#!/bin/bash
# 检查demo页面文件是否存在
fd -p "demo" packages/nutui-taro-demo/src/pages/verticaltabs/

# 检查是否有相关的路由配置文件
fd -p "index.config" packages/nutui-taro-demo/src/pages/verticaltabs/

# 检查pages目录结构
fd -t d "pages" packages/nutui-taro-demo/src/

Length of output: 485

]
},
{
Expand Down
13 changes: 12 additions & 1 deletion src/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,23 @@
"version": "2.0.0",
"name": "Tabs",
"type": "component",
"cName": "选项卡切换",
"cName": "水平选项卡",
"desc": "常用于平级区域大块内容的的收纳和展现,支持内嵌标签形式和渲染循环数据形式",
"sort": 12,
"show": true,
"taro": true,
"author": "oasis"
},
{
"version": "2.0.0",
"name": "VerticalTabs",
"type": "component",
"cName": "垂直选项卡",
"desc": "常用于平级区域大块内容的的收纳和展现,支持内嵌标签形式和渲染循环数据形式",
"sort": 13,
"show": true,
"taro": true,
"author": "Alex.hxy"
}
]
},
Expand Down
6 changes: 3 additions & 3 deletions src/packages/tabs/__test__/tabs.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test('base Tabs', () => {

test('base tabs props', () => {
const { container } = render(
<Tabs value="0" direction="horizontal" activeType="smile">
<Tabs value="0" activeType="smile">
<TabPane title="Tab 1" value="0">
Tab 1
</TabPane>
Expand All @@ -31,7 +31,7 @@ test('base tabs props', () => {

test('base tabs props', () => {
const { container } = render(
<Tabs value="0" direction="horizontal" activeType="card">
<Tabs value="0" activeType="card">
<TabPane title="Tab 1" value="0">
Tab 1
</TabPane>
Expand Down Expand Up @@ -144,7 +144,7 @@ test('base click', () => {
test('click tab when have many tabs', async () => {
const handleClick = vi.fn(() => {})
const { container } = render(
<Tabs value="0" onClick={handleClick} direction="vertical">
<Tabs value="0" onClick={handleClick}>
<TabPane title="Tab 1" value="0">
Tab 1
</TabPane>
Expand Down
27 changes: 2 additions & 25 deletions src/packages/tabs/demo.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,6 @@ import Demo15 from './demos/taro/demo15'
import Demo16 from './demos/taro/demo16'
import Demo17 from './demos/taro/demo17'
import Demo18 from './demos/taro/demo18'
import Demo19 from './demos/taro/demo19'
import Demo20 from './demos/taro/demo20'
import Demo21 from './demos/taro/demo21'
import Demo22 from './demos/taro/demo22'
import Demo23 from './demos/taro/demo23'

const TabsDemo = () => {
const [translated] = useTranslate({
Expand All @@ -40,10 +35,6 @@ const TabsDemo = () => {
title2: '通过 value 匹配',
title3: '数据异步渲染 3s',
title4: '数量多,滚动操作',
title5: '左右布局',
title6: '左右布局-微笑曲线',
title12: '嵌套布局',
title13: '嵌套布局 2',
title14: '滑动切换',
title7: 'Title 字体尺寸:20px 12px',
title8: '自定义标签栏',
Expand All @@ -64,10 +55,6 @@ const TabsDemo = () => {
title2: 'Match By Value',
title3: 'Data Is Rendered Asynchronously For 3s',
title4: 'A Large Number Of Scrolling Operations',
title5: 'Left And Right Layout',
title6: 'Left And Right Layout - Smile Curve',
title12: 'Tabs In Tabs',
title13: 'Tabs In Tabs 2',
title14: 'Slide To Switch',
title7: 'Title FontSize: 20px 12px',
title8: 'Custom Tab Bar',
Expand Down Expand Up @@ -118,20 +105,10 @@ const TabsDemo = () => {
<Demo15 />
<View className="h2">{translated.title4}</View>
<Demo16 />
<View className="h2">{translated.title4} 2</View>
<Demo17 />
<View className="h2">{translated.title5}</View>
<Demo18 />
<View className="h2">{translated.title6}</View>
<Demo19 />
<View className="h2">{translated.title12}</View>
<Demo20 />
<View className="h2">{translated.title13}</View>
<Demo21 />
<View className="h2">{translated.title7}</View>
<Demo22 />
<Demo17 />
<View className="h2">{translated.title8}</View>
<Demo23 />
<Demo18 />
</ScrollView>
</>
)
Expand Down
27 changes: 2 additions & 25 deletions src/packages/tabs/demo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,6 @@ import Demo15 from './demos/h5/demo15'
import Demo16 from './demos/h5/demo16'
import Demo17 from './demos/h5/demo17'
import Demo18 from './demos/h5/demo18'
import Demo19 from './demos/h5/demo19'
import Demo20 from './demos/h5/demo20'
import Demo21 from './demos/h5/demo21'
import Demo22 from './demos/h5/demo22'
import Demo23 from './demos/h5/demo23'

const TabsDemo = () => {
const [translated] = useTranslate({
Expand All @@ -36,10 +31,6 @@ const TabsDemo = () => {
title2: '通过 value 匹配',
title3: '数据异步渲染 3s',
title4: '数量多,滚动操作',
title5: '左右布局',
title6: '左右布局-微笑曲线',
title12: '嵌套布局',
title13: '嵌套布局2',
title14: '滑动切换',
title7: 'Title 字体尺寸:20px 12px',
title8: '自定义标签栏',
Expand All @@ -60,10 +51,6 @@ const TabsDemo = () => {
title2: 'Match By Value',
title3: 'Data Is Rendered Asynchronously For 3s',
title4: 'A Large Number Of Scrolling Operations',
title5: 'Left And Right Layout',
title6: 'Left And Right Layout - Smile Curve',
title12: 'Tabs In Tabs',
title13: 'Tabs In Tabs 2',
title14: 'Slide To Switch',
title7: 'Title FontSize: 20px 12px',
title8: 'Custom Tab Bar',
Expand Down Expand Up @@ -111,20 +98,10 @@ const TabsDemo = () => {
<Demo15 />
<h2>{translated.title4}</h2>
<Demo16 />
<h2>{translated.title4} 2</h2>
<Demo17 />
<h2>{translated.title5}</h2>
<Demo18 />
<h2>{translated.title6}</h2>
<Demo19 />
<h2>{translated.title12}</h2>
<Demo20 />
<h2>{translated.title13}</h2>
<Demo21 />
<h2>{translated.title7}</h2>
<Demo22 />
<Demo17 />
<h2>{translated.title8}</h2>
<Demo23 />
<Demo18 />
</div>
</>
)
Expand Down
34 changes: 21 additions & 13 deletions src/packages/tabs/demos/h5/demo17.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,34 @@
import React, { useState } from 'react'
import { Tabs } from '@nutui/nutui-react'

const Demo17 = () => {
const [tab4value, setTab4value] = useState<number | string>('0')
const list4 = Array.from(new Array(10).keys())
const Demo22 = () => {
const [tab11value, setTab11value] = useState<string | number>('0')
const [tab12value, setTab12value] = useState<string | number>('0')
Comment on lines +4 to +6
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

组件命名与状态管理需要改进

组件从 Demo17 重命名为 Demo22,但文件名仍然是 demo17.tsx,这可能会导致混淆。建议保持文件名与组件名的一致性。另外,状态变量的命名(tab11value, tab12value)不够语义化。

建议进行如下修改:

-const Demo22 = () => {
-  const [tab11value, setTab11value] = useState<string | number>('0')
-  const [tab12value, setTab12value] = useState<string | number>('0')
+const Demo17 = () => {
+  const [largeTabValue, setLargeTabValue] = useState<string | number>('0')
+  const [smallTabValue, setSmallTabValue] = useState<string | number>('0')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const Demo22 = () => {
const [tab11value, setTab11value] = useState<string | number>('0')
const [tab12value, setTab12value] = useState<string | number>('0')
const Demo17 = () => {
const [largeTabValue, setLargeTabValue] = useState<string | number>('0')
const [smallTabValue, setSmallTabValue] = useState<string | number>('0')

return (
<>
<Tabs
value={tab4value}
style={{ height: '300px' }}
value={tab11value}
onChange={(value) => {
setTab4value(value)
setTab11value(value)
}}
direction="vertical"
style={{ '--nutui-tabs-titles-font-size': '20px' }}
>
{list4.map((item) => (
<Tabs.TabPane key={item} title={`Tab ${item}`}>
Tab {item}
</Tabs.TabPane>
))}
<Tabs.TabPane title="Tab 1"> Tab 1 </Tabs.TabPane>
<Tabs.TabPane title="Tab 2"> Tab 2 </Tabs.TabPane>
<Tabs.TabPane title="Tab 3"> Tab 3 </Tabs.TabPane>
</Tabs>
Comment on lines 9 to +19
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议增强标签页的可访问性和内容展示

  1. 缺少必要的 ARIA 属性来提升可访问性
  2. 标签页内容过于简单,建议添加更有意义的示例内容
  3. 建议使用常量来管理样式变量

建议按照以下方式修改:

+const FONT_SIZES = {
+  large: '20px',
+  small: '12px',
+}

 <Tabs
   value={tab11value}
   onChange={(value) => {
     setTab11value(value)
   }}
-  style={{ '--nutui-tabs-titles-font-size': '20px' }}
+  style={{ '--nutui-tabs-titles-font-size': FONT_SIZES.large }}
+  role="tablist"
+  aria-label="大字号标签页示例"
 >
-  <Tabs.TabPane title="Tab 1"> Tab 1 </Tabs.TabPane>
+  <Tabs.TabPane title="Tab 1" role="tabpanel" aria-label="标签页1">
+    这是一个使用大字号的标签页示例内容
+  </Tabs.TabPane>

Committable suggestion skipped: line range outside the PR's diff.

<Tabs
value={tab12value}
onChange={(value) => {
setTab12value(value)
}}
style={{ '--nutui-tabs-titles-font-size': '12px' }}
>
<Tabs.TabPane title="Tab 1"> Tab 1 </Tabs.TabPane>
<Tabs.TabPane title="Tab 2"> Tab 2 </Tabs.TabPane>
<Tabs.TabPane title="Tab 3"> Tab 3 </Tabs.TabPane>
Alex-huxiyang marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +20 to +29
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议重构重复的标签页代码

当前代码存在明显的重复,两个标签页组件的结构完全相同,仅字体大小不同。建议提取可重用的组件来减少代码重复。

建议创建一个可复用的标签页组件:

interface CustomTabsProps {
  value: string | number
  onChange: (value: string | number) => void
  fontSize: 'large' | 'small'
  label: string
}

const CustomTabs: React.FC<CustomTabsProps> = ({ value, onChange, fontSize, label }) => (
  <Tabs
    value={value}
    onChange={onChange}
    style={{ '--nutui-tabs-titles-font-size': FONT_SIZES[fontSize] }}
    role="tablist"
    aria-label={label}
  >
    <Tabs.TabPane title="Tab 1" role="tabpanel">示例内容 1</Tabs.TabPane>
    <Tabs.TabPane title="Tab 2" role="tabpanel">示例内容 2</Tabs.TabPane>
    <Tabs.TabPane title="Tab 3" role="tabpanel">示例内容 3</Tabs.TabPane>
  </Tabs>
)

Comment on lines +20 to +29
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

第二个 Tabs 组件存在重复代码

两个 Tabs 组件的结构完全相同,只是字体大小不同。建议将重复的部分抽离为可复用的组件。

建议创建一个新的组件来处理这种重复的结构:

interface CustomTabsProps {
  value: string | number
  onChange: (value: string | number) => void
  fontSize: string
}

const CustomTabs: React.FC<CustomTabsProps> = ({ value, onChange, fontSize }) => (
  <Tabs
    value={value}
    onChange={onChange}
    style={{ '--nutui-tabs-titles-font-size': fontSize }}
  >
    <Tabs.TabPane title="Tab 1">
      <div className="content">标签页内容 1</div>
    </Tabs.TabPane>
    <Tabs.TabPane title="Tab 2">
      <div className="content">标签页内容 2</div>
    </Tabs.TabPane>
    <Tabs.TabPane title="Tab 3">
      <div className="content">标签页内容 3</div>
    </Tabs.TabPane>
  </Tabs>
)

</Tabs>
</>
)
}
export default Demo17
export default Demo22
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

导出语句需要与组件名保持一致

如果采纳了之前的建议将组件改名为 Demo17,这里的导出语句也需要相应修改。

-export default Demo22
+export default Demo17
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export default Demo22
export default Demo17

47 changes: 35 additions & 12 deletions src/packages/tabs/demos/h5/demo18.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,49 @@
import React, { useState } from 'react'
import { Tabs } from '@nutui/nutui-react'
import { Star } from '@nutui/icons-react'

const Demo18 = () => {
const [tab5value, setTab5value] = useState<number | string>('0')
const list5 = Array.from(new Array(2).keys())
const Demo23 = () => {
Comment on lines +3 to +5
Copy link

Choose a reason for hiding this comment

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

💡 Codebase verification

组件命名不一致问题

文件名为 demo18.tsx,但组件名为 Demo23,这存在以下问题:

  • src/packages/tabs/demo.tsxsrc/packages/tabs/demo.taro.tsx 中仍在引用 Demo18
  • 文件名与组件名不一致,影响代码可维护性

建议:

  • 保持文件名与组件名一致,将文件重命名为 demo23.tsx
  • 或将组件名改回 Demo18 以匹配文件名
  • 更新所有相关引用
🔗 Analysis chain

验证组件重命名的影响

组件从 Demo18 重命名为 Demo23 可能会影响其他文件中的引用。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查是否有其他文件仍在引用 Demo18
rg "Demo18" --type tsx

Length of output: 50


Script:

#!/bin/bash
# Search for Demo18 references in all files
rg "Demo18"

# Also search for Demo23 to understand the current usage
rg "Demo23"

# List all files in the demos directory to understand the structure
fd . "src/packages/tabs/demos"

Length of output: 1980

const [tab7value, setTab7value] = useState('c1')
const list6 = [
{
title: '自定义 1',
paneKey: 'c1',
icon: <Star />,
},
{
title: '自定义 2',
paneKey: 'c2',
},
{
title: '自定义 3',
paneKey: 'c3',
},
]
return (
<>
<Tabs
style={{ height: '300px' }}
value={tab5value}
onChange={(value) => {
setTab5value(value)
value={tab7value}
title={() => {
return list6.map((item) => (
<div
onClick={() => setTab7value(item.paneKey)}
className={`nut-tabs-titles-item ${tab7value === item.paneKey ? 'nut-tabs-titles-item-active' : ''}`}
key={item.paneKey}
>
{item.icon || null}
<span className="nut-tabs-titles-item-text">{item.title}</span>
<span className="nut-tabs-titles-item-line" />
</div>
Alex-huxiyang marked this conversation as resolved.
Show resolved Hide resolved
))
}}
direction="vertical"
>
{list5.map((item) => (
<Tabs.TabPane key={item} title={`Tab ${item}`}>
Tab {item}
{list6.map((item) => (
<Tabs.TabPane key={item.paneKey} value={item.paneKey}>
{item.title}
</Tabs.TabPane>
))}
</Tabs>
</>
)
}
Comment on lines 22 to 48
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议优化渲染逻辑和性能

当前实现存在以下几个需要注意的地方:

  1. 建议将标题渲染逻辑抽离为独立组件:
const TabTitle: React.FC<{
  item: TabItem;
  isActive: boolean;
  onClick: () => void;
}> = ({ item, isActive, onClick }) => (
  <div
    onClick={onClick}
    className={`nut-tabs-titles-item ${isActive ? 'nut-tabs-titles-item-active' : ''}`}
  >
    {item.icon}
    <span className="nut-tabs-titles-item-text">{item.title}</span>
    <span className="nut-tabs-titles-item-line" />
  </div>
);
  1. 建议使用 CSS Modules 或 styled-components 替代直接的 className 操作

  2. 建议使用 useMemo 优化列表渲染:

const tabPanes = useMemo(() => 
  list6.map((item) => (
    <Tabs.TabPane key={item.paneKey} value={item.paneKey}>
      {item.title}
    </Tabs.TabPane>
  )),
  [list6]
);

export default Demo18
export default Demo23
27 changes: 0 additions & 27 deletions src/packages/tabs/demos/h5/demo19.tsx

This file was deleted.

34 changes: 0 additions & 34 deletions src/packages/tabs/demos/h5/demo22.tsx

This file was deleted.

49 changes: 0 additions & 49 deletions src/packages/tabs/demos/h5/demo23.tsx

This file was deleted.

Loading
Loading