diff --git a/src/packages/tabbar/__tests__/__snapshots__/tabbar.spec.tsx.snap b/src/packages/tabbar/__tests__/__snapshots__/tabbar.spec.tsx.snap index 0cac7282f9..a94bfdb4a4 100644 --- a/src/packages/tabbar/__tests__/__snapshots__/tabbar.spec.tsx.snap +++ b/src/packages/tabbar/__tests__/__snapshots__/tabbar.spec.tsx.snap @@ -1,5 +1,7 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`should only render title 1`] = `"
首页
11
分类
"`; +exports[`render item size 2 and direction is horizontal 1`] = `"
首页
招手
,
我的
"`; -exports[`should render fixed element when using bottom prop 1`] = `"
首页
分类
"`; +exports[`should only render title 1`] = `"
首页
11
分类
"`; + +exports[`should render fixed element when using bottom prop 1`] = `"
首页
分类
"`; diff --git a/src/packages/tabbar/__tests__/tabbar.spec.tsx b/src/packages/tabbar/__tests__/tabbar.spec.tsx index 7162b6c6df..d7590220b1 100644 --- a/src/packages/tabbar/__tests__/tabbar.spec.tsx +++ b/src/packages/tabbar/__tests__/tabbar.spec.tsx @@ -1,19 +1,27 @@ 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( <> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> ) @@ -21,21 +29,17 @@ test('should render tabbar when default', () => { 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( <> - } - value={11} - /> - } /> - } /> + } value={11} /> + } /> + } /> ) @@ -51,8 +55,8 @@ test('should render fixed element when using bottom prop', async () => { const { container } = render( <> - } /> - } /> + } /> + } /> ) @@ -64,23 +68,65 @@ test('should match active tabbar by click', async () => { <> } - value={11} + title={(active) => (active ? '首页' : '首页2')} + icon={(active) => (active ? : )} + value={(active) => (active ? '招手' : '22')} /> - } /> - } /> + } dot /> + } dot /> + } dot /> ) const tabbarItem: NodeListOf = container.querySelectorAll('.nut-tabbar-item') + const tabbarItemText: NodeListOf = container.querySelectorAll( + '.nut-tabbar-item-text' + ) + const tabbarItemBadgeValue: NodeListOf = + container.querySelectorAll('.nut-badge-sup') + const tabbarItemActiveIcon: NodeListOf = + container.querySelectorAll('.nut-icon-HeartFill') + const tabbarItemIcon: NodeListOf = + 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( + <> + + } value={11} /> + } + onActiveClick={onActiveClick} + /> + } /> + + + ) + + const tabbarItem: NodeListOf = + 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 () => { @@ -88,13 +134,9 @@ test('should show sure emitted when click', async () => { const { container } = render( <> - } - value={11} - /> - } /> - } /> + } value={11} /> + } /> + } /> ) @@ -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( + <> + + } value="招手" /> + } dot /> + + + ) + expect(container.innerHTML).toMatchSnapshot() +}) diff --git a/src/packages/tabbar/demo.taro.tsx b/src/packages/tabbar/demo.taro.tsx index 46b8b05d09..2fe2d46d74 100644 --- a/src/packages/tabbar/demo.taro.tsx +++ b/src/packages/tabbar/demo.taro.tsx @@ -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', }, }) return ( <>
- + {translated.ce5c5446} - {translated.c38a08ef} + {translated.b840c88f} {translated.ce5c5448} {translated.ce5c5440} - {translated.b840c88f} + {translated.c38a08ef} - {translated.c9e6df49} - {translated.customColor} + + {translated.c9e6df49} - {translated['8dab2f66']} + {translated.c9e6df48} {translated.cfbdc781} diff --git a/src/packages/tabbar/demo.tsx b/src/packages/tabbar/demo.tsx index ea2325d3f3..71fd798948 100644 --- a/src/packages/tabbar/demo.tsx +++ b/src/packages/tabbar/demo.tsx @@ -14,59 +14,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', }, }) return ( <> -
+

{translated.ce5c5446}

-

{translated.c38a08ef}

+

{translated.b840c88f}

{translated.ce5c5448}

{translated.ce5c5440}

-

{translated.b840c88f}

+

{translated.c38a08ef}

-

{translated.c9e6df49}

-

{translated.customColor}

+ +

{translated.c9e6df49}

-

{translated['8dab2f66']}

+

{translated.c9e6df48}

-

{translated.cfbdc781}

+

{translated.cfbdc781}

