diff --git a/src/packages/navbar/demo.tsx b/src/packages/navbar/demo.tsx index 6436db05437ce41d56c51cd2685f09e987b06c1a..07bb11eaacc0d62e25bc91161ed0d4436bada51e 100644 --- a/src/packages/navbar/demo.tsx +++ b/src/packages/navbar/demo.tsx @@ -1,5 +1,8 @@ -import React from 'react' +import React, { useState } from 'react' import { NavBar } from './navbar' +import { Icon } from '../icon/icon' +import { Tabs } from '../tabs/tabs' +import { TabPane } from '../tabpane/tabpane' import { useTranslate } from '../../sites/assets/locale' interface T { @@ -11,6 +14,7 @@ interface T { cfbdc781: string c3a3a1d2: string e51e4582: string + c9e6df49: string } const NavBarDemo = () => { @@ -24,6 +28,7 @@ const NavBarDemo = () => { cfbdc781: '清空', c3a3a1d2: '购物车', e51e4582: '浏览记录', + c9e6df49: '自定义导航栏中间内容', }, 'zh-TW': { ce5c5446: '基礎用法', @@ -34,6 +39,7 @@ const NavBarDemo = () => { cfbdc781: '清空', c3a3a1d2: '購物車', e51e4582: '瀏覽記錄', + c9e6df49: '自定義導航欄中間內容', }, 'en-US': { ce5c5446: 'Basic usage', @@ -44,38 +50,76 @@ const NavBarDemo = () => { cfbdc781: 'empty', c3a3a1d2: 'shopping cart', e51e4582: 'Browsing history', + c9e6df49: 'Customize the middle content of the navigation bar', }, }) + const [tab1value, setTab1value] = useState('Tab 1') return ( <>

{translated.ce5c5446}

alert(translated.b840c88f)} onClickBack={(e) => alert(translated.a74a1fd4)} - onClickIcon={(e) => alert('icon')} - /> + onClickRight={(e) => alert('icon')} + > + + alert(translated.b840c88f)} onClickBack={(e) => alert(translated.a74a1fd4)} - onClickClear={(e) => alert(translated.cfbdc781)} + onClickRight={(e) => alert(translated.cfbdc781)} /> alert(translated.b840c88f)} + onClickRight={(e) => alert(translated['8dab2f66'])} onClickBack={(e) => alert(translated.a74a1fd4)} - onClickClear={(e) => alert(translated['8dab2f66'])} onClickIcon={(e) => alert('icon')} - /> + > + + + alert(translated.b840c88f)} + onClickBack={(e) => alert(translated.a74a1fd4)} + onClickRight={(e) => alert('icon')} + > + + +

{translated.c9e6df49}

