Skip to content
Merged
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`should only render title 1`] = `"<div class="nut-tabbar"><div class="nut-tabbar-wrap"><div class="nut-tabbar-item nut-tabbar-item-active" style="color: blue;"><div class="nut-badge"><div class="nut-tabbar-item-icon-box nut-tabbar-item-icon-box-nav nut-tabbar-item-icon-box-large">首页</div><div class="nut-badge-sup nut-badge-number nut-badge-content" style="top: 0px; right: 0px;">11</div></div></div><div class="nut-tabbar-item" style="color: grey;"><div class="nut-badge"><div class="nut-tabbar-item-icon-box nut-tabbar-item-icon-box-nav nut-tabbar-item-icon-box-large">分类</div></div></div><div class="nut-tabbar-item" style="color: grey;"><div class="nut-badge"><div class="nut-tabbar-item-icon-box nut-tabbar-item-icon-box-nav nut-tabbar-item-icon-box-large">逛</div></div></div></div></div>"`;
exports[`render item size 2 and direction is horizontal 1`] = `"<div class="nut-tabbar"><div class="nut-tabbar-wrap nut-tabbar-wrap-2 nut-tabbar-wrap-horizontal"><div class="nut-tabbar-item nut-tabbar-item-active"><svg class="nut-icon nut-icon-Home " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-labelledby="Home" role="presentation"><path d="M.209 17.059 24 0l23.79 17.065a.5.5 0 0 1 .209.407v2.46a.5.5 0 0 1-.791.407l-2.208-1.584v19.242a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V18.749L.79 20.333A.5.5 0 0 1 0 19.926v-2.46a.5.5 0 0 1 .209-.407M24 3.692 6 16.598v21.399a5 5 0 0 0 5.001 5h26a5 5 0 0 0 5-5V16.603zm-4.939 21.447a.527.527 0 0 0-.718.011l-1.415 1.414a.481.481 0 0 0 .01.7c3.998 3.64 10.127 3.64 14.124 0a.482.482 0 0 0 .009-.7l-1.415-1.414a.527.527 0 0 0-.719-.011 7.501 7.501 0 0 1-9.876 0" fill="currentColor"></path></svg><div class="nut-tabbar-item-text">首页</div><div class="nut-badge"><div class="nut-badge-sup" style="top: 0px; right: 0px;">招手</div></div></div><div class="nut-tabbar-item"><div class="nut-badge"><svg class="nut-icon nut-icon-Hi " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" aria-labelledby="Hi" role="presentation"><path d="M650.67 554.67c-20.09 0-38.33-8.37-51.6-22.18l-46.14 44.35c24.67 25.69 59.33 41.82 97.74 41.83 38.4 0 73.06-16.14 97.74-41.83l-46.15-44.35c-13.27 13.8-31.51 22.18-51.59 22.18M501.33 384h85.34v85.33h-85.34zM800 384h-85.33v85.33H800z" fill="currentColor"></path>,<path d="m452.37 44.16-4.9-3.49c-34.91-24.73-78.02-23.02-117.12-10.05-42.37 14.05-86.46 42.93-126.89 78.49-80.41 70.72-155.64 176.32-178.25 271.83C1.41 481.44-7.06 592.03 6.42 689.39c13.33 96.28 49.17 186.04 120.4 235.6l4.86 3.39c45.07 31.4 75.17 52.28 130.93 62.94 53.91 10.29 132.93 11.35 280.22 11.35 148.16 0 260.15-8.62 338.46-43.19 40.28-17.77 72.47-42.7 96.08-77.06 23.39-34.06 36.93-75.31 43.41-123.63 10.5-78.23-5.54-154.19-35.06-209.06-4.19-7.79-4.97-18.1-1.47-27.62 26.17-71.15 19.17-166.2-19.65-242.57-39.67-78.05-114.86-140.27-225.27-135.44-8.03.35-15.53-3.14-20.03-8.68C640.04 37.97 539.73 27.4 465.25 39.74a32.87 32.87 0 0 0-7.3 2.09l-5.57 2.33zm47.09 56.89 14.18-.09c50.88-.34 107.24 17.1 154.97 75.77 18.09 22.25 45.76 33.95 73.57 32.74 79.62-3.49 133.55 39.51 164.16 99.74 31.45 61.85 35.82 137.97 16.57 190.31-9.53 25.9-8.41 55.85 5.26 81.23 22.87 42.52 36.52 104.53 27.83 169.34-5.57 41.48-16.57 72.06-32.49 95.25-15.72 22.89-37.65 40.62-68.59 54.28-64.09 28.29-162.85 37.63-312.08 37.63-150.11 0-221.62-1.34-267.97-10.2-42.18-8.06-62.01-21.87-109.62-55.01l-1.13-.78c-49.19-34.24-80.64-101.94-92.96-190.87C59 592.54 66.5 490.22 88.8 396.02c18.52-78.17 83.84-172.71 157.8-237.76 36.76-32.34 73.28-55.25 104.31-65.53 31.3-10.38 50.41-6.21 62.12 3.97 24.95 21.7 28.13 35.35 28.03 42.11-.13 7.97-4.86 19.27-20.76 35.97-14.26 14.98-33.02 29.82-54.59 46.89l-6.66 5.27c-23.31 18.47-49.34 39.52-69.72 63.15-65.95 76.51-72.37 171.52-68.05 227.42a32.69 32.69 0 1 0 65.17-5.04c-3.71-47.89 2.73-122.06 52.38-179.63 15.75-18.28 37.03-35.78 60.8-54.61l6.8-5.38c20.91-16.51 43.56-34.42 61.19-52.92 19.38-20.36 38.28-47.03 38.79-80.11a89.06 89.06 0 0 0-3.2-25.07z" fill="currentColor"></path></svg><div class="nut-badge-sup nut-badge-dot nut-badge-dot-normal nut-badge-content" style="top: 3px; right: 0px;"></div></div><div class="nut-tabbar-item-text">我的</div></div></div></div>"`;