diff --git a/src/packages/tabbar/demos/h5/demo1.tsx b/src/packages/tabbar/demos/h5/demo1.tsx index c2bcf25557..9093fa863b 100644 --- a/src/packages/tabbar/demos/h5/demo1.tsx +++ b/src/packages/tabbar/demos/h5/demo1.tsx @@ -1,15 +1,18 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Cart, Hi, Home, User, Heart, HeartFill } from '@nutui/icons-react' -const Demo1 = () => ( - - } value={9} /> - } dot /> +const Demo = () => ( + + } /> } /> + (active ? : )} + /> } /> } /> ) -export default Demo1 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo2.tsx b/src/packages/tabbar/demos/h5/demo2.tsx index 77ab75a6ea..3eaa4b7e8d 100644 --- a/src/packages/tabbar/demos/h5/demo2.tsx +++ b/src/packages/tabbar/demos/h5/demo2.tsx @@ -1,25 +1,15 @@ -import React, { useState } from 'react' +import React from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Cart, Message, Hi, Home, User } from '@nutui/icons-react' -const Demo2 = () => { - const [activeIndex, setActiveIndex] = useState(2) +const Demo = () => ( + + } dot /> + } value="内容" /> + } value={100} /> + } value={80} /> + } value={8} /> + +) - return ( - { - setActiveIndex(value) - }} - > - } /> - } /> - } /> - } /> - } /> - - ) -} - -export default Demo2 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo3.tsx b/src/packages/tabbar/demos/h5/demo3.tsx index 2d529e7a64..843593385d 100644 --- a/src/packages/tabbar/demos/h5/demo3.tsx +++ b/src/packages/tabbar/demos/h5/demo3.tsx @@ -1,18 +1,14 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Cart, Message, Hi, Home, User } from '@nutui/icons-react' -const Demo3 = () => ( - { - console.log(value) - }} - > +const Demo = () => ( + } /> - } /> } /> + } /> } /> } /> ) -export default Demo3 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo4.tsx b/src/packages/tabbar/demos/h5/demo4.tsx index c34d9970cd..c0e1ddaa3a 100644 --- a/src/packages/tabbar/demos/h5/demo4.tsx +++ b/src/packages/tabbar/demos/h5/demo4.tsx @@ -1,17 +1,13 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react' -const Demo4 = () => ( - { - console.log(value) - }} - > +const Demo = () => ( + - + ) -export default Demo4 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo5.tsx b/src/packages/tabbar/demos/h5/demo5.tsx index 49810182b1..310862217b 100644 --- a/src/packages/tabbar/demos/h5/demo5.tsx +++ b/src/packages/tabbar/demos/h5/demo5.tsx @@ -1,15 +1,37 @@ import React from 'react' -import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Tabbar, Image } from '@nutui/nutui-react' +import { Cart, Hi, Home, User, Message } from '@nutui/icons-react' -const Demo5 = () => ( - - } value={11} /> - } /> - } /> - } value={110} /> - } /> - -) +const Demo = () => { + return ( + + (active ? '' : '首页')} + icon={(active: boolean) => + active ? ( + + ) : ( + + ) + } + /> -export default Demo5 + + active ? ( + + ) : ( + + ) + } + title={(active: boolean) => (active ? '逛' : '')} + value="AI" + /> + } value={100} /> + } /> + } /> + + ) +} + +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo6.tsx b/src/packages/tabbar/demos/h5/demo6.tsx index a520a164f3..444d743e0b 100644 --- a/src/packages/tabbar/demos/h5/demo6.tsx +++ b/src/packages/tabbar/demos/h5/demo6.tsx @@ -1,15 +1,29 @@ import React from 'react' -import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' - -const Demo6 = () => ( - - } dot /> - } /> - } /> - } dot /> - } /> - +import { Tabbar, Space } from '@nutui/nutui-react' +import { Cart, Home, User } from '@nutui/icons-react' + +const Demo = () => ( + + + } /> + } /> + } /> + + + + } /> + } /> + + + + } dot /> + } value={22} /> + + ) -export default Demo6 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo7.tsx b/src/packages/tabbar/demos/h5/demo7.tsx index ea95c1c801..0150e34d80 100644 --- a/src/packages/tabbar/demos/h5/demo7.tsx +++ b/src/packages/tabbar/demos/h5/demo7.tsx @@ -1,15 +1,20 @@ -import React from 'react' +import React, { useState } from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Cart, Hi, Home, User } from '@nutui/icons-react' -const Demo7 = () => ( - - } /> - } /> - } /> - } /> - } /> - -) +const Demo = () => { + const [index, setIndex] = useState(3) -export default Demo7 + return ( + <> + setIndex(value)}> + } /> + } /> + } /> + } /> + + + ) +} + +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo8.tsx b/src/packages/tabbar/demos/h5/demo8.tsx index 56676f6451..c85b1dbc58 100644 --- a/src/packages/tabbar/demos/h5/demo8.tsx +++ b/src/packages/tabbar/demos/h5/demo8.tsx @@ -1,13 +1,22 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Category, Hi, Home } from '@nutui/icons-react' +import { Cart, Hi, Home, User, Heart, HeartFill } from '@nutui/icons-react' -const Demo8 = () => ( - +const Demo = () => ( + } /> - } /> } /> + (active ? : )} + /> + } + onActiveClick={() => console.log('可以在这里写想要的事件')} + /> + } /> ) -export default Demo8 +export default Demo diff --git a/src/packages/tabbar/demos/h5/demo9.tsx b/src/packages/tabbar/demos/h5/demo9.tsx index 8a7c7711a6..7f2f530f6c 100644 --- a/src/packages/tabbar/demos/h5/demo9.tsx +++ b/src/packages/tabbar/demos/h5/demo9.tsx @@ -1,15 +1,15 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react' +import { Cart, Message, Hi, Home, User } from '@nutui/icons-react' -const Demo9 = () => ( +const Demo = () => ( } /> - } /> } /> + } /> } /> } /> ) -export default Demo9 +export default Demo diff --git a/src/packages/tabbar/demos/taro/demo1.tsx b/src/packages/tabbar/demos/taro/demo1.tsx index 5dc7d62d3b..aa769e1762 100644 --- a/src/packages/tabbar/demos/taro/demo1.tsx +++ b/src/packages/tabbar/demos/taro/demo1.tsx @@ -1,16 +1,15 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Cart, HeartFill, Heart, Hi, Home, User } from '@nutui/icons-react-taro' const Demo1 = () => ( - { - console.log(value) - }} - > - } value={9} /> - } /> + + } /> } /> + (active ? : )} + /> } /> } /> diff --git a/src/packages/tabbar/demos/taro/demo2.tsx b/src/packages/tabbar/demos/taro/demo2.tsx index 8e6d3675a0..25504aecbd 100644 --- a/src/packages/tabbar/demos/taro/demo2.tsx +++ b/src/packages/tabbar/demos/taro/demo2.tsx @@ -1,15 +1,15 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Cart, Hi, Home, User, Message } from '@nutui/icons-react-taro' -const Demo2 = () => ( - - } /> - } /> - } /> - } /> - } /> +const Demo5 = () => ( + + } title="首页" dot /> + } value="内容" /> + } value={100} /> + } value={80} /> + } value={8} /> ) -export default Demo2 +export default Demo5 diff --git a/src/packages/tabbar/demos/taro/demo3.tsx b/src/packages/tabbar/demos/taro/demo3.tsx index ca83abc8a8..99995e3ff6 100644 --- a/src/packages/tabbar/demos/taro/demo3.tsx +++ b/src/packages/tabbar/demos/taro/demo3.tsx @@ -1,19 +1,14 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Cart, Message, Hi, Home, User } from '@nutui/icons-react-taro' const Demo3 = () => ( - { - console.log(value) - }} - > + } /> - } /> } /> + } /> } /> } /> ) - export default Demo3 diff --git a/src/packages/tabbar/demos/taro/demo4.tsx b/src/packages/tabbar/demos/taro/demo4.tsx index cc27a0f16b..2e06ac000f 100644 --- a/src/packages/tabbar/demos/taro/demo4.tsx +++ b/src/packages/tabbar/demos/taro/demo4.tsx @@ -2,17 +2,12 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' const Demo4 = () => ( - { - console.log(value) - }} - > + - + ) - export default Demo4 diff --git a/src/packages/tabbar/demos/taro/demo5.tsx b/src/packages/tabbar/demos/taro/demo5.tsx index bccb849b86..e03a0f4383 100644 --- a/src/packages/tabbar/demos/taro/demo5.tsx +++ b/src/packages/tabbar/demos/taro/demo5.tsx @@ -1,15 +1,47 @@ import React from 'react' -import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Tabbar, Image } from '@nutui/nutui-react-taro' +import { Cart, Hi, Home, User, Message } from '@nutui/icons-react-taro' +import { harmony } from '@/utils/platform-taro' +import pxTransform from '@/utils/px-transform' -const Demo5 = () => ( - - } title="首页" value={11} /> - } /> - } /> - } value={110} /> - } /> - -) +const Demo2 = () => { + return ( + + (active ? '' : '首页')} + icon={(active: boolean) => + active ? ( + + ) : ( + + ) + } + /> -export default Demo5 + + active ? ( + + ) : ( + + ) + } + title={(active: boolean) => (active ? '逛' : '')} + value="AI" + /> + } value={100} /> + } /> + } /> + + ) +} + +export default Demo2 diff --git a/src/packages/tabbar/demos/taro/demo6.tsx b/src/packages/tabbar/demos/taro/demo6.tsx index 75a4064f82..ecf57d0c8b 100644 --- a/src/packages/tabbar/demos/taro/demo6.tsx +++ b/src/packages/tabbar/demos/taro/demo6.tsx @@ -1,15 +1,29 @@ import React from 'react' -import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' - -const Demo6 = () => ( - - } dot /> - } /> - } /> - } dot /> - } /> - +import { Tabbar, Space } from '@nutui/nutui-react-taro' +import { Cart, Home, User } from '@nutui/icons-react-taro' + +const Demo7 = () => ( + + + } /> + } /> + } /> + + + + } /> + } /> + + + + } dot /> + } value={22} /> + + ) -export default Demo6 +export default Demo7 diff --git a/src/packages/tabbar/demos/taro/demo7.tsx b/src/packages/tabbar/demos/taro/demo7.tsx index 3e2c8fe155..0eed28496a 100644 --- a/src/packages/tabbar/demos/taro/demo7.tsx +++ b/src/packages/tabbar/demos/taro/demo7.tsx @@ -1,15 +1,20 @@ -import React from 'react' +import React, { useState } from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Cart, Hi, Home, User } from '@nutui/icons-react-taro' -const Demo7 = () => ( - - } /> - } /> - } /> - } /> - } /> - -) +const Demo = () => { + const [index, setIndex] = useState(3) -export default Demo7 + return ( + <> + setIndex(value)}> + } /> + } /> + } /> + } /> + + + ) +} + +export default Demo diff --git a/src/packages/tabbar/demos/taro/demo8.tsx b/src/packages/tabbar/demos/taro/demo8.tsx index 6db0b54620..ff2b4b8627 100644 --- a/src/packages/tabbar/demos/taro/demo8.tsx +++ b/src/packages/tabbar/demos/taro/demo8.tsx @@ -1,13 +1,22 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Category, Hi, Home } from '@nutui/icons-react-taro' +import { Cart, Hi, Home, User, Heart, HeartFill } from '@nutui/icons-react-taro' -const Demo8 = () => ( - +const Demo = () => ( + } /> - } /> } /> + (active ? : )} + /> + } + onActiveClick={() => console.log('可以在这里写想要的事件')} + /> + } /> ) -export default Demo8 +export default Demo diff --git a/src/packages/tabbar/demos/taro/demo9.tsx b/src/packages/tabbar/demos/taro/demo9.tsx index b9e8b3fe7e..ef8b2ece6d 100644 --- a/src/packages/tabbar/demos/taro/demo9.tsx +++ b/src/packages/tabbar/demos/taro/demo9.tsx @@ -1,12 +1,12 @@ import React from 'react' import { Tabbar } from '@nutui/nutui-react-taro' -import { Cart, Category, Hi, Home, User } from '@nutui/icons-react-taro' +import { Cart, Message, Hi, Home, User } from '@nutui/icons-react-taro' const Demo9 = () => ( } /> - } /> } /> + } /> } /> } /> diff --git a/src/packages/tabbar/doc.en-US.md b/src/packages/tabbar/doc.en-US.md index 60982b9f24..b2647d79c3 100644 --- a/src/packages/tabbar/doc.en-US.md +++ b/src/packages/tabbar/doc.en-US.md @@ -18,7 +18,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### Custom DefaultValue +### Logo Tips :::demo @@ -34,7 +34,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### No Icon +### Only Text :::demo @@ -42,7 +42,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### Logo Tips +### Custom :::demo @@ -50,7 +50,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### Dot +### Custom Color and Size :::demo @@ -58,7 +58,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### Custom Color +### With Controlled :::demo @@ -66,7 +66,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### Tabbar With Custom Number Of Icons +### onActiveClick Event :::demo @@ -102,13 +102,14 @@ import { Tabbar } from '@nutui/nutui-react' | Property | Description | Type | Default | | --- | --- | --- | --- | -| title | the title of the tab | `ReactNode` | `-` | -| icon | Custom icon | `ReactNode` | `-` | -| value | value to show in Badge, eg number、charctor and custom content | `ReactNode` | `-` | +| title | the title of the tab | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| icon | Custom icon | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| value | value to show in Badge, eg number、charctor and custom content | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | | max | when value is number, it's the max size | `number` | `99` | | dot | Whether Badge is dotted | `boolean` | `false` | | top | Up and down offset of Badge, support unit setting, can be set to: 5, etc. | `number` | `0` | | right | Left and right offset of Badge, support unit setting, can be set to: 5, etc. | `number` | `0` | +| onActiveClick | When item is focused, you can add your callback when you click it again | `() => void` | `-` | ## Theming @@ -118,16 +119,16 @@ The component provides the following CSS variables, which can be used to customi | Name | Description | Default | | --- | --- | --- | -| \--nutui-tabbar-height | tabbar height | `50px` | +| \--nutui-tabbar-height | tabbar height | `46px` | | \--nutui-tabbar-active-color | active color | `$color-primary` | | \--nutui-tabbar-inactive-color | default color | `$color-title` | | \--nutui-tabbar-border-top | borderTop | `1px solid #eee` | | \--nutui-tabbar-border-bottom | borderBottom | `1px solid #eee` | | \--nutui-tabbar-box-shadow | boxShadow | `none` | -| \--nutui-tabbar-text-font-size | title fontSize | `$font-size-xs` | +| \--nutui-tabbar-text-font-size | title fontSize | `$font-size-xxs` | | \--nutui-tabbar-text-large-font-size | title fontSize when icon is null | `$font-size-l` | | \--nutui-tabbar-text-large-font-weight | title fontWeight when icon is null | `$font-weight` | | \--nutui-tabbar-text-line-height | title lineHeight | `initial` | -| \--nutui-tabbar-text-margin-top | title marginTop | `3px` | +| \--nutui-tabbar-text-margin-top | title marginTop | `4px` | diff --git a/src/packages/tabbar/doc.md b/src/packages/tabbar/doc.md index c703950d6a..f4686b8b63 100644 --- a/src/packages/tabbar/doc.md +++ b/src/packages/tabbar/doc.md @@ -18,7 +18,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 自定义选中 +### 徽标提示 :::demo @@ -34,7 +34,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 无图标 +### 只配文字 :::demo @@ -42,7 +42,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 徽标提示 +### 首坑品牌+营销态 :::demo @@ -50,7 +50,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 红点 +### 自定义颜色+数量 :::demo @@ -58,7 +58,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 自定义颜色 +### 受控 :::demo @@ -66,7 +66,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 可自定义icon个数的tabbar +### 焦点时点击(模拟双击)支持回调 :::demo @@ -102,13 +102,14 @@ import { Tabbar } from '@nutui/nutui-react' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| title | 标签页的标题 | `ReactNode` | `-` | -| icon | 自定义图标 | `ReactNode` | `-` | -| value | 徽标中显示的内容,支持数字、字符和自定义内容 | `ReactNode` | `-` | +| title | 标签页的标题 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| icon | 自定义图标 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| value | 徽标中显示的内容,支持数字、字符和自定义内容 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | | max | value 为数值时,最大值 | `number` | `99` | | dot | 徽标是否为小点 | `boolean` | `false` | | top | 徽标的上下偏移量,支持单位设置,可设置为:5 等 | `number` | `0` | | right | 徽标的左右偏移量,支持单位设置,可设置为:5 等 | `number` | `0` | +| onActiveClick | 用于处理当元素处于焦点时,再次点击时可增加自定义事件。 | `() => void` | `-` | ## 主题定制 @@ -118,16 +119,16 @@ import { Tabbar } from '@nutui/nutui-react' | 名称 | 说明 | 默认值 | | --- | --- | --- | -| \--nutui-tabbar-height | 高度 | `50px` | +| \--nutui-tabbar-height | 高度 | `46px` | | \--nutui-tabbar-active-color | 选中颜色 | `$color-primary` | | \--nutui-tabbar-inactive-color | 未选中颜色 | `$color-title` | | \--nutui-tabbar-border-top | 上边框 | `1px solid #eee` | | \--nutui-tabbar-border-bottom | 下边框 | `1px solid #eee` | | \--nutui-tabbar-box-shadow | 阴影 | `none` | -| \--nutui-tabbar-text-font-size | 标题字体大小 | `$font-size-xs` | +| \--nutui-tabbar-text-font-size | 标题字体大小 | `$font-size-xxs` | | \--nutui-tabbar-text-large-font-size | 无图标时标题字体大小 | `$font-size-l` | | \--nutui-tabbar-text-large-font-weight | 无图标时标题字体粗细 | `$font-weight` | | \--nutui-tabbar-text-line-height | 字体行高 | `initial` | -| \--nutui-tabbar-text-margin-top | 标题上外边距 | `3px` | +| \--nutui-tabbar-text-margin-top | 标题上外边距 | `4px` | diff --git a/src/packages/tabbar/doc.taro.md b/src/packages/tabbar/doc.taro.md index da8682648f..9ec6ca32da 100644 --- a/src/packages/tabbar/doc.taro.md +++ b/src/packages/tabbar/doc.taro.md @@ -18,7 +18,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 自定义选中 +### 徽标提示 :::demo @@ -34,7 +34,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 无图标 +### 只配文字 :::demo @@ -42,7 +42,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 徽标提示 +### 首坑品牌+营销态 :::demo @@ -50,7 +50,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 红点 +### 自定义颜色+数量 :::demo @@ -58,7 +58,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 自定义颜色 +### 受控 :::demo @@ -66,7 +66,7 @@ import { Tabbar } from '@nutui/nutui-react-taro' ::: -### 可自定义icon个数的tabbar +### 焦点时点击(模拟双击)支持回调 :::demo @@ -102,13 +102,14 @@ import { Tabbar } from '@nutui/nutui-react-taro' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| title | 标签页的标题 | `ReactNode` | `-` | -| icon | 自定义图标 | `ReactNode` | `-` | -| value | 徽标中显示的内容,支持数字、字符和自定义内容 | `ReactNode` | `-` | +| title | 标签页的标题 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| icon | 自定义图标 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| value | 徽标中显示的内容,支持数字、字符和自定义内容 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | | max | value 为数值时,最大值 | `number` | `99` | | dot | 徽标是否为小点 | `boolean` | `false` | | top | 徽标的上下偏移量,支持单位设置,可设置为:5 等 | `number` | `0` | | right | 徽标的左右偏移量,支持单位设置,可设置为:5 等 | `number` | `0` | +| onActiveClick | 用于处理当元素处于焦点时,再次点击时可增加自定义事件。 | `() => void` | `-` | ## 主题定制 @@ -118,16 +119,16 @@ import { Tabbar } from '@nutui/nutui-react-taro' | 名称 | 说明 | 默认值 | | --- | --- | --- | -| \--nutui-tabbar-height | 高度 | `50px` | +| \--nutui-tabbar-height | 高度 | `46px` | | \--nutui-tabbar-active-color | 选中颜色 | `$color-primary` | | \--nutui-tabbar-inactive-color | 未选中颜色 | `$color-title` | | \--nutui-tabbar-border-top | 上边框 | `1px solid #eee` | | \--nutui-tabbar-border-bottom | 下边框 | `1px solid #eee` | | \--nutui-tabbar-box-shadow | 阴影 | `none` | -| \--nutui-tabbar-text-font-size | 标题字体大小 | `$font-size-xs` | +| \--nutui-tabbar-text-font-size | 标题字体大小 | `$font-size-xxs` | | \--nutui-tabbar-text-large-font-size | 无图标时标题字体大小 | `$font-size-l` | | \--nutui-tabbar-text-large-font-weight | 无图标时标题字体粗细 | `$font-weight` | | \--nutui-tabbar-text-line-height | 字体行高 | `initial` | -| \--nutui-tabbar-text-margin-top | 标题上外边距 | `3px` | +| \--nutui-tabbar-text-margin-top | 标题上外边距 | `4px` | diff --git a/src/packages/tabbar/doc.zh-TW.md b/src/packages/tabbar/doc.zh-TW.md index 6f6ad8b846..e71c880723 100644 --- a/src/packages/tabbar/doc.zh-TW.md +++ b/src/packages/tabbar/doc.zh-TW.md @@ -18,7 +18,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 自定義選中 +### 徽標提示 :::demo @@ -34,7 +34,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 無圖標 +### 只配文字 :::demo @@ -42,7 +42,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 徽標提示 +### 首坑品牌+營銷態 :::demo @@ -50,7 +50,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 紅點 +### 自定義顏色+數量 :::demo @@ -58,7 +58,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 自定義顏色 +### 受控 :::demo @@ -66,7 +66,7 @@ import { Tabbar } from '@nutui/nutui-react' ::: -### 可自定義icon個數的tabbar +### 焦點時點擊(模擬雙擊)支持回調 :::demo @@ -102,15 +102,16 @@ import { Tabbar } from '@nutui/nutui-react' | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | -| title | 標簽頁的標題 | `ReactNode` | `-` | -| icon | 自定義圖標 | `ReactNode` | `-` | -| value | 徽標中顯示的內容,支持數字、字符和自定義內容 | `ReactNode` | `-` | +| title | 標簽頁的標題 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| icon | 自定義圖標 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | +| value | 徽標中顯示的內容,支持數字、字符和自定義內容 | `ReactNode` \| `((active: boolean) => ReactNode)` | `-` | | max | value 為數值時,最大值 | `number` | `99` | | dot | 徽標是否為小點 | `boolean` | `false` | | top | 徽標的上下偏移量,支持單位設置,可設置為:5 等 | `number` | `0` | | right | 徽標的左右偏移量,支持單位設置,可設置為:5 等 | `number` | `0` | +| onActiveClick | 用於處理當元素處於焦點時,再次點擊時可增加自定義事件。 | `() => void` | `-` | -## 主題定制 +## 主題定製 ### 樣式變量 @@ -118,16 +119,16 @@ import { Tabbar } from '@nutui/nutui-react' | 名稱 | 說明 | 默認值 | | --- | --- | --- | -| \--nutui-tabbar-height | 高度 | `50px` | +| \--nutui-tabbar-height | 高度 | `46px` | | \--nutui-tabbar-active-color | 選中顏色 | `$color-primary` | | \--nutui-tabbar-inactive-color | 未選中顏色 | `$color-title` | | \--nutui-tabbar-border-top | 上邊框 | `1px solid #eee` | | \--nutui-tabbar-border-bottom | 下邊框 | `1px solid #eee` | | \--nutui-tabbar-box-shadow | 陰影 | `none` | -| \--nutui-tabbar-text-font-size | 標題字體大小 | `$font-size-xs` | +| \--nutui-tabbar-text-font-size | 標題字體大小 | `$font-size-xxs` | | \--nutui-tabbar-text-large-font-size | 無圖標時標題字體大小 | `$font-size-l` | | \--nutui-tabbar-text-large-font-weight | 無圖標時標題字體粗細 | `$font-weight` | | \--nutui-tabbar-text-line-height | 字體行高 | `initial` | -| \--nutui-tabbar-text-margin-top | 標題上外邊距 | `3px` | +| \--nutui-tabbar-text-margin-top | 標題上外邊距 | `4px` | diff --git a/src/packages/tabbar/tabbar.scss b/src/packages/tabbar/tabbar.scss index 0f6ccf769b..aed7942448 100644 --- a/src/packages/tabbar/tabbar.scss +++ b/src/packages/tabbar/tabbar.scss @@ -6,24 +6,40 @@ border-bottom: $tabbar-border-bottom; border-top: $tabbar-border-top; width: 100%; - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - box-sizing: border-box; background: $color-background-overlay; &-wrap { - width: 100%; height: $tabbar-height; display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - } - &:last-child { - border-right: 0; + &-3 { + padding: 0 16px; + } + + &-2 { + padding: 0 32px; + } + + &-horizontal { + align-items: center; + .nut-tabbar-item { + flex-direction: row; + justify-content: center; + .nut-icon { + width: 20px; + height: 20px; + } + .nut-tabbar-item-text { + margin: 0 4px 0 6px; + font-size: 14px; + } + .nut-badge-sup { + &::after { + border: 0; + } + } + } + } } &-fixed { @@ -31,13 +47,6 @@ bottom: 0px; left: 0px; } - - &-safe-area { - display: block; - width: 100%; - padding-bottom: constant(safe-area-inset-bottom); - padding-bottom: env(safe-area-inset-bottom); - } } [dir='rtl'] .nut-tabbar, diff --git a/src/packages/tabbar/tabbar.taro.tsx b/src/packages/tabbar/tabbar.taro.tsx index 9bbfb5171f..e310029453 100644 --- a/src/packages/tabbar/tabbar.taro.tsx +++ b/src/packages/tabbar/tabbar.taro.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent } from 'react' +import React, { FunctionComponent, useMemo } from 'react' import classNames from 'classnames' import { View } from '@tarojs/components' import { ComponentDefaults } from '@/utils/typings' @@ -6,6 +6,7 @@ import { usePropsValue } from '@/hooks/use-props-value' import TabbarItem from '../tabbaritem/index.taro' import TabbarContext from './context' import { TaroTabbarProps } from '@/types' +import SafeArea from '@/packages/safearea/index.taro' const defaultProps = { ...ComponentDefaults, @@ -13,8 +14,9 @@ const defaultProps = { fixed: false, inactiveColor: '', activeColor: '', + direction: 'vertical', safeArea: false, - onSwitch: (value) => {}, + onSwitch: () => {}, } as TaroTabbarProps export const Tabbar: FunctionComponent> & { @@ -27,14 +29,12 @@ export const Tabbar: FunctionComponent> & { fixed, activeColor, inactiveColor, + direction, safeArea, className, style, onSwitch, - } = { - ...defaultProps, - ...props, - } + } = { ...defaultProps, ...props } const classPrefix = 'nut-tabbar' const [selectIndex, setSelectIndex] = usePropsValue({ @@ -44,6 +44,23 @@ export const Tabbar: FunctionComponent> & { onChange: onSwitch, }) + const sizeCls = useMemo(() => { + const size = React.Children.count(children) + return size > 3 + ? '' + : classNames({ + [`${classPrefix}-wrap-3`]: size === 3, + [`${classPrefix}-wrap-2`]: size === 2, + [`${classPrefix}-wrap-${direction}`]: + size === 2 && direction !== 'vertical', + }) + }, [children, direction]) + + const itemDirection = useMemo(() => { + const size = React.Children.count(children) + return size === 2 && direction !== 'vertical' && direction + }, [direction, children]) + return ( > & { )} style={style} > - + > & { handleClick: setSelectIndex, }} > - {React.Children.map(children, (child, index) => { - if (!React.isValidElement(child)) return null - return React.cloneElement(child, { ...child.props, index }) - })} + {React.Children.map(children, (child, index) => + React.isValidElement(child) + ? React.cloneElement(child, { + ...child.props, + index, + direction: itemDirection, + }) + : null + )} - {(fixed || safeArea) && } + {(fixed || safeArea) && } ) } diff --git a/src/packages/tabbar/tabbar.tsx b/src/packages/tabbar/tabbar.tsx index 5be1dddebc..3651b8a017 100644 --- a/src/packages/tabbar/tabbar.tsx +++ b/src/packages/tabbar/tabbar.tsx @@ -1,10 +1,11 @@ -import React, { FunctionComponent } from 'react' +import React, { FunctionComponent, useMemo } from 'react' import classNames from 'classnames' import { ComponentDefaults } from '@/utils/typings' import { usePropsValue } from '@/hooks/use-props-value' import TabbarItem from '../tabbaritem' import TabbarContext from './context' import { WebTabbarProps } from '@/types' +import SafeArea from '@/packages/safearea/index' const defaultProps = { ...ComponentDefaults, @@ -12,8 +13,9 @@ const defaultProps = { fixed: false, inactiveColor: '', activeColor: '', + direction: 'vertical', safeArea: false, - onSwitch: (value) => {}, + onSwitch: () => {}, } as WebTabbarProps export const Tabbar: FunctionComponent> & { @@ -26,14 +28,13 @@ export const Tabbar: FunctionComponent> & { fixed, activeColor, inactiveColor, + direction, safeArea, className, style, onSwitch, - } = { - ...defaultProps, - ...props, - } + } = { ...defaultProps, ...props } + const classPrefix = 'nut-tabbar' const [selectIndex, setSelectIndex] = usePropsValue({ @@ -43,18 +44,33 @@ export const Tabbar: FunctionComponent> & { onChange: onSwitch, }) + const sizeCls = useMemo(() => { + const size = React.Children.count(children) + return size > 3 + ? '' + : classNames({ + [`${classPrefix}-wrap-3`]: size === 3, + [`${classPrefix}-wrap-2`]: size === 2, + [`${classPrefix}-wrap-${direction}`]: + size === 2 && direction !== 'vertical', + }) + }, [children, direction]) + + const itemDirection = useMemo(() => { + const size = React.Children.count(children) + return size === 2 && direction !== 'vertical' && direction + }, [direction, children]) + return (
-
+
> & { handleClick: setSelectIndex, }} > - {React.Children.map(children, (child, index) => { - if (!React.isValidElement(child)) return null - return React.cloneElement(child, { ...child.props, index }) - })} + {React.Children.map(children, (child, index) => + React.isValidElement(child) + ? React.cloneElement(child, { + ...child.props, + index, + direction: itemDirection, + }) + : null + )}
- {(fixed || safeArea) &&
} + {(fixed || safeArea) && }
) } diff --git a/src/packages/tabbaritem/tabbaritem.scss b/src/packages/tabbaritem/tabbaritem.scss index fcdec7da14..ccb308ffa5 100644 --- a/src/packages/tabbaritem/tabbaritem.scss +++ b/src/packages/tabbaritem/tabbaritem.scss @@ -3,45 +3,48 @@ .nut-tabbar-item { display: flex; flex-direction: column; - justify-content: center; align-items: center; flex: 1; - text-align: center; - text-decoration: none; + padding: 6px 0 2px; color: $tabbar-inactive-color; height: 100%; - &-icon-box { - padding: 0px; - display: flex; - flex-direction: column; - align-items: center; - position: relative; + .nut-icon { + width: 24px; + height: 24px; + font-size: 24px; + /* #ifdef harmony*/ + color: $tabbar-inactive-color; + /* #endif*/ + /* #ifndef harmony*/ + color: inherit; + /* #endif*/ + } - .nut-icon { - width: 22px; - height: 22px; - font-size: 22px; - /* #ifdef harmony*/ - color: $tabbar-inactive-color; - /* #endif*/ - /* #ifndef harmony*/ - color: inherit; - /* #endif*/ - } + &-text { + display: block; + color: $color-text; + font-size: $tabbar-text-font-size; + line-height: $tabbar-text-font-size; + margin-top: $tabbar-text-margin-top; + } - &-nav { - display: block; - color: $color-text; - font-size: $tabbar-text-font-size; - line-height: $tabbar-text-font-size; - margin-top: $tabbar-text-margin-top; + .nut-image { + &-default { + width: 38px; + height: 38px; + border-radius: 38px; } + } + + &-large { + justify-content: center; + padding: 0; - &-large { + .nut-tabbar-item-text { font-size: $tabbar-text-large-font-size; margin-top: 0; - line-height: $tabbar-text-line-height; + line-height: $tabbar-text-large-font-size; font-weight: $tabbar-text-large-font-weight; } } @@ -49,7 +52,7 @@ &-active { color: $tabbar-active-color; - .nut-tabbar-item-icon-box, + .nut-tabbar-item-text, .nut-icon { /* #ifdef harmony*/ color: $tabbar-active-color; diff --git a/src/packages/tabbaritem/tabbaritem.taro.tsx b/src/packages/tabbaritem/tabbaritem.taro.tsx index 5c66c57d1c..a4ad41806d 100644 --- a/src/packages/tabbaritem/tabbaritem.taro.tsx +++ b/src/packages/tabbaritem/tabbaritem.taro.tsx @@ -1,10 +1,9 @@ -import React, { FunctionComponent, useContext } from 'react' +import React, { FunctionComponent, useContext, ReactNode } from 'react' import classNames from 'classnames' import { View } from '@tarojs/components' import { ComponentDefaults } from '@/utils/typings' import Badge from '@/packages/badge/index.taro' import TabbarContext from '@/packages/tabbar/context' -import addColorForHarmony from '@/utils/add-color-for-harmony' import { TaroTabbarItemProps } from '@/types' const defaultProps = { @@ -16,6 +15,7 @@ const defaultProps = { max: 99, top: '0', right: '0', + direction: 'vertical', } as TaroTabbarItemProps export const TabbarItem: FunctionComponent> = ( @@ -34,6 +34,8 @@ export const TabbarItem: FunctionComponent> = ( right, // @ts-ignore index, + direction, + onActiveClick, ...rest } = { ...defaultProps, @@ -45,16 +47,18 @@ export const TabbarItem: FunctionComponent> = ( classPrefix, { [`${classPrefix}-active`]: active, + [`${classPrefix}-large`]: !icon || !title, }, className ) - const boxPrefix = `${classPrefix}-icon-box` - const titleClass = classNames(boxPrefix, `${boxPrefix}-nav`, { - [`${boxPrefix}-large`]: !icon, - }) + const renderNodeWithActive = ( + node: ReactNode | ((active: boolean) => ReactNode) + ) => { + return node && typeof node === 'function' ? node(active) : node + } const badgeProps = { - value, + value: renderNodeWithActive(value), dot, max, top, @@ -66,17 +70,57 @@ export const TabbarItem: FunctionComponent> = ( return ( title && ( - {title} + {renderNodeWithActive(title)} ) ) } + const renderTitle = () => { + return ( + + {renderTitleText()} + + ) + } + + const renderIcon = () => { + const distIcon = renderNodeWithActive(icon) + // 鸿蒙差异处理,需要手动给icon一个color + return React.isValidElement(distIcon) + ? React.cloneElement(distIcon, { + ...distIcon.props, + color: active ? ctx?.activeColor : ctx?.inactiveColor, + }) + : null + } + + const renderIconAndTitle = () => { + return ( + <> + + {renderIcon()} + + {renderTitleText()} + + ) + } + + const renderDualItem = () => { + return dot ? null : ( + <> + {renderIcon()} + {renderTitleText()} + + + ) + } + return ( > = ( color: active ? ctx?.activeColor : ctx?.inactiveColor, ...style, }} - onClick={() => ctx?.handleClick(index)} + onClick={() => (active ? onActiveClick?.() : ctx?.handleClick(index))} {...rest} > - {icon ? ( + {direction === 'horizontal' && !dot ? ( + renderDualItem() + ) : ( <> - - - {addColorForHarmony( - icon, - active ? ctx?.activeColor : ctx?.inactiveColor - )} - - - {renderTitleText()} + {icon && renderIconAndTitle()} + {!icon && renderTitle()} - ) : ( - {renderTitleText()} )} ) diff --git a/src/packages/tabbaritem/tabbaritem.tsx b/src/packages/tabbaritem/tabbaritem.tsx index bba38b14f7..c68bffce85 100644 --- a/src/packages/tabbaritem/tabbaritem.tsx +++ b/src/packages/tabbaritem/tabbaritem.tsx @@ -1,4 +1,4 @@ -import React, { FunctionComponent, useContext } from 'react' +import React, { FunctionComponent, useContext, ReactNode } from 'react' import classNames from 'classnames' import { ComponentDefaults } from '@/utils/typings' import Badge from '@/packages/badge/index' @@ -14,6 +14,7 @@ const defaultProps = { max: 99, top: '0', right: '0', + direction: 'vertical', } as WebTabbarItemProps export const TabbarItem: FunctionComponent> = ( @@ -32,6 +33,8 @@ export const TabbarItem: FunctionComponent> = ( right, // @ts-ignore index, + direction, + onActiveClick, ...rest } = { ...defaultProps, @@ -43,16 +46,19 @@ export const TabbarItem: FunctionComponent> = ( classPrefix, { [`${classPrefix}-active`]: active, + [`${classPrefix}-large`]: !icon || !title, }, className ) - const boxPrefix = `${classPrefix}-icon-box` - const titleClass = classNames(boxPrefix, `${boxPrefix}-nav`, { - [`${boxPrefix}-large`]: !icon, - }) + + const renderNodeWithActive = ( + node: ReactNode | ((active: boolean) => ReactNode) + ) => { + return node && typeof node === 'function' ? node(active) : node + } const badgeProps = { - value, + value: renderNodeWithActive(value), dot, max, top, @@ -61,7 +67,46 @@ export const TabbarItem: FunctionComponent> = ( } const renderTitleText = () => { - return title &&
{title}
+ return ( + title && ( +
+ {renderNodeWithActive(title)} +
+ ) + ) + } + + const renderTitle = () => { + return ( + + {renderTitleText()} + + ) + } + + const renderIcon = () => { + return renderNodeWithActive(icon) + } + + const renderIconAndTitle = () => { + return ( + <> + + {renderIcon()} + + {renderTitleText()} + + ) + } + + const renderDualItem = () => { + return dot ? null : ( + <> + {renderIcon()} + {renderTitleText()} + + + ) } return ( @@ -71,18 +116,16 @@ export const TabbarItem: FunctionComponent> = ( color: active ? ctx?.activeColor : ctx?.inactiveColor, ...style, }} - onClick={() => ctx?.handleClick(index)} + onClick={() => (active ? onActiveClick?.() : ctx?.handleClick(index))} {...rest} > - {icon ? ( + {direction === 'horizontal' && !dot ? ( + renderDualItem() + ) : ( <> - -
{icon}
-
- {renderTitleText()} + {icon && renderIconAndTitle()} + {!icon && renderTitle()} - ) : ( - {renderTitleText()} )}
) diff --git a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md index a9cdf02f2f..6ce2eca91c 100644 --- a/src/sites/sites-react/doc/docs/react/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/react/migrate-from-v2.md @@ -137,8 +137,13 @@ plugins: [ - 注意:** 该组件不符合移动端规范,已被废弃。请使用 SideBar ** -[//]: # '#### Tabbar' -[//]: # '#### TabbarItem' +#### Tabbar + +#### TabbarItem + +- 为 `icon`、`title` 和 `value` 增加新的类型,支持 `function` 根据当前是否 `active` 状态展示不同的 icon/title/value。 +- 增加 `onActiveClick` 事件,用于处理当元素处于焦点时,再次点击时可增加自定义事件。 + [//]: # '#### Tabs' [//]: # '#### Tabs.Tabpane' diff --git a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md index 4d673d5814..7be61352ac 100644 --- a/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md +++ b/src/sites/sites-react/doc/docs/taro/migrate-from-v2.md @@ -137,8 +137,13 @@ plugins: [ - 注意:** 该组件不符合移动端规范,已被废弃。请使用 SideBar ** -[//]: # '#### Tabbar' -[//]: # '#### TabbarItem' +#### Tabbar + +#### TabbarItem + +- 为 `icon`、`title` 和 `value` 增加新的类型,支持 `function` 根据当前是否 `active` 状态展示不同的 icon/title/value。 +- 增加 `onActiveClick` 事件,用于处理当元素处于焦点时,再次点击时可增加自定义事件。 + [//]: # '#### Tabs' [//]: # '#### Tabs.Tabpane' @@ -162,11 +167,7 @@ plugins: [ - 移除 `async`, 可通过 `beforeChange` 替代 - 增加 `beforeChange`, 处理异步调用 - [//]: # '#### NumberKeyboard' - [//]: # '#### Picker' - [//]: # '#### Radio' - [//]: # '### Radio.Group' - [//]: # '#### Range' + [//]: # '#### NumberKeyboard' [//]: # '#### Picker' [//]: # '#### Radio' diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 3276b5699d..79ad6da470 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1135,21 +1135,18 @@ $rate-font-color: var(--nutui-rate-font-color, $color-primary-icon) !default; $rate-font-size: var(--nutui-rate-font-size, 12px) !default; // tabbar(✅) -$tabbar-height: var(--nutui-tabbar-height, 50px) !default; +$tabbar-height: var(--nutui-tabbar-height, 46px) !default; $tabbar-active-color: var(--nutui-tabbar-active-color, $color-primary) !default; $tabbar-inactive-color: var( --nutui-tabbar-inactive-color, $color-title ) !default; -$tabbar-border-top: var(--nutui-tabbar-border-top, 1px solid #eee) !default; -$tabbar-border-bottom: var( - --nutui-tabbar-border-bottom, - 1px solid #eee -) !default; +$tabbar-border-top: var(--nutui-tabbar-border-top, 0) !default; +$tabbar-border-bottom: var(--nutui-tabbar-border-bottom, 0) !default; $tabbar-box-shadow: var(--nutui-tabbar-box-shadow, none) !default; $tabbar-text-font-size: var( --nutui-tabbar-text-font-size, - $font-size-xs + $font-size-xxs ) !default; $tabbar-text-large-font-size: var( --nutui-tabbar-text-large-font-size, @@ -1160,8 +1157,7 @@ $tabbar-text-large-font-weight: var( $font-weight ) !default; $tabbar-text-line-height: var(--nutui-tabbar-text-line-height, 20px) !default; -$tabbar-height: var(--nutui-tabbar-height, 50px) !default; -$tabbar-text-margin-top: var(--nutui-tabbar-text-margin-top, 3px) !default; +$tabbar-text-margin-top: var(--nutui-tabbar-text-margin-top, 4px) !default; //pulltorefresh $pulltorefresh-icon-width: var(--nutui-pulltorefresh-icon-width, 36px) !default; diff --git a/src/types/spec/tabbar/base.ts b/src/types/spec/tabbar/base.ts index 8eaca5fbb8..7f26ab20e2 100644 --- a/src/types/spec/tabbar/base.ts +++ b/src/types/spec/tabbar/base.ts @@ -1,5 +1,5 @@ import { ReactNode } from 'react' -import { BaseProps } from '../../base/props' +import { BaseProps, Direction } from '@/types' export interface BaseTabbar extends BaseProps { defaultValue: number @@ -7,16 +7,19 @@ export interface BaseTabbar extends BaseProps { fixed: boolean inactiveColor: string activeColor: string + direction: Direction safeArea: boolean onSwitch: (value: number) => void } export interface BaseTabbarItem extends BaseProps { - title: ReactNode - icon: ReactNode - value: ReactNode + title: ReactNode | ((active: boolean) => ReactNode) + icon: ReactNode | ((active: boolean) => ReactNode) + value: ReactNode | ((active: boolean) => ReactNode) dot: boolean max: number top: string right: string + direction: Direction + onActiveClick: () => void }