+ alert(translated.b840c88f)} + onClickRight={(e) => alert(translated['8dab2f66'])} + onClickBack={(e) => alert(translated.a74a1fd4)} + onClickIcon={(e) => alert('icon')} + > +
+ { + setTab1value(paneKey) + }} + > + Tab 1 + Tab 2 + Tab 3 + +
+ +
) diff --git a/src/packages/navbar/doc.en-US.md b/src/packages/navbar/doc.en-US.md index a84982089406e529ed0e4f5e0581e3e0b6d6eecf..ecb016053da972f18a93f81c359f823e8d0d083a 100644 --- a/src/packages/navbar/doc.en-US.md +++ b/src/packages/navbar/doc.en-US.md @@ -15,6 +15,32 @@ import { NavBar } from '@nutui/nutui-react'; ### Basic usage +:::demo +```tsx +import React from "react"; +import { NavBar, Icon } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + alert("back")} + onClickBack={(e) => alert("title")} + onClickRight={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + :::demo ```tsx import React from "react"; @@ -23,14 +49,14 @@ import { NavBar } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('title')} - onClickBack={(e) => alert('back')} - onClickIcon={(e) => alert('icon')} - /> + alert("back")} + onClickBack={(e) => alert("title")} + onClickRight={(e) => alert('clear')} + /> ); }; @@ -42,19 +68,22 @@ export default App; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('title')} - onClickBack={(e) => alert('back')} - onClickClear={(e) => alert('clear')} - /> + alert("back")} + onClickBack={(e) => alert("title")} + onClickRight={(e) => alert('edit')} + onClickIcon={(e) => alert('icon')} + > + + ); }; @@ -66,21 +95,58 @@ export default App; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; const App = () => { + return ( + <> + alert("back")} + onClickBack={(e) => alert("title")} + onClickRight={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + + +### Customize the middle content of the navigation bar + +:::demo +```tsx +import React, { useState } from "react"; +import { NavBar, Icon, Tabs, TabPane } from '@nutui/nutui-react'; + +const App = () => { + const [tab1value, setTab1value] = useState('Tab 1') return ( <> - alert('title')} - onClickBack={(e) => alert('back')} - onClickClear={(e) => alert('edit')} - onClickIcon={(e) => alert('icon')} - /> + alert("title")} + onClickRight={(e) => alert("edit")} + onClickBack={(e) => alert("back")} + onClickIcon={(e) => alert('icon')} + > +
+ { setTab1value(paneKey) }}> + Tab 1 + Tab 2 + Tab 3 + +
+ +
); }; @@ -95,14 +161,22 @@ export default App; |-----------------|------------------------------------------------------------------------------------------------|---------|---------| | title | title name | String | - | | desc | Description on the right | String | - | -| leftShow | Whether to show the left arrow | Boolean | false | -| icon | Left [icon name](#/icon) or image link | String | - | -| titIcon | title with icon | String | - | +| leftShow | Whether to show the left arrow | Boolean | true | +| titIcon | title with icon | String | - | +| leftText | copy on the left | String | - | +| fixed | Is it fixed | Boolean | false | +| safeAreaInsetTop | Whether it is suitable for the safe area | Boolean | false | +| border | whether to show the bottom border | Boolean | false | +| placeholder | When fixed to the top, whether to generate a placeholder element of equal height at the label position | Boolean | false | +| zIndex | Navigation Bar Hierarchy | Number、String | 10 | +| style | container style | React.CSSProperties | {} | +| className | container class name | String | "" | ### Event + | Event | Description | callback parameter | |-------|----------|-------------| -| onClickTitle | Click page title event | event:Event | -| onClickClear | Click on the copy event on the right | event:Event | -| onClickBack | Click to return to previous page of events | event:Event | -| onClickIcon | Click the right icon event | event:Event | \ No newline at end of file +| onClickTitle | click title event | event:Event | +| onClickRight | Click on the event on the right | event:Event | +| onClickBack | click back event | event:Event | +| onClickIcon | Click the icon event on the right side of the title | event:Event | \ No newline at end of file diff --git a/src/packages/navbar/doc.md b/src/packages/navbar/doc.md index 98768f333940bb8ea1e2808f57197a2058cc1792..6d3af784b05e3a1f1ac8f00d38189d48d4b5cdb2 100644 --- a/src/packages/navbar/doc.md +++ b/src/packages/navbar/doc.md @@ -18,19 +18,21 @@ import { NavBar } from '@nutui/nutui-react'; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('标题')} - onClickBack={(e) => alert('返回')} - onClickIcon={(e) => alert('icon')} - /> + alert("返回")} + onClickBack={(e) => alert("标题")} + onClickRight={(e) => alert('icon')} + > + + ); }; @@ -47,14 +49,14 @@ import { NavBar } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('标题')} - onClickBack={(e) => alert('返回')} - onClickClear={(e) => alert('清空')} - /> + alert("返回")} + onClickBack={(e) => alert("标题")} + onClickRight={(e) => alert('清空')} + /> ); }; @@ -66,21 +68,85 @@ export default App; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + alert("返回")} + onClickBack={(e) => alert("标题")} + onClickRight={(e) => alert('编辑')} + onClickIcon={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + +:::demo +```tsx +import React from "react"; +import { NavBar, Icon } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + alert("返回")} + onClickBack={(e) => alert("标题")} + onClickRight={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + + +### 自定义导航栏中间内容 + +:::demo +```tsx +import React, { useState } from "react"; +import { NavBar, Icon, Tabs, TabPane } from '@nutui/nutui-react'; const App = () => { + const [tab1value, setTab1value] = useState('Tab 1') return ( <> - alert('标题')} - onClickBack={(e) => alert('返回')} - onClickClear={(e) => alert('编辑')} - onClickIcon={(e) => alert('icon')} - /> + alert("标题")} + onClickRight={(e) => alert("编辑")} + onClickBack={(e) => alert("返回")} + onClickIcon={(e) => alert('icon')} + > +
+ { setTab1value(paneKey) }}> + Tab 1 + Tab 2 + Tab 3 + +
+ +
); }; @@ -95,14 +161,21 @@ export default App; |-----------------|------------------------------------------------------------------------------------------------|---------|---------| | title | 标题名称 | String | - | | desc | 右侧描述 | String | - | -| leftShow | 是否展示左侧箭头 | Boolean | false | -| icon | 左侧 [图标名称](#/icon) 或图片链接 | String | - | -| titIcon | 标题带icon | String | - | +| leftShow | 是否展示左侧箭头 | Boolean | true | +| titIcon | 标题带icon | String | - | +| leftText | 左侧文案 | String | - | +| fixed | 是否固定 | Boolean | false | +| safeAreaInsetTop | 是否适配安全区 | Boolean | false | +| border | 是否显示底部边框 | Boolean | false | +| placeholder | 固定在顶部时,是否在标签位置生成一个等高的占位元素 | Boolean | false | +| zIndex | 导航栏层级 | Number、String | 10 | +| style | 容器样式 | React.CSSProperties | {} | +| className | 容器类名 | String | "" | ### Event | 名称 | 说明 | 回调参数 | |-------|----------|-------------| -| onClickTitle | 点击页面标题事件 | event:Event | -| onClickClear | 点击右侧文案事件 | event:Event | -| onClickBack | 点击返回上一页事件 | event:Event | -| onClickIcon | 点击右侧icon事件 | event:Event | \ No newline at end of file +| onClickTitle | 点击标题事件 | event:Event | +| onClickRight | 点击右侧事件 | event:Event | +| onClickBack | 点击返回事件 | event:Event | +| onClickIcon | 点击标题右侧icon事件 | event:Event | \ No newline at end of file diff --git a/src/packages/navbar/doc.zh-TW.md b/src/packages/navbar/doc.zh-TW.md index a9cdff3317f1f371d9bc5f66f7de1cacc0673652..67adb0433ea9469beb3c6b0ad6b60c71e33a3862 100644 --- a/src/packages/navbar/doc.zh-TW.md +++ b/src/packages/navbar/doc.zh-TW.md @@ -18,19 +18,21 @@ import { NavBar } from '@nutui/nutui-react'; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('標題')} - onClickBack={(e) => alert('返回')} - onClickIcon={(e) => alert('icon')} - /> + alert("返回")} + onClickBack={(e) => alert("標題")} + onClickRight={(e) => alert('icon')} + > + + ); }; @@ -47,14 +49,14 @@ import { NavBar } from '@nutui/nutui-react'; const App = () => { return ( <> - alert('標題')} - onClickBack={(e) => alert('返回')} - onClickClear={(e) => alert('清空')} - /> + alert("返回")} + onClickBack={(e) => alert("標題")} + onClickRight={(e) => alert('清空')} + /> ); }; @@ -66,21 +68,85 @@ export default App; :::demo ```tsx import React from "react"; -import { NavBar } from '@nutui/nutui-react'; +import { NavBar, Icon } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + alert("返回")} + onClickBack={(e) => alert("標題")} + onClickRight={(e) => alert('編輯')} + onClickIcon={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + +:::demo +```tsx +import React from "react"; +import { NavBar, Icon } from '@nutui/nutui-react'; + +const App = () => { + return ( + <> + alert("返回")} + onClickBack={(e) => alert("標題")} + onClickRight={(e) => alert('icon')} + > + + + + ); +}; +export default App; + +``` +::: + + +### 自定義導航欄中間內容 + +:::demo +```tsx +import React, { useState } from "react"; +import { NavBar, Icon, Tabs, TabPane } from '@nutui/nutui-react'; const App = () => { + const [tab1value, setTab1value] = useState('Tab 1') return ( <> - alert('標題')} - onClickBack={(e) => alert('返回')} - onClickClear={(e) => alert('編輯')} - onClickIcon={(e) => alert('icon')} - /> + alert("標題")} + onClickRight={(e) => alert("編輯")} + onClickBack={(e) => alert("返回")} + onClickIcon={(e) => alert('icon')} + > +
+ { setTab1value(paneKey) }}> + Tab 1 + Tab 2 + Tab 3 + +
+ +
); }; @@ -95,14 +161,21 @@ export default App; |-----------------|------------------------------------------------------------------------------------------------|---------|---------| | title | 標題名稱 | String | - | | desc | 右側描述 | String | - | -| leftShow | 是否展示左側箭頭 | Boolean | false | -| icon | 左側 [圖標名稱](#/icon) 或圖片鏈接 | String | - | -| titIcon | 標題帶icon | String | - | +| leftShow | 是否展示左側箭頭 | Boolean | true | +| titIcon | 標題帶icon | String | - | +| leftText | 左側文案 | String | - | +| fixed | 是否固定 | Boolean | false | +| safeAreaInsetTop | 是否適配安全區 | Boolean | false | +| border | 是否顯示底部邊框 | Boolean | false | +| placeholder | 固定在頂部時,是否在標籤位置生成一個等高的佔位元素 | Boolean | false | +| zIndex | 導航欄層級 | Number、String | 10 | +| style | 容器樣式 | React.CSSProperties | {} | +| className | 容器類名 | String | "" | ### Event | 名稱 | 說明 | 回調參數 | |-------|----------|-------------| -| onClickTitle | 點擊頁面標題事件 | event:Event | -| onClickClear | 點擊右側文案事件 | event:Event | -| onClickBack | 點擊返回上一頁事件 | event:Event | -| onClickIcon | 點擊右側icon事件 | event:Event | \ No newline at end of file +| onClickTitle | 點擊標題事件 | event:Event | +| onClickRight | 點擊右側事件 | event:Event | +| onClickBack | 點擊返回事件 | event:Event | +| onClickIcon | 點擊標題右側icon事件 | event:Event | \ No newline at end of file diff --git a/src/packages/navbar/navbar.scss b/src/packages/navbar/navbar.scss index 8e158a8cff12ad3fa80c02f0ecb1b72fba3bee69..44398ca29a9d5fcedbcb5bc065a14df57aa9aeab 100644 --- a/src/packages/navbar/navbar.scss +++ b/src/packages/navbar/navbar.scss @@ -1,40 +1,132 @@ -@import '../icon/icon.scss'; - .nut-navbar { position: relative; display: flex; - justify-content: space-around; align-items: center; - height: 44px; - padding: 13px 16px; - background: #fff; - box-shadow: 0 1px 7px 0 #edeef1; - font-size: 14px; - color: #666; - margin-bottom: 20px; - &__back { - padding: 0 16px; - &:before { - content: '\e673'; + height: $navbar-height; + box-sizing: border-box; + padding: $navbar-padding; + background: $navbar-background; + box-shadow: $navbar-box-shadow; + font-size: $navbar-title-base-font; + color: $navbar-color; + margin-bottom: $navbar-margin-bottom; + overflow: hidden; + &:active::before { + opacity: 0.1; + } + &--border { + border-bottom: 1px solid #eee; + } + &--fixed { + position: fixed; + top: 0; + left: 0; + width: 100%; + } + &--placeholder { + display: inline-block; + width: 100%; + } + &--safe-area-inset-top { + padding-top: constant(safe-area-inset-top); + padding-top: env(safe-area-inset-top); + } + &--clickable { + &::before { position: absolute; + content: ' '; top: 50%; left: 50%; + width: 100%; + height: 100%; + background-color: $black; + border: inherit; + border-color: $black; + border-radius: inherit; transform: translate(-50%, -50%); + opacity: 0; } } - &__icon { - display: flex; - margin-left: 16px; - .nut-icon:before { - max-width: 100%; + + .nutui-iconfont { + .nut-icon-left { + text-align: left; } } + &__title { - flex: 1; + min-width: 53%; + margin: 0 auto; text-align: center; + display: flex; + align-items: center; + justify-content: center; + .title { + min-width: $navbar-title-width; + font-size: $navbar-title-font; + font-weight: $navbar-title-font-weight; + color: $navbar-title-font-color; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 1; + overflow: hidden; + } + &.icon { + .icon { + margin: $navbar-title-icon-margin; + } + } .nut-icon { - vertical-align: middle; - margin-top: -2px; + display: inline; + } + &-desc { + font-size: $cell-title-desc-font; + } + .text__title { + display: inline-block; + } + + .nut-tabs__titles { + background: $white; + } + + .nut-tabpane { + display: none; + } + } + + &__title ::-webkit-scrollbar { + display: none; + } + + &__left { + font-size: $cell-desc-font; + color: $cell-desc-color; + position: absolute; + left: 0; + top: 0; + bottom: 0; + display: flex; + align-items: center; + cursor: pointer; + padding: 0 16px; + } + &__right { + font-size: $cell-desc-font; + color: $cell-desc-color; + position: absolute; + right: 0; + top: 0; + bottom: 0; + display: flex; + align-items: center; + padding: 0 16px; + cursor: pointer; + .rightIcon { + margin-left: 16px; + } + .leftIcon { + margin-left: 16px; } } } diff --git a/src/packages/navbar/navbar.tsx b/src/packages/navbar/navbar.tsx index 5423ba9533e99e46f54ddbd776805dc77d6b6a68..ff444fdc5edec03e12befa697d82169a6212ebd4 100644 --- a/src/packages/navbar/navbar.tsx +++ b/src/packages/navbar/navbar.tsx @@ -1,67 +1,146 @@ import React, { FunctionComponent } from 'react' +import classNames from 'classnames' import Icon from '@/packages/icon' import bem from '@/utils/bem' export interface NavBarProps { - title: string - desc: string leftShow: boolean - icon: string + title: string titIcon: string + leftText: string + desc: string className: string + fixed: boolean + safeAreaInsetTop: boolean + border: boolean + placeholder: boolean + zIndex: number | string style: React.CSSProperties onClickTitle: (e: React.MouseEvent) => void onClickIcon: (e: React.MouseEvent) => void onClickBack: (e: React.MouseEvent) => void - onClickClear: (e: React.MouseEvent) => void + onClickRight: (e: React.MouseEvent) => void } const defaultProps = { title: '', desc: '', - leftShow: false, - icon: '', + leftShow: true, titIcon: '', className: '', + leftText: '', + fixed: false, + safeAreaInsetTop: false, + border: false, + placeholder: false, + zIndex: 10, + style: {}, } as NavBarProps export const NavBar: FunctionComponent> = (props) => { const { desc, - icon, title, titIcon, leftShow, className, style, + leftText, + fixed, + safeAreaInsetTop, + border, + placeholder, + zIndex, onClickTitle, onClickIcon, onClickBack, - onClickClear, + onClickRight, } = { ...defaultProps, ...props, } const b = bem('navbar') - return ( -
- {leftShow && ( - onClickBack(e)} - /> - )} -
onClickTitle(e)}> - {title} - {titIcon && } + + const children = Array.isArray(props.children) + ? props.children + : [props.children] + + const slot = children.reduce((slot: any, item: React.ReactElement) => { + const data = slot + if (item && item.props) { + data[item.props.slot] = item + } + return data + }, {}) + + const styles = () => { + return { + ...style, + zIndex, + } + } + + const renderLeft = () => { + return ( +
onClickBack(e)}> + {leftShow && } + {leftText &&
{leftText}
} + {slot.left} +
+ ) + } + + const renderContent = () => { + return ( +
+ {title && ( +
onClickTitle(e)}> + {title} +
+ )} + {titIcon && ( +
onClickIcon(e)}> + +
+ )} + {slot.content} +
+ ) + } + + const renderRight = () => { + return ( +
onClickRight(e)}> + {desc &&
{desc}
} + {slot.right}
-
onClickClear(e)}> - {desc} + ) + } + + const renderWrapper = () => { + return ( +
+ {renderLeft()} + {renderContent()} + {renderRight()}
- {icon && ( -
onClickIcon(e)}> - -
+ ) + } + + const classes = classNames({ + [`nut-navbar--border`]: border, + [`nut-navbar--fixed`]: fixed, + [`nut-navbar--safe-area-inset-top`]: safeAreaInsetTop, + }) + + const cls = classNames(b(''), classes, className) + + return ( + <> + {fixed && placeholder ? ( +
{renderWrapper()}
+ ) : ( + renderWrapper() )} -
+ ) } diff --git a/src/styles/variables.scss b/src/styles/variables.scss index b3cd80ede3dd542f6f81880277b74128a470b74b..05487002a289e8d356b0dd8505ffe952b98dd9d2 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -477,6 +477,20 @@ $divider-vertical-top: 2px !default; $divider-vertical-border-left: rgba(0, 0, 0, 0.06) !default; $divider-vertical-margin: 0 8px !default; +//navbar +$navbar-height: 44px !default; +$navbar-margin-bottom: 20px !default; +$navbar-padding: 13px 16px !default; +$navbar-background: $white !default; +$navbar-box-shadow: 0px 1px 7px 0px rgba(237, 238, 241, 1) !default; +$navbar-color: $title-color2 !default; +$navbar-title-base-font: $font-size-2 !default; +$navbar-title-font: $font-size-2 !default; +$navbar-title-font-weight: 0 !default; +$navbar-title-font-color: $navbar-color !default; +$navbar-title-width: 100px !default; +$navbar-title-icon-margin: 0 0 0 13px !default; + // layout $row-content-color: #fff !default; $row-content-background-color: #ff8881 !default;