exports[`should render fixed element when using bottom prop 1`] = `"<div class="nut-tabbar nut-tabbar-fixed"><div class="nut-tabbar-wrap"><div class="nut-tabbar-item nut-tabbar-item-active"><div class="nut-badge"><div class="nut-tabbar-item-icon-box"><svg class="nut-icon nut-icon-Home " style="width: 20px; height: 20px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-labelledby="Home" role="presentation"><path d="M.209 17.059 24 0l23.79 17.065a.5.5 0 0 1 .209.407v2.46a.5.5 0 0 1-.791.407l-2.208-1.584v19.242a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V18.749L.79 20.333A.5.5 0 0 1 0 19.926v-2.46a.5.5 0 0 1 .209-.407M24 3.692 6 16.598v21.399a5 5 0 0 0 5.001 5h26a5 5 0 0 0 5-5V16.603zm-4.939 21.447a.527.527 0 0 0-.718.011l-1.415 1.414a.481.481 0 0 0 .01.7c3.998 3.64 10.127 3.64 14.124 0a.482.482 0 0 0 .009-.7l-1.415-1.414a.527.527 0 0 0-.719-.011 7.501 7.501 0 0 1-9.876 0" fill="currentColor"></path></svg></div></div><div class="nut-tabbar-item-icon-box nut-tabbar-item-icon-box-nav">首页</div></div><div class="nut-tabbar-item"><div class="nut-badge"><div class="nut-tabbar-item-icon-box"><svg class="nut-icon nut-icon-Category " style="width: 20px; height: 20px;" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" aria-labelledby="Category" role="presentation"><path d="M85.33 138.67V96c0-5.97 4.69-10.67 10.67-10.67h832c5.97 0 10.67 4.69 10.67 10.67v42.67c0 5.97-4.69 10.67-10.67 10.66H96c-5.97 0-10.67-4.69-10.67-10.66m0 394.66v-42.66C85.33 484.7 90.02 480 96 480h832c5.97 0 10.67 4.69 10.67 10.67v42.66c0 5.97-4.69 10.67-10.67 10.67H96c-5.97 0-10.67-4.69-10.67-10.67M928 874.67c5.97 0 10.67 4.69 10.67 10.66V928c0 5.97-4.69 10.67-10.67 10.67H96c-5.97 0-10.67-4.69-10.67-10.67v-42.67c0-5.97 4.69-10.67 10.67-10.66z" fill="currentColor"></path></svg></div></div><div class="nut-tabbar-item-icon-box nut-tabbar-item-icon-box-nav">分类</div></div></div><div class="nut-tabbar-safe-area"></div></div>"`;
exports[`should only render title 1`] = `"<div class="nut-tabbar"><div class="nut-tabbar-wrap nut-tabbar-wrap-3"><div class="nut-tabbar-item nut-tabbar-item-active nut-tabbar-item-large" style="color: blue;"><div class="nut-badge"><div class="nut-tabbar-item-text">首页</div><div class="nut-badge-sup nut-badge-number nut-badge-content" style="top: 0px; right: 0px;">11</div></div></div><div class="nut-tabbar-item nut-tabbar-item-large" style="color: grey;"><div class="nut-badge"><div class="nut-tabbar-item-text">分类</div></div></div><div class="nut-tabbar-item nut-tabbar-item-large" style="color: grey;"><div class="nut-badge"><div class="nut-tabbar-item-text">逛</div></div></div></div></div>"`;

exports[`should render fixed element when using bottom prop 1`] = `"<div class="nut-tabbar nut-tabbar-fixed"><div class="nut-tabbar-wrap nut-tabbar-wrap-2"><div class="nut-tabbar-item nut-tabbar-item-active"><div class="nut-badge"><svg class="nut-icon nut-icon-Home " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" aria-labelledby="Home" role="presentation"><path d="M.209 17.059 24 0l23.79 17.065a.5.5 0 0 1 .209.407v2.46a.5.5 0 0 1-.791.407l-2.208-1.584v19.242a8 8 0 0 1-8 8H11a8 8 0 0 1-8-8V18.749L.79 20.333A.5.5 0 0 1 0 19.926v-2.46a.5.5 0 0 1 .209-.407M24 3.692 6 16.598v21.399a5 5 0 0 0 5.001 5h26a5 5 0 0 0 5-5V16.603zm-4.939 21.447a.527.527 0 0 0-.718.011l-1.415 1.414a.481.481 0 0 0 .01.7c3.998 3.64 10.127 3.64 14.124 0a.482.482 0 0 0 .009-.7l-1.415-1.414a.527.527 0 0 0-.719-.011 7.501 7.501 0 0 1-9.876 0" fill="currentColor"></path></svg></div><div class="nut-tabbar-item-text">首页</div></div><div class="nut-tabbar-item"><div class="nut-badge"><svg class="nut-icon nut-icon-Category " xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1024 1024" aria-labelledby="Category" role="presentation"><path d="M85.33 138.67V96c0-5.97 4.69-10.67 10.67-10.67h832c5.97 0 10.67 4.69 10.67 10.67v42.67c0 5.97-4.69 10.67-10.67 10.66H96c-5.97 0-10.67-4.69-10.67-10.66m0 394.66v-42.66C85.33 484.7 90.02 480 96 480h832c5.97 0 10.67 4.69 10.67 10.67v42.66c0 5.97-4.69 10.67-10.67 10.67H96c-5.97 0-10.67-4.69-10.67-10.67M928 874.67c5.97 0 10.67 4.69 10.67 10.66V928c0 5.97-4.69 10.67-10.67 10.67H96c-5.97 0-10.67-4.69-10.67-10.67v-42.67c0-5.97 4.69-10.67 10.67-10.66z" fill="currentColor"></path></svg></div><div class="nut-tabbar-item-text">分类</div></div></div><div class="nut-safe-area nut-safe-area-position-bottom"></div></div>"`;
120 changes: 87 additions & 33 deletions src/packages/tabbar/__tests__/tabbar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,45 @@
import * as React from 'react'
import { render, fireEvent } from '@testing-library/react'
import { render, fireEvent, waitFor } from '@testing-library/react'
import '@testing-library/jest-dom'

import { Cart, Category, Hi, Home, User } from '@nutui/icons-react'
import {
Cart,
Category,
Heart,
HeartFill,
Hi,
Home,
User,
} from '@nutui/icons-react'
import { Tabbar } from '../tabbar'

test('should render tabbar when default', () => {
const { container } = render(
<>
<Tabbar>
<Tabbar.Item title="首页" icon={<Home width={20} height={20} />} />
<Tabbar.Item title="分类" icon={<Category width={20} height={20} />} />
<Tabbar.Item title="逛" icon={<Hi width={20} height={20} />} />
<Tabbar.Item title="购物车" icon={<Cart width={20} height={20} />} />
<Tabbar.Item title="我的" icon={<User width={20} height={20} />} />
<Tabbar.Item title="首页" icon={<Home />} />
<Tabbar.Item title="分类" icon={<Category />} />
<Tabbar.Item title="逛" icon={<Hi />} />
<Tabbar.Item title="购物车" icon={<Cart />} />
<Tabbar.Item title="我的" icon={<User />} />
</Tabbar>
</>
)

expect(container.firstChild).toBeInTheDocument()
expect(container.querySelectorAll('.nut-tabbar-item').length).toEqual(5)
expect(
container.querySelectorAll('.nut-tabbar-item-icon-box').length
).toEqual(10)
container.querySelectorAll('.nut-tabbar-item .nut-icon').length
).toEqual(5)
})

test('should render custom color and badge when using prop', () => {
const { container } = render(
<>
<Tabbar inactiveColor="grey" activeColor="blue">
<Tabbar.Item
title="首页"
icon={<Home width={20} height={20} />}
value={11}
/>
<Tabbar.Item title="分类" icon={<Category width={20} height={20} />} />
<Tabbar.Item title="逛" icon={<Hi width={20} height={20} />} />
<Tabbar.Item title="首页" icon={<Home />} value={11} />
<Tabbar.Item title="分类" icon={<Category />} />
<Tabbar.Item title="逛" icon={<Hi />} />
</Tabbar>
</>
)
Expand All @@ -51,8 +55,8 @@ test('should render fixed element when using bottom prop', async () => {
const { container } = render(
<>
<Tabbar fixed safeArea>
<Tabbar.Item title="首页" icon={<Home width={20} height={20} />} />
<Tabbar.Item title="分类" icon={<Category width={20} height={20} />} />
<Tabbar.Item title="首页" icon={<Home />} />
<Tabbar.Item title="分类" icon={<Category />} />
</Tabbar>
</>
)
Expand All @@ -64,37 +68,75 @@ test('should match active tabbar by click', async () => {
<>
<Tabbar inactiveColor="grey" activeColor="blue">
<Tabbar.Item
title="首页"
icon={<Home width={20} height={20} />}
value={11}
title={(active) => (active ? '首页' : '首页2')}
icon={(active) => (active ? <HeartFill /> : <Heart />)}
value={(active) => (active ? '招手' : '22')}
/>
<Tabbar.Item title="分类" icon={<Category width={20} height={20} />} />
<Tabbar.Item title="逛" icon={<Hi width={20} height={20} />} />
<Tabbar.Item title="我的" icon={<Hi />} dot />
<Tabbar.Item title="我的" icon={<Hi />} dot />
<Tabbar.Item title="我的" icon={<Hi />} dot />
</Tabbar>
</>
)

const tabbarItem: NodeListOf<HTMLElement> =
container.querySelectorAll('.nut-tabbar-item')
const tabbarItemText: NodeListOf<HTMLElement> = container.querySelectorAll(
'.nut-tabbar-item-text'
)
const tabbarItemBadgeValue: NodeListOf<HTMLElement> =
container.querySelectorAll('.nut-badge-sup')
const tabbarItemActiveIcon: NodeListOf<HTMLElement> =
container.querySelectorAll('.nut-icon-HeartFill')
const tabbarItemIcon: NodeListOf<HTMLElement> =
container.querySelectorAll('.nut-icon-Heart')
expect(tabbarItem[0].style.color).toEqual('blue')
expect(tabbarItemText[0].innerText).toEqual('首页')
expect(tabbarItemActiveIcon.length).toEqual(1)
expect(tabbarItemIcon.length).toEqual(0)
expect(tabbarItemBadgeValue[0].innerText).toEqual('招手')
fireEvent.click(tabbarItem[1])
waitFor(() => {
expect(tabbarItem[0].style.color).toEqual('grey')
expect(tabbarItemText[0].innerText).toEqual('首页2')
expect(tabbarItemActiveIcon.length).toEqual(0)
expect(tabbarItemIcon.length).toEqual(1)
expect(tabbarItemBadgeValue[0].innerText).toEqual('22')
expect(tabbarItem[1].style.color).toEqual('blue')
})
})

test('double click', async () => {
const onActiveClick = vi.fn()
const { container } = render(
<>
<Tabbar>
<Tabbar.Item title="首页" icon={<Home />} value={11} />
<Tabbar.Item
title="分类"
icon={<Category />}
onActiveClick={onActiveClick}
/>
<Tabbar.Item title="逛" icon={<Hi />} />
</Tabbar>
</>
)

const tabbarItem: NodeListOf<HTMLElement> =
container.querySelectorAll('.nut-tabbar-item')
fireEvent.click(tabbarItem[1])
fireEvent.click(tabbarItem[1])
expect(tabbarItem[1].style.color).toEqual('blue')
fireEvent.click(tabbarItem[2])
expect(tabbarItem[2].style.color).toEqual('blue')
expect(onActiveClick).toBeCalled()
})

test('should show sure emitted when click', async () => {
const onSwitch = vi.fn()
const { container } = render(
<>
<Tabbar inactiveColor="grey" activeColor="blue" onSwitch={onSwitch}>
<Tabbar.Item
title="首页"
icon={<Home width={20} height={20} />}
value={11}
/>
<Tabbar.Item title="分类" icon={<Category width={20} height={20} />} />
<Tabbar.Item title="逛" icon={<Hi width={20} height={20} />} />
<Tabbar.Item title="首页" icon={<Home />} value={11} />
<Tabbar.Item title="分类" icon={<Category />} />
<Tabbar.Item title="逛" icon={<Hi />} />
</Tabbar>
</>
)
Expand All @@ -118,3 +160,15 @@ test('should only render title', async () => {
)
expect(container.innerHTML).toMatchSnapshot()
})

test('render item size 2 and direction is horizontal', async () => {
const { container } = render(
<>
<Tabbar direction="horizontal">
<Tabbar.Item title="首页" icon={<Home />} value="招手" />
<Tabbar.Item title="我的" icon={<Hi />} dot />
</Tabbar>
</>
)
expect(container.innerHTML).toMatchSnapshot()
})
46 changes: 24 additions & 22 deletions src/packages/tabbar/demo.taro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,57 +17,59 @@ const TabbarDemo = () => {
const [translated] = useTranslate({
'zh-CN': {
ce5c5446: '基础用法',
c38a08ef: '自定义选中',
c38a08ef: '首坑品牌+营销态',
ce5c5448: '只配图标',
ce5c5440: '无图标',
ce5c5440: '只配文字',
b840c88f: '徽标提示',
customColor: '自定义颜色',
'8dab2f66': '可自定义icon个数的tabbar',
customColor: '自定义颜色+数量',
cfbdc781: '固定底部',
c9e6df49: '红点',
c9e6df49: '受控',
c9e6df48: '模拟双击支持回调',
},
'zh-TW': {
ce5c5446: '基礎用法',
c38a08ef: '自定義選中',
ce5c5448: '只配图标',
ce5c5440: '无图标',
c38a08ef: '首坑品牌+營銷態',
ce5c5448: '只配圖標',
ce5c5440: '只配文字',
b840c88f: '徽標提示',
customColor: '自定義顏色',
'8dab2f66': '可自定義icon個數的tabbar',
customColor: '自定義顏色+數量',
cfbdc781: '固定底部',
c9e6df49: '紅點',
c9e6df49: '受控',
c9e6df48: '模擬雙擊支持回調',
},
'en-US': {
ce5c5446: 'Basic Usage',
c38a08ef: 'Custom DefaultValue',
c38a08ef: 'Custom',
ce5c5448: 'Only Icon',
ce5c5440: 'No Icon',
ce5c5440: 'Only Text',
b840c88f: 'Logo Tips',
customColor: 'Custom Color',
'8dab2f66': 'Tabbar With Custom Number Of Icons',
customColor: 'Custom Color and Size',
cfbdc781: 'Fixed Bottom',
c9e6df49: 'Dot',
c9e6df49: 'With Controled',
c9e6df48: 'Mock Double Click',
},
Comment on lines 40 to 50
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

英文翻译中存在拼写错误

第48行中的英文翻译 "With Controled" 存在拼写错误,应修改为 "With Controlled"(多一个'l')。

此外,英文翻译中 "Custom" 可能过于简单,无法准确表达 "首坑品牌+营销态" 的含义,建议考虑使用更具描述性的翻译,如 "Featured Brand + Marketing State"。

-      c9e6df49: 'With Controled',
+      c9e6df49: 'With Controlled',
📝 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
'en-US': {
ce5c5446: 'Basic Usage',
c38a08ef: 'Custom DefaultValue',
c38a08ef: 'Custom',
ce5c5448: 'Only Icon',
ce5c5440: 'No Icon',
ce5c5440: 'Only Text',
b840c88f: 'Logo Tips',
customColor: 'Custom Color',
'8dab2f66': 'Tabbar With Custom Number Of Icons',
customColor: 'Custom Color and Size',
cfbdc781: 'Fixed Bottom',
c9e6df49: 'Dot',
c9e6df49: 'With Controled',
c9e6df48: 'Mock Double Click',
},
'en-US': {
ce5c5446: 'Basic Usage',
c38a08ef: 'Custom',
ce5c5448: 'Only Icon',
ce5c5440: 'Only Text',
b840c88f: 'Logo Tips',
customColor: 'Custom Color and Size',
cfbdc781: 'Fixed Bottom',
c9e6df49: 'With Controlled',
c9e6df48: 'Mock Double Click',
},

})
return (
<>
<Header />
<ScrollView className={`demo ${Taro.getEnv() === 'WEB' ? 'web' : ''}`}>
<ScrollView
className={`demo full ${Taro.getEnv() === 'WEB' ? 'web' : ''}`}
>
<View className="h2">{translated.ce5c5446}</View>
<Demo1 />
<View className="h2">{translated.c38a08ef}</View>
<View className="h2">{translated.b840c88f}</View>
<Demo2 />
<View className="h2">{translated.ce5c5448}</View>
<Demo3 />
<View className="h2">{translated.ce5c5440}</View>
<Demo4 />
<View className="h2">{translated.b840c88f}</View>
<View className="h2">{translated.c38a08ef}</View>
<Demo5 />
<View className="h2">{translated.c9e6df49}</View>
<Demo6 />
<View className="h2">{translated.customColor}</View>
<Demo6 />
<View className="h2">{translated.c9e6df49}</View>
<Demo7 />
<View className="h2">{translated['8dab2f66']}</View>
<View className="h2">{translated.c9e6df48}</View>
<Demo8 />
<View className="h2" style={{ marginBottom: 100 }}>
{translated.cfbdc781}
Expand Down
Loading
Loading