From 9de31224184f2efad04cbe04b52e8a4126bdec20 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Mon, 16 Dec 2024 20:29:09 +0800
Subject: [PATCH 01/14] chore: save my content
---
src/config.json | 12 +
src/packages/sidebar/demo.tsx | 50 ++++
src/packages/sidebar/demos/h5/demo1.tsx | 25 ++
src/packages/sidebar/demos/h5/demo2.tsx | 22 ++
src/packages/sidebar/demos/h5/demo3.tsx | 28 +++
src/packages/sidebar/demos/h5/demo4.tsx | 50 ++++
src/packages/sidebar/demos/h5/demo5.tsx | 26 ++
src/packages/sidebar/demos/h5/demo6.tsx | 47 ++++
src/packages/sidebar/doc.en-US.md | 80 +++++++
src/packages/sidebar/doc.md | 72 ++++++
src/packages/sidebar/doc.taro.md | 84 +++++++
src/packages/sidebar/doc.zh-TW.md | 80 +++++++
src/packages/sidebar/index.taro.ts | 4 +
src/packages/sidebar/index.ts | 4 +
src/packages/sidebar/sidebar.scss | 131 ++++++++++
src/packages/sidebar/sidebar.taro.tsx | 83 +++++++
src/packages/sidebar/sidebar.tsx | 225 ++++++++++++++++++
src/packages/sidebar/utils.ts | 22 ++
src/packages/sidebaritem/index.taro.ts | 4 +
src/packages/sidebaritem/index.ts | 4 +
src/packages/sidebaritem/sidebaritem.scss | 16 ++
src/packages/sidebaritem/sidebaritem.taro.tsx | 44 ++++
src/packages/sidebaritem/sidebaritem.tsx | 43 ++++
23 files changed, 1156 insertions(+)
create mode 100644 src/packages/sidebar/demo.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo1.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo2.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo3.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo4.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo5.tsx
create mode 100644 src/packages/sidebar/demos/h5/demo6.tsx
create mode 100644 src/packages/sidebar/doc.en-US.md
create mode 100644 src/packages/sidebar/doc.md
create mode 100644 src/packages/sidebar/doc.taro.md
create mode 100644 src/packages/sidebar/doc.zh-TW.md
create mode 100644 src/packages/sidebar/index.taro.ts
create mode 100644 src/packages/sidebar/index.ts
create mode 100644 src/packages/sidebar/sidebar.scss
create mode 100644 src/packages/sidebar/sidebar.taro.tsx
create mode 100644 src/packages/sidebar/sidebar.tsx
create mode 100644 src/packages/sidebar/utils.ts
create mode 100644 src/packages/sidebaritem/index.taro.ts
create mode 100644 src/packages/sidebaritem/index.ts
create mode 100644 src/packages/sidebaritem/sidebaritem.scss
create mode 100644 src/packages/sidebaritem/sidebaritem.taro.tsx
create mode 100644 src/packages/sidebaritem/sidebaritem.tsx
diff --git a/src/config.json b/src/config.json
index e1ff16c552..cd63da9a4f 100644
--- a/src/config.json
+++ b/src/config.json
@@ -343,6 +343,18 @@
"taro": true,
"author": "hx"
},
+ {
+ "version": "2.0.0",
+ "name": "SideBar",
+ "type": "component",
+ "cName": "侧边栏导航",
+ "desc": "用于内容选择和切换",
+ "sort": 10,
+ "show": true,
+ "taro": true,
+ "author": "Alex.hxy",
+ "v15": true
+ },
{
"version": "2.0.0",
"name": "SideNavBarItem",
diff --git a/src/packages/sidebar/demo.tsx b/src/packages/sidebar/demo.tsx
new file mode 100644
index 0000000000..b1ee3224e4
--- /dev/null
+++ b/src/packages/sidebar/demo.tsx
@@ -0,0 +1,50 @@
+import React from 'react'
+import { useTranslate } from '@/sites/assets/locale'
+import Demo1 from './demos/h5/demo1'
+import Demo2 from './demos/h5/demo2'
+import Demo3 from './demos/h5/demo3'
+import Demo4 from './demos/h5/demo4'
+import Demo5 from './demos/h5/demo5'
+import Demo6 from './demos/h5/demo6'
+
+const SideNavBarDemo = () => {
+ const [translated] = useTranslate({
+ 'zh-CN': {
+ basic: '基础用法',
+ disabled: '禁用选项',
+ matchByValue: '根据value匹配',
+ multiTitle: '多个标题',
+ setDuration: '设置滚动动画时长',
+ swtchOnEnd: '滚动底部时自动切换 ',
+ },
+ 'en-US': {
+ basic: 'Basic Usage',
+ disabled: 'Disabled',
+ matchByValue: 'Match By Value',
+ multiTitle: 'Multiple Titles',
+ setDuration: 'Set Scroll Animation Duration',
+ swtchOnEnd: 'Switch On End',
+ },
+ })
+
+ return (
+ <>
+
+
{translated.basic}
+
+ {translated.disabled}
+
+ {translated.matchByValue}
+
+ {translated.multiTitle}
+
+ {translated.setDuration}
+
+ {translated.swtchOnEnd}
+
+
+ >
+ )
+}
+
+export default SideNavBarDemo
diff --git a/src/packages/sidebar/demos/h5/demo1.tsx b/src/packages/sidebar/demos/h5/demo1.tsx
new file mode 100644
index 0000000000..e748cdc696
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo1.tsx
@@ -0,0 +1,25 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react'
+
+const Demo1 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ >
+ )
+}
+export default Demo1
diff --git a/src/packages/sidebar/demos/h5/demo2.tsx b/src/packages/sidebar/demos/h5/demo2.tsx
new file mode 100644
index 0000000000..245fbc385d
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo2.tsx
@@ -0,0 +1,22 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react'
+
+const Demo2 = () => {
+ const [value, setValue] = useState('0')
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ Content 1
+ Content 2
+
+
+ >
+ )
+}
+export default Demo2
diff --git a/src/packages/sidebar/demos/h5/demo3.tsx b/src/packages/sidebar/demos/h5/demo3.tsx
new file mode 100644
index 0000000000..7147345faf
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo3.tsx
@@ -0,0 +1,28 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react'
+
+const Demo2 = () => {
+ const [value, setValue] = useState('b')
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+
+ Content 1
+
+
+ Content 2
+
+
+ Content 3
+
+
+ >
+ )
+}
+export default Demo2
diff --git a/src/packages/sidebar/demos/h5/demo4.tsx b/src/packages/sidebar/demos/h5/demo4.tsx
new file mode 100644
index 0000000000..faa46b6333
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo4.tsx
@@ -0,0 +1,50 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react'
+
+const Demo4 = () => {
+ const [value, setValue] = useState(1)
+ const list = [
+ {
+ title: 'Option 1',
+ value: 1,
+ },
+ {
+ title: 'Option 2',
+ value: 2,
+ },
+ {
+ title: 'Option 3',
+ value: 3,
+ },
+ {
+ title: 'Option 4',
+ value: 4,
+ },
+ {
+ title: 'Option 5',
+ value: 5,
+ },
+ {
+ title: 'Option 6',
+ value: 6,
+ },
+ ]
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item.value}
+
+ ))}
+
+ >
+ )
+}
+export default Demo4
diff --git a/src/packages/sidebar/demos/h5/demo5.tsx b/src/packages/sidebar/demos/h5/demo5.tsx
new file mode 100644
index 0000000000..7d37049230
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo5.tsx
@@ -0,0 +1,26 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react'
+
+const Demo5 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ >
+ )
+}
+export default Demo5
diff --git a/src/packages/sidebar/demos/h5/demo6.tsx b/src/packages/sidebar/demos/h5/demo6.tsx
new file mode 100644
index 0000000000..40eaebd2e1
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo6.tsx
@@ -0,0 +1,47 @@
+import React, { useState } from 'react'
+import { SideBar, Space } from '@nutui/nutui-react'
+
+const Demo6 = () => {
+ function generateRandomStr(n: number) {
+ const words = []
+ const alphabet = 'abcdefghijklmnopqrstuvwxyz'
+ function getRandomInt(min: number, max: number) {
+ return Math.floor(Math.random() * (max - min + 1)) + min
+ }
+ for (let i = 0; i < n; i++) {
+ const wordLength = getRandomInt(3, 10)
+ let word = ''
+ for (let j = 0; j < wordLength; j++) {
+ const randomIndex = getRandomInt(0, alphabet.length - 1)
+ word += alphabet[randomIndex]
+ }
+ words.push(word)
+ }
+ const sentence = `${words.join(' ')}.`
+ return sentence.charAt(0).toUpperCase() + sentence.slice(1)
+ }
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+
+ {generateRandomStr(30)}
+ {generateRandomStr(30)}
+
+
+ ))}
+
+ >
+ )
+}
+export default Demo6
diff --git a/src/packages/sidebar/doc.en-US.md b/src/packages/sidebar/doc.en-US.md
new file mode 100644
index 0000000000..64af02c249
--- /dev/null
+++ b/src/packages/sidebar/doc.en-US.md
@@ -0,0 +1,80 @@
+# SideNavBar组件
+
+For content selection and switching
+
+## Import
+
+```tsx
+import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+```
+
+## Demo
+
+### Basic Usage
+
+:::demo
+
+
+
+:::
+
+### Navigation Nesting (Up To Three Levels Recommended)
+
+:::demo
+
+
+
+:::
+
+## SideNavBar
+
+### Props
+
+| Property | Description | Type | Default |
+| --- | --- | --- | --- |
+| visible | whether the component is visible | `boolean` | `false` |
+| title | overall title | `string` | `-` |
+| width | mask width in percentage | `string` | `80%` |
+| position | popup position | `left` \| `right` | `left` |
+| indent | indent width | `number` | `20` |
+| onClose | Triggered when the mask is closed | `-` | `-` |
+
+## SubSideNavBar
+
+### Props
+
+| Property | Description | Type | Default |
+| --- | --- | --- | --- |
+| value | unique identifier for navigation | `string` \| `number` | `-` |
+| title | overall title | `string` | `-` |
+| open | whether the navigation is expanded by default | `boolean` | `true` |
+| onClick | Navigation click | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+
+## SideNavBarItem
+
+### Props
+
+| Property | Description | Type | Default |
+| --- | --- | --- | --- |
+| value | unique identifier for navigation | `string` \| `number` | `-` |
+| title | overall title | `string` | `-` |
+| onClick | Navigation click | `({title: string, value: string \| number}) => void` | `-` |
+
+## Theming
+
+### CSS Variables
+
+The component provides the following CSS variables, which can be used to customize styles. Please refer to [ConfigProvider component](#/en-US/component/configprovider).
+
+| Name | Description | Default |
+| --- | --- | --- |
+| \--nutui-sidenavbar-content-bg-color | sidebar navigation background color | `$white` |
+| \--nutui-sidenavbar-item-height | The height of each item in the sidebar | `40px` |
+| \--nutui-sidenavbar-title-padding | padding for title | `10px 8px 10px 20px` |
+| \--nutui-sidenavbar-title-background | The background color of the title | `$color-background` |
+| \--nutui-sidenavbar-title-color | The font color of the title | `$color-title` |
+| \--nutui-sidenavbar-sub-title-padding | Padding of subtitle | `10px 8px 10px 35px` |
+| \--nutui-sidenavbar-sub-title-background | Subtitle background color | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-title-color | Subtitle font color | `$color-title` |
+| \--nutui-sidenavbar-sub-list-background | option list background color | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-list-color | option list font color | `$color-title` |
diff --git a/src/packages/sidebar/doc.md b/src/packages/sidebar/doc.md
new file mode 100644
index 0000000000..98135b2e7d
--- /dev/null
+++ b/src/packages/sidebar/doc.md
@@ -0,0 +1,72 @@
+# SideNavBar组件
+
+用于内容选择和切换
+
+## 引入
+
+```tsx
+import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+```
+
+## 示例代码
+
+### 基础用法
+
+:::demo
+
+
+
+:::
+
+## SideNavBar
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| visible | 组件是否显示 | `boolean` | `false` |
+| title | 整体标题 | `string` | `-` |
+| width | 遮罩宽度百分比 | `string` | `80%` |
+| position | 弹出位置 | `left` \| `right` | `left` |
+| indent | 缩进宽度 | `number` | `20` |
+| onClose | 关闭遮罩时触发 | `-` | `-` |
+
+## SubSideNavBar
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| value | 导航唯一标识 | `string` \| `number` | `-` |
+| title | 整体标题 | `string` | `-` |
+| open | 导航是否默认展开 | `boolean` | `true` |
+| onClick | 导航点击 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+
+## SideNavBarItem
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| value | 导航唯一标识 | `string` \| `number` | `-` |
+| title | 整体标题 | `string` | `-` |
+| onClick | 导航点击 | `({title: string, value: string \| number}) => void` | `-` |
+
+## 主题定制
+
+### 样式变量
+
+组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/component/configprovider)。
+
+| 名称 | 说明 | 默认值 |
+| --- | --- | --- |
+| \--nutui-sidenavbar-content-bg-color | 侧边栏导航背景色 | `$white` |
+| \--nutui-sidenavbar-item-height | 侧边栏每项的高度 | `40px` |
+| \--nutui-sidenavbar-title-padding | 标题的内边距 | `10px 8px 10px 20px` |
+| \--nutui-sidenavbar-title-background | 标题的背景色 | `$color-background` |
+| \--nutui-sidenavbar-title-color | 标题的字体颜色 | `$color-title` |
+| \--nutui-sidenavbar-sub-title-padding | 子标题的内边距 | `10px 8px 10px 35px` |
+| \--nutui-sidenavbar-sub-title-background | 子标题背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-title-color | 子标题字体颜色 | `$color-title` |
+| \--nutui-sidenavbar-sub-list-background | 选项列表背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-list-color | 选项列表字体颜色 | `$color-title` |
diff --git a/src/packages/sidebar/doc.taro.md b/src/packages/sidebar/doc.taro.md
new file mode 100644
index 0000000000..1db5ec19e3
--- /dev/null
+++ b/src/packages/sidebar/doc.taro.md
@@ -0,0 +1,84 @@
+# SideNavBar组件
+
+用于内容选择和切换
+
+## 引入
+
+```tsx
+import {
+ SideNavBar,
+ SubSideNavBar,
+ SideNavBarItem,
+} from '@nutui/nutui-react-taro'
+```
+
+## 示例代码
+
+### 基础用法
+
+:::demo
+
+
+
+:::
+
+### 嵌套及回调
+
+:::demo
+
+
+
+:::
+
+## SideNavBar
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| visible | 组件是否显示 | `boolean` | `false` |
+| title | 整体标题 | `string` | `-` |
+| width | 遮罩宽度百分比 | `string` | `80%` |
+| position | 弹出位置 | `left` \| `right` | `left` |
+| indent | 缩进宽度 | `number` | `20` |
+| onClose | 关闭遮罩时触发 | `-` | `-` |
+
+## SubSideNavBar
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| key | 导航唯一标识 | `string` \| `number` | `-` |
+| title | 整体标题 | `string` | `-` |
+| open | 导航是否默认展开 | `boolean` | `true` |
+| onClick | 导航点击 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+
+## SideNavBarItem
+
+### Props
+
+| 属性 | 说明 | 类型 | 默认值 |
+| --- | --- | --- | --- |
+| key | 导航唯一标识 | `string` \| `number` | `-` |
+| title | 整体标题 | `string` | `-` |
+| onClick | 导航点击 | `({title: string, value: string \| number}) => void` | `-` |
+
+## 主题定制
+
+### 样式变量
+
+组件提供了下列 CSS 变量,可用于自定义样式,使用方法请参考 [ConfigProvider 组件](#/zh-CN/component/configprovider)。
+
+| 名称 | 说明 | 默认值 |
+| --- | --- | --- |
+| \--nutui-sidenavbar-content-bg-color | 侧边栏导航背景色 | `$white` |
+| \--nutui-sidenavbar-item-height | 侧边栏每项的高度 | `40px` |
+| \--nutui-sidenavbar-title-padding | 标题的内边距 | `10px 8px 10px 20px` |
+| \--nutui-sidenavbar-title-background | 标题的背景色 | `$color-background` |
+| \--nutui-sidenavbar-title-color | 标题的字体颜色 | `$color-title` |
+| \--nutui-sidenavbar-sub-title-padding | 子标题的内边距 | `10px 8px 10px 35px` |
+| \--nutui-sidenavbar-sub-title-background | 子标题背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-title-color | 子标题字体颜色 | `$color-title` |
+| \--nutui-sidenavbar-sub-list-background | 选项列表背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-list-color | 选项列表字体颜色 | `$color-title` |
diff --git a/src/packages/sidebar/doc.zh-TW.md b/src/packages/sidebar/doc.zh-TW.md
new file mode 100644
index 0000000000..d100e8ba5b
--- /dev/null
+++ b/src/packages/sidebar/doc.zh-TW.md
@@ -0,0 +1,80 @@
+# SideNavBar組件
+
+用於內容選擇和切換
+
+## 引入
+
+```tsx
+import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+```
+
+## 示例代碼
+
+### 基礎用法
+
+:::demo
+
+
+
+:::
+
+### 導航嵌套(建議最多三層)
+
+:::demo
+
+
+
+:::
+
+## SideNavBar
+
+### Props
+
+| 屬性 | 說明 | 類型 | 默認值 |
+| --- | --- | --- | --- |
+| visible | 組件是否顯示 | `boolean` | `false` |
+| title | 整體標題 | `string` | `-` |
+| width | 遮罩寬度百分比 | `string` | `80%` |
+| position | 彈出位置 | `left` \| `right` | `left` |
+| offset | 縮進寬度 | `number` | `20` |
+| onClose | 關閉遮罩時觸發 | `-` | `-` |
+
+## SubSideNavBar
+
+### Props
+
+| 屬性 | 說明 | 類型 | 默認值 |
+| --- | --- | --- | --- |
+| value | 導航唯一標識 | `string` \| `number` | `-` |
+| title | 整體標題 | `string` | `-` |
+| open | 導航是否默認展開 | `boolean` | `true` |
+| onClick | 導航點擊 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+
+## SideNavBarItem
+
+### Props
+
+| 屬性 | 說明 | 類型 | 默認值 |
+| --- | --- | --- | --- |
+| value | 導航唯一標識 | `string` \| `number` | `-` |
+| title | 整體標題 | `string` | `-` |
+| onClick | 導航點擊 | `({title: string, value: string \| number}) => void` | `-` |
+
+## 主題定制
+
+### 樣式變量
+
+組件提供了下列 CSS 變量,可用於自定義樣式,使用方法請參考 [ConfigProvider 組件](#/zh-CN/component/configprovider)。
+
+| 名稱 | 說明 | 默認值 |
+| --- | --- | --- |
+| \--nutui-sidenavbar-content-bg-color | 側邊欄導航背景色 | `$white` |
+| \--nutui-sidenavbar-item-height | 側邊欄每項的高度 | `40px` |
+| \--nutui-sidenavbar-title-padding | 標題的內邊距 | `10px 8px 10px 20px` |
+| \--nutui-sidenavbar-title-background | 標題的背景色 | `$color-background` |
+| \--nutui-sidenavbar-title-color | 標題的字體顏色 | `$color-title` |
+| \--nutui-sidenavbar-sub-title-padding | 子標題的內邊距 | `10px 8px 10px 35px` |
+| \--nutui-sidenavbar-sub-title-background | 子標題背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-title-color | 子標題字體顏色 | `$color-title` |
+| \--nutui-sidenavbar-sub-list-background | 選項列表背景色 | `$color-background-sunken` |
+| \--nutui-sidenavbar-sub-list-color | 選項列表字體顏色 | `$color-title` |
diff --git a/src/packages/sidebar/index.taro.ts b/src/packages/sidebar/index.taro.ts
new file mode 100644
index 0000000000..9a46581651
--- /dev/null
+++ b/src/packages/sidebar/index.taro.ts
@@ -0,0 +1,4 @@
+import { SideNavBar } from './sidebar.taro'
+
+export type { SideNavBarProps } from './sidebar.taro'
+export default SideNavBar
diff --git a/src/packages/sidebar/index.ts b/src/packages/sidebar/index.ts
new file mode 100644
index 0000000000..3e3500b0a2
--- /dev/null
+++ b/src/packages/sidebar/index.ts
@@ -0,0 +1,4 @@
+import { SideBar } from './sidebar'
+
+export type { SideBarProps } from './sidebar'
+export default SideBar
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
new file mode 100644
index 0000000000..13f6fc9832
--- /dev/null
+++ b/src/packages/sidebar/sidebar.scss
@@ -0,0 +1,131 @@
+@import '../../styles/mixins/index';
+@import '../sidebaritem/sidebaritem.scss';
+
+.nut-sidebar {
+ display: flex;
+}
+
+.nut-sidebar-titles {
+ display: flex;
+ box-sizing: border-box;
+ height: $tabs-titles-height;
+ user-select: none;
+ overflow: hidden;
+ background: $tabs-titles-background-color;
+ scrollbar-width: none;
+
+ &::-webkit-scrollbar {
+ display: none;
+ width: 0;
+ background: transparent;
+ }
+
+ .nut-sidebar-list {
+ width: 100%;
+ height: auto;
+ display: flex;
+ flex-shrink: 0;
+ }
+
+ &-left {
+ justify-content: flex-start;
+ .nut-sidebar-titles-item {
+ padding: 0 22px;
+ }
+ }
+
+ &-scrollable {
+ overflow-x: auto;
+ overflow-y: hidden;
+ }
+
+ &-item {
+ cursor: pointer;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex: 1 0 auto;
+ padding: 0 $tabs-titles-gap;
+ height: $tabs-titles-height;
+ line-height: $tabs-titles-height;
+ min-width: $tabs-titles-item-min-width;
+ font-size: $tabs-titles-font-size;
+ color: $tabs-titles-item-color;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+
+ &-left,
+ &-right {
+ flex: none;
+ }
+
+ &-text {
+ text-align: center;
+ }
+
+ &-active {
+ color: #fa2c19;
+ font-weight: 500;
+ }
+
+ &-disabled {
+ color: $color-text-disabled;
+ cursor: not-allowed;
+ }
+ }
+}
+
+.nut-sidebar-vertical {
+ flex-direction: row;
+ width: 100%;
+
+ .nut-sidebar-ellipsis {
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+
+ .nut-sidebar-titles {
+ box-sizing: border-box;
+ flex-direction: column;
+ height: 100%;
+ width: 104px;
+ flex-shrink: 0;
+
+ .nut-sidebar-list {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ flex-shrink: 0;
+ }
+ }
+
+ .nut-sidebar-titles-scrollable {
+ overflow-x: hidden;
+ overflow-y: auto;
+ }
+
+ .nut-sidebar-titles-item {
+ height: 52px;
+ margin: 0;
+ flex: none;
+ &-active {
+ font-size: 18px;
+ }
+ }
+
+ .nut-sidebar-content {
+ flex-direction: column;
+ height: 100%;
+
+ &-wrap {
+ flex: 1;
+ overflow: hidden;
+ }
+
+ .nut-tabpane {
+ height: 100%;
+ }
+ }
+}
diff --git a/src/packages/sidebar/sidebar.taro.tsx b/src/packages/sidebar/sidebar.taro.tsx
new file mode 100644
index 0000000000..c2c89928bb
--- /dev/null
+++ b/src/packages/sidebar/sidebar.taro.tsx
@@ -0,0 +1,83 @@
+import React, { FunctionComponent, useState, ReactNode } from 'react'
+import classNames from 'classnames'
+import { View } from '@tarojs/components'
+import Popup from '@/packages/popup/index.taro'
+import { OffsetContext } from './context'
+import { BasicComponent, ComponentDefaults } from '@/utils/typings'
+
+export interface SideNavBarProps
+ extends Omit, 'title'>,
+ BasicComponent {
+ title: ReactNode
+ visible: boolean
+ width: string
+ indent: number
+ position: 'left' | 'right'
+ onClose: () => void
+}
+
+const defaultProps = {
+ ...ComponentDefaults,
+ position: 'left',
+ width: '80%',
+} as SideNavBarProps
+export const SideNavBar: FunctionComponent> = (
+ props
+) => {
+ const classPrefix = 'nut-sidenavbar'
+ const {
+ title,
+ visible,
+ width,
+ position,
+ children,
+ className,
+ onClose,
+ indent,
+ ...rest
+ } = {
+ ...defaultProps,
+ ...props,
+ }
+ const innerIndent = indent ? Number(indent) : 20
+ const [sidenavbarShow, setSidenavbarShow] = useState(true)
+ const handleClick = () => {
+ setSidenavbarShow(!sidenavbarShow)
+ }
+ return (
+
+
+
+
+
+ {title}
+
+
+
+ {children}
+
+
+
+
+
+ )
+}
+
+SideNavBar.displayName = 'NutSideNavBar'
diff --git a/src/packages/sidebar/sidebar.tsx b/src/packages/sidebar/sidebar.tsx
new file mode 100644
index 0000000000..36288ac709
--- /dev/null
+++ b/src/packages/sidebar/sidebar.tsx
@@ -0,0 +1,225 @@
+import React, { FunctionComponent, useEffect, useRef } from 'react'
+import classNames from 'classnames'
+import { BasicComponent, ComponentDefaults } from '@/utils/typings'
+import SideBarItem from '@/packages/sidebaritem'
+import raf from '@/utils/raf'
+import { usePropsValue } from '@/utils/use-props-value'
+import { useForceUpdate } from '@/utils/use-force-update'
+
+export type TabsTitle = {
+ title: string
+ disabled: boolean
+ active?: boolean
+ value: string | number
+}
+
+export interface TabsProps extends BasicComponent {
+ tabStyle: React.CSSProperties
+ switchOnEnd: boolean
+ value: string | number
+ defaultValue: string | number
+ activeColor: string
+ direction: 'horizontal' | 'vertical'
+ activeType: 'line' | 'smile' | 'simple' | 'card' | 'button' | 'divider'
+ duration: number | string
+ align: 'left' | 'right'
+ title: () => JSX.Element[]
+ onChange: (index: string | number) => void
+ onClick: (index: string | number) => void
+ autoHeight: boolean
+ children?: React.ReactNode
+}
+
+const defaultProps = {
+ ...ComponentDefaults,
+ tabStyle: {},
+ activeColor: '',
+ duration: 0,
+ autoHeight: false,
+ switchOnEnd: true,
+} as TabsProps
+
+const classPrefix = 'nut-sidebar'
+export const SideBar: FunctionComponent> & {
+ Item: typeof SideBarItem
+} = (props) => {
+ const {
+ activeColor,
+ tabStyle,
+ duration,
+ align,
+ title,
+ children,
+ onClick,
+ onChange,
+ className,
+ autoHeight,
+ value: outerValue,
+ defaultValue: outerDefaultValue,
+ ...rest
+ } = {
+ ...defaultProps,
+ ...props,
+ }
+
+ const [value, setValue] = usePropsValue({
+ value: outerValue,
+ defaultValue: outerDefaultValue,
+ finalValue: 0,
+ onChange,
+ })
+ const titleItemsRef = useRef([])
+ const navRef = useRef(null)
+ const scrollDirection = (nav: any, to: number, duration: number) => {
+ let count = 0
+ const from = nav.scrollTop
+ const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16)
+
+ function animate() {
+ nav.scrollTop += (to - from) / frames
+ if (++count < frames) {
+ raf(animate)
+ }
+ }
+ animate()
+ }
+ const scrollIntoView = (index: number, immediate?: boolean) => {
+ const nav = navRef.current
+ const titleItem = titleItemsRef.current
+ const titlesLength = titles.current.length
+ const itemLength = titleItemsRef.current.length
+ if (!nav || !titleItem || !titleItem[itemLength - titlesLength + index]) {
+ return
+ }
+ const title = titleItem[itemLength - titlesLength + index]
+ const runTop = title.offsetTop - nav.offsetTop + 10
+ const to = runTop - (nav.offsetHeight - title.offsetHeight) / 2
+ scrollDirection(nav, to, immediate ? 0 : 0.3)
+ }
+
+ const getTitles = () => {
+ const titles: TabsTitle[] = []
+ React.Children.forEach(children, (child: any, idx) => {
+ if (React.isValidElement(child)) {
+ const props: any = child?.props
+ if (props?.title || props?.value) {
+ titles.push({
+ title: props.title,
+ value: props.value || idx,
+ disabled: props.disabled,
+ })
+ }
+ }
+ })
+ return titles
+ }
+ const titles = useRef(getTitles())
+ const forceUpdate = useForceUpdate()
+ useEffect(() => {
+ titles.current = getTitles()
+ let current: string | number = ''
+ titles.current.forEach((title) => {
+ // eslint-disable-next-line eqeqeq
+ if (title.value == value) {
+ current = value
+ }
+ })
+ if (current !== '' && current !== value) {
+ setValue(current)
+ } else {
+ forceUpdate()
+ }
+ }, [children])
+
+ const classes = classNames(classPrefix, `${classPrefix}-vertical`, className)
+ const classesTitle = classNames(`${classPrefix}-titles`, {
+ [`${classPrefix}-titles-scrollable`]: true,
+ [`${classPrefix}-titles-${align}`]: align,
+ })
+
+ const getContentStyle = () => {
+ // eslint-disable-next-line eqeqeq
+ let index = titles.current.findIndex((t) => t.value == value)
+ index = index < 0 ? 0 : index
+ return {
+ transform: `translate3d( 0,-${index * 100}%, 0)`,
+ transitionDuration: `${duration}ms`,
+ }
+ }
+ useEffect(() => {
+ let index = titles.current.findIndex((t) => t.value === value)
+ index = index < 0 ? 0 : index
+ setTimeout(() => {
+ scrollIntoView(index)
+ })
+ }, [value])
+
+ const tabChange = (item: TabsTitle) => {
+ onClick && onClick(item.value)
+ if (item.disabled) {
+ return
+ }
+ setValue(item.value)
+ }
+ return (
+
+
+ {!!title && typeof title === 'function'
+ ? title()
+ : titles.current.map((item) => {
+ return (
+
{
+ tabChange(item)
+ }}
+ className={classNames(`${classPrefix}-titles-item`, {
+ [`${classPrefix}-titles-item-active`]:
+ !item.disabled && String(item.value) === String(value),
+ [`${classPrefix}-titles-item-disabled`]: item.disabled,
+ [`${classPrefix}-titles-item-${align}`]: align,
+ })}
+ ref={(ref: HTMLDivElement) => titleItemsRef.current.push(ref)}
+ key={item.value}
+ >
+
+ {item.title}
+
+
+ )
+ })}
+
+
+
+ {React.Children.map(children, (child, idx) => {
+ if (!React.isValidElement(child)) {
+ return null
+ }
+ let childProps = {
+ ...child.props,
+ active: value === child.props.value,
+ }
+
+ if (
+ String(value) !== String(child.props.value || idx) &&
+ autoHeight
+ ) {
+ childProps = {
+ ...childProps,
+ autoHeightClassName: 'inactive',
+ }
+ }
+ return React.cloneElement(child, childProps)
+ })}
+
+
+
+ )
+}
+
+SideBar.displayName = 'NutSideBar'
+SideBar.Item = SideBarItem
diff --git a/src/packages/sidebar/utils.ts b/src/packages/sidebar/utils.ts
new file mode 100644
index 0000000000..5f4d67d36f
--- /dev/null
+++ b/src/packages/sidebar/utils.ts
@@ -0,0 +1,22 @@
+import { MouseEventHandler } from 'react'
+
+const handleClick: MouseEventHandler = (e) => {
+ e.stopPropagation()
+ const isIcon = (e.target as HTMLDivElement).className.includes('arrow-icon')
+ const isTitle =
+ (e.target as HTMLDivElement).className.includes('-title') || isIcon
+ const currentClass = e.currentTarget.className
+ const isShow = currentClass.includes('sidenavbar-show')
+ const arrowIcon = e.currentTarget.querySelector('.arrow-icon') as Element
+ const iconClass = arrowIcon.className
+
+ if (isTitle) {
+ e.currentTarget.className = isShow
+ ? currentClass.replace('sidenavbar-show', 'sidenavbar-hide')
+ : currentClass.replace('sidenavbar-hide', 'sidenavbar-show')
+ arrowIcon.className = isShow
+ ? iconClass.replace('arrow-down', 'arrow-up')
+ : iconClass.replace('arrow-up', 'arrow-down')
+ }
+}
+export { handleClick }
diff --git a/src/packages/sidebaritem/index.taro.ts b/src/packages/sidebaritem/index.taro.ts
new file mode 100644
index 0000000000..26732133ec
--- /dev/null
+++ b/src/packages/sidebaritem/index.taro.ts
@@ -0,0 +1,4 @@
+import { SideBarItem } from './sidebaritem.taro'
+
+export type { SideBarItemProps } from './sidebaritem.taro'
+export default SideBarItem
diff --git a/src/packages/sidebaritem/index.ts b/src/packages/sidebaritem/index.ts
new file mode 100644
index 0000000000..dd3073a4af
--- /dev/null
+++ b/src/packages/sidebaritem/index.ts
@@ -0,0 +1,4 @@
+import { SideBarItem } from './sidebaritem'
+
+export type { SideBarItemProps } from './sidebaritem'
+export default SideBarItem
diff --git a/src/packages/sidebaritem/sidebaritem.scss b/src/packages/sidebaritem/sidebaritem.scss
new file mode 100644
index 0000000000..cb71c81228
--- /dev/null
+++ b/src/packages/sidebaritem/sidebaritem.scss
@@ -0,0 +1,16 @@
+.nut-sidebaritem {
+ width: 100%;
+ height: 100%;
+ flex-shrink: 0;
+ display: block;
+ background-color: $tabs-tabpane-backgroundColor;
+ color: $color-title;
+ padding: $tabs-tabpane-padding;
+ box-sizing: border-box;
+ overflow: auto;
+
+ &.inactive {
+ overflow: visible;
+ height: 0;
+ }
+}
diff --git a/src/packages/sidebaritem/sidebaritem.taro.tsx b/src/packages/sidebaritem/sidebaritem.taro.tsx
new file mode 100644
index 0000000000..ae3391dfd4
--- /dev/null
+++ b/src/packages/sidebaritem/sidebaritem.taro.tsx
@@ -0,0 +1,44 @@
+import React, { FunctionComponent } from 'react'
+import classNames from 'classnames'
+import { View } from '@tarojs/components'
+
+interface SideBarItemInnerProps {
+ autoHeightClassName: string
+}
+
+export interface SideBarItemProps {
+ title: string | number
+ value: string | number
+ disabled: boolean
+ className: string
+ children?: React.ReactNode
+}
+
+const defaultProps = {
+ title: '',
+ value: '',
+ disabled: false,
+} as SideBarItemProps
+
+export const SideBarItem: FunctionComponent<
+ Partial
+> = (props) => {
+ const { children, autoHeightClassName, className, disabled } = {
+ ...defaultProps,
+ ...props,
+ }
+
+ const classPrefix = 'nut-sidebaritem'
+ const classes = classNames(
+ classPrefix,
+ {
+ active: !disabled && (props as any).active,
+ },
+ autoHeightClassName,
+ className
+ )
+
+ return children ? (
+ {!disabled && children}
+ ) : null
+}
diff --git a/src/packages/sidebaritem/sidebaritem.tsx b/src/packages/sidebaritem/sidebaritem.tsx
new file mode 100644
index 0000000000..f5d93c1f92
--- /dev/null
+++ b/src/packages/sidebaritem/sidebaritem.tsx
@@ -0,0 +1,43 @@
+import React, { FunctionComponent } from 'react'
+import classNames from 'classnames'
+
+interface SideBarItemInnerProps {
+ autoHeightClassName: string
+}
+
+export interface SideBarItemProps {
+ title: string | number
+ value: string | number
+ disabled: boolean
+ className: string
+ children?: React.ReactNode
+}
+
+const defaultProps = {
+ title: '',
+ value: '',
+ disabled: false,
+} as SideBarItemProps
+
+export const SideBarItem: FunctionComponent<
+ Partial
+> = (props) => {
+ const { children, autoHeightClassName, className, disabled } = {
+ ...defaultProps,
+ ...props,
+ }
+
+ const classPrefix = 'nut-sidebaritem'
+ const classes = classNames(
+ classPrefix,
+ {
+ active: !disabled && (props as any).active,
+ },
+ autoHeightClassName,
+ className
+ )
+
+ return children ? (
+ {!disabled && children}
+ ) : null
+}
From 6317e5199184348c23d2c3b59f7eca9d884bc661 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Tue, 17 Dec 2024 16:12:14 +0800
Subject: [PATCH 02/14] chore: save my content
---
src/packages/sidebar/demo.tsx | 5 -
src/packages/sidebar/demos/h5/demo1.tsx | 2 +-
src/packages/sidebar/demos/h5/demo2.tsx | 6 +-
src/packages/sidebar/demos/h5/demo3.tsx | 6 +-
src/packages/sidebar/demos/h5/demo4.tsx | 35 +----
src/packages/sidebar/demos/h5/demo5.tsx | 7 +-
src/packages/sidebar/demos/h5/demo6.tsx | 47 -------
src/packages/sidebar/sidebar.scss | 153 ++++++----------------
src/packages/sidebar/sidebar.tsx | 107 ++++++---------
src/packages/sidebaritem/sidebaritem.scss | 4 +-
src/packages/sidebaritem/sidebaritem.tsx | 17 +--
src/styles/variables.scss | 24 +++-
12 files changed, 128 insertions(+), 285 deletions(-)
delete mode 100644 src/packages/sidebar/demos/h5/demo6.tsx
diff --git a/src/packages/sidebar/demo.tsx b/src/packages/sidebar/demo.tsx
index b1ee3224e4..df27900dcc 100644
--- a/src/packages/sidebar/demo.tsx
+++ b/src/packages/sidebar/demo.tsx
@@ -5,7 +5,6 @@ import Demo2 from './demos/h5/demo2'
import Demo3 from './demos/h5/demo3'
import Demo4 from './demos/h5/demo4'
import Demo5 from './demos/h5/demo5'
-import Demo6 from './demos/h5/demo6'
const SideNavBarDemo = () => {
const [translated] = useTranslate({
@@ -15,7 +14,6 @@ const SideNavBarDemo = () => {
matchByValue: '根据value匹配',
multiTitle: '多个标题',
setDuration: '设置滚动动画时长',
- swtchOnEnd: '滚动底部时自动切换 ',
},
'en-US': {
basic: 'Basic Usage',
@@ -23,7 +21,6 @@ const SideNavBarDemo = () => {
matchByValue: 'Match By Value',
multiTitle: 'Multiple Titles',
setDuration: 'Set Scroll Animation Duration',
- swtchOnEnd: 'Switch On End',
},
})
@@ -40,8 +37,6 @@ const SideNavBarDemo = () => {
{translated.setDuration}
- {translated.swtchOnEnd}
-
>
)
diff --git a/src/packages/sidebar/demos/h5/demo1.tsx b/src/packages/sidebar/demos/h5/demo1.tsx
index e748cdc696..8eede1cefc 100644
--- a/src/packages/sidebar/demos/h5/demo1.tsx
+++ b/src/packages/sidebar/demos/h5/demo1.tsx
@@ -14,7 +14,7 @@ const Demo1 = () => {
}}
>
{list.map((item) => (
-
+
Content {item + 1}
))}
diff --git a/src/packages/sidebar/demos/h5/demo2.tsx b/src/packages/sidebar/demos/h5/demo2.tsx
index 245fbc385d..faef940812 100644
--- a/src/packages/sidebar/demos/h5/demo2.tsx
+++ b/src/packages/sidebar/demos/h5/demo2.tsx
@@ -12,9 +12,9 @@ const Demo2 = () => {
setValue(value)
}}
>
- Content 1
- Content 2
-
+ Content 1
+ Content 2
+
>
)
diff --git a/src/packages/sidebar/demos/h5/demo3.tsx b/src/packages/sidebar/demos/h5/demo3.tsx
index 7147345faf..91e73389d5 100644
--- a/src/packages/sidebar/demos/h5/demo3.tsx
+++ b/src/packages/sidebar/demos/h5/demo3.tsx
@@ -12,13 +12,13 @@ const Demo2 = () => {
setValue(value)
}}
>
-
+
Content 1
-
+
Content 2
-
+
Content 3
diff --git a/src/packages/sidebar/demos/h5/demo4.tsx b/src/packages/sidebar/demos/h5/demo4.tsx
index faa46b6333..1753d010df 100644
--- a/src/packages/sidebar/demos/h5/demo4.tsx
+++ b/src/packages/sidebar/demos/h5/demo4.tsx
@@ -2,45 +2,20 @@ import React, { useState } from 'react'
import { SideBar } from '@nutui/nutui-react'
const Demo4 = () => {
- const [value, setValue] = useState(1)
- const list = [
- {
- title: 'Option 1',
- value: 1,
- },
- {
- title: 'Option 2',
- value: 2,
- },
- {
- title: 'Option 3',
- value: 3,
- },
- {
- title: 'Option 4',
- value: 4,
- },
- {
- title: 'Option 5',
- value: 5,
- },
- {
- title: 'Option 6',
- value: 6,
- },
- ]
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(20).keys())
return (
<>
{
setValue(value)
}}
>
{list.map((item) => (
-
- Content {item.value}
+
+ Content {item + 1}
))}
diff --git a/src/packages/sidebar/demos/h5/demo5.tsx b/src/packages/sidebar/demos/h5/demo5.tsx
index 7d37049230..86fb9502ba 100644
--- a/src/packages/sidebar/demos/h5/demo5.tsx
+++ b/src/packages/sidebar/demos/h5/demo5.tsx
@@ -3,19 +3,20 @@ import { SideBar } from '@nutui/nutui-react'
const Demo5 = () => {
const [value, setValue] = useState('0')
- const list = Array.from(new Array(3).keys())
+ const list = Array.from(new Array(20).keys())
return (
<>
{
setValue(value)
}}
>
{list.map((item) => (
-
+
Content {item + 1}
))}
diff --git a/src/packages/sidebar/demos/h5/demo6.tsx b/src/packages/sidebar/demos/h5/demo6.tsx
deleted file mode 100644
index 40eaebd2e1..0000000000
--- a/src/packages/sidebar/demos/h5/demo6.tsx
+++ /dev/null
@@ -1,47 +0,0 @@
-import React, { useState } from 'react'
-import { SideBar, Space } from '@nutui/nutui-react'
-
-const Demo6 = () => {
- function generateRandomStr(n: number) {
- const words = []
- const alphabet = 'abcdefghijklmnopqrstuvwxyz'
- function getRandomInt(min: number, max: number) {
- return Math.floor(Math.random() * (max - min + 1)) + min
- }
- for (let i = 0; i < n; i++) {
- const wordLength = getRandomInt(3, 10)
- let word = ''
- for (let j = 0; j < wordLength; j++) {
- const randomIndex = getRandomInt(0, alphabet.length - 1)
- word += alphabet[randomIndex]
- }
- words.push(word)
- }
- const sentence = `${words.join(' ')}.`
- return sentence.charAt(0).toUpperCase() + sentence.slice(1)
- }
- const [value, setValue] = useState('0')
- const list = Array.from(new Array(3).keys())
- return (
- <>
- {
- setValue(value)
- }}
- >
- {list.map((item) => (
-
-
- {generateRandomStr(30)}
- {generateRandomStr(30)}
-
-
- ))}
-
- >
- )
-}
-export default Demo6
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index 13f6fc9832..a94af4d32e 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -3,129 +3,62 @@
.nut-sidebar {
display: flex;
-}
-
-.nut-sidebar-titles {
- display: flex;
- box-sizing: border-box;
- height: $tabs-titles-height;
- user-select: none;
- overflow: hidden;
- background: $tabs-titles-background-color;
- scrollbar-width: none;
-
- &::-webkit-scrollbar {
- display: none;
- width: 0;
- background: transparent;
- }
-
- .nut-sidebar-list {
- width: 100%;
- height: auto;
- display: flex;
- flex-shrink: 0;
- }
-
- &-left {
- justify-content: flex-start;
- .nut-sidebar-titles-item {
- padding: 0 22px;
- }
- }
-
- &-scrollable {
- overflow-x: auto;
- overflow-y: hidden;
- }
-
- &-item {
- cursor: pointer;
- position: relative;
- display: flex;
- align-items: center;
- justify-content: center;
- flex: 1 0 auto;
- padding: 0 $tabs-titles-gap;
- height: $tabs-titles-height;
- line-height: $tabs-titles-height;
- min-width: $tabs-titles-item-min-width;
- font-size: $tabs-titles-font-size;
- color: $tabs-titles-item-color;
- text-overflow: ellipsis;
- white-space: nowrap;
-
- &-left,
- &-right {
- flex: none;
- }
-
- &-text {
- text-align: center;
- }
-
- &-active {
- color: #fa2c19;
- font-weight: 500;
- }
-
- &-disabled {
- color: $color-text-disabled;
- cursor: not-allowed;
+ &-content {
+ flex-direction: column;
+ height: 100%;
+ &-wrap {
+ flex: 1;
+ overflow: hidden;
}
}
-}
-
-.nut-sidebar-vertical {
- flex-direction: row;
- width: 100%;
-
- .nut-sidebar-ellipsis {
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
- }
-
- .nut-sidebar-titles {
+ &-titles {
+ background: $sidebar-background-color;
box-sizing: border-box;
flex-direction: column;
+ border-radius: $sidebar-border-radius;
height: 100%;
- width: 104px;
+ width: $sidebar-width;
flex-shrink: 0;
-
+ &::-webkit-scrollbar {
+ display: none;
+ width: 0;
+ background: transparent;
+ }
.nut-sidebar-list {
width: 100%;
display: flex;
flex-direction: column;
flex-shrink: 0;
}
- }
-
- .nut-sidebar-titles-scrollable {
- overflow-x: hidden;
- overflow-y: auto;
- }
-
- .nut-sidebar-titles-item {
- height: 52px;
- margin: 0;
- flex: none;
- &-active {
- font-size: 18px;
+ &-scrollable {
+ overflow-x: hidden;
+ overflow-y: auto;
}
- }
-
- .nut-sidebar-content {
- flex-direction: column;
- height: 100%;
-
- &-wrap {
- flex: 1;
- overflow: hidden;
- }
-
- .nut-tabpane {
- height: 100%;
+ &-item {
+ cursor: pointer;
+ position: relative;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ height: $sidebar-title-height;
+ margin: 0;
+ flex: none;
+ font-size: $sidebar-inactive-font-size;
+ &-text {
+ text-align: center;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+ }
+ &-active {
+ color: $sidebar-active-color;
+ font-weight: $sidebar-active-font-weight;
+ font-size: $sidebar-active-font-size;
+ }
+ &-disabled {
+ color: $color-text-disabled;
+ cursor: not-allowed;
+ }
}
}
}
diff --git a/src/packages/sidebar/sidebar.tsx b/src/packages/sidebar/sidebar.tsx
index 36288ac709..ea0e3c77f1 100644
--- a/src/packages/sidebar/sidebar.tsx
+++ b/src/packages/sidebar/sidebar.tsx
@@ -1,80 +1,63 @@
-import React, { FunctionComponent, useEffect, useRef } from 'react'
+import React, { FC, useEffect, useRef } from 'react'
import classNames from 'classnames'
import { BasicComponent, ComponentDefaults } from '@/utils/typings'
import SideBarItem from '@/packages/sidebaritem'
import raf from '@/utils/raf'
import { usePropsValue } from '@/utils/use-props-value'
import { useForceUpdate } from '@/utils/use-force-update'
+import { mergeProps } from '@/utils/merge-props'
-export type TabsTitle = {
+export type SideBarItemProps = {
title: string
disabled: boolean
active?: boolean
value: string | number
}
-export interface TabsProps extends BasicComponent {
- tabStyle: React.CSSProperties
- switchOnEnd: boolean
+export interface SideBarProps extends BasicComponent {
value: string | number
defaultValue: string | number
- activeColor: string
- direction: 'horizontal' | 'vertical'
- activeType: 'line' | 'smile' | 'simple' | 'card' | 'button' | 'divider'
- duration: number | string
- align: 'left' | 'right'
+ contentDuration: number
+ sidebarDuration: number
title: () => JSX.Element[]
onChange: (index: string | number) => void
onClick: (index: string | number) => void
- autoHeight: boolean
children?: React.ReactNode
}
const defaultProps = {
...ComponentDefaults,
- tabStyle: {},
- activeColor: '',
- duration: 0,
- autoHeight: false,
- switchOnEnd: true,
-} as TabsProps
+ contentDuration: 0,
+ sidebarDuration: 0,
+} as SideBarProps
const classPrefix = 'nut-sidebar'
-export const SideBar: FunctionComponent> & {
+export const SideBar: FC> & {
Item: typeof SideBarItem
} = (props) => {
const {
- activeColor,
- tabStyle,
- duration,
- align,
+ contentDuration,
+ sidebarDuration,
title,
children,
onClick,
onChange,
className,
- autoHeight,
- value: outerValue,
- defaultValue: outerDefaultValue,
...rest
- } = {
- ...defaultProps,
- ...props,
- }
+ } = mergeProps(defaultProps, props)
const [value, setValue] = usePropsValue({
- value: outerValue,
- defaultValue: outerDefaultValue,
+ value: props.value,
+ defaultValue: props.defaultValue,
finalValue: 0,
onChange,
})
const titleItemsRef = useRef([])
const navRef = useRef(null)
- const scrollDirection = (nav: any, to: number, duration: number) => {
+ const scroll = (nav: any, to: number) => {
let count = 0
const from = nav.scrollTop
- const frames = duration === 0 ? 1 : Math.round((duration * 1000) / 16)
-
+ const frames = sidebarDuration === 0 ? 1 : Math.round(sidebarDuration / 16)
function animate() {
nav.scrollTop += (to - from) / frames
if (++count < frames) {
@@ -83,7 +66,7 @@ export const SideBar: FunctionComponent> & {
}
animate()
}
- const scrollIntoView = (index: number, immediate?: boolean) => {
+ const scrollIntoView = (index: number) => {
const nav = navRef.current
const titleItem = titleItemsRef.current
const titlesLength = titles.current.length
@@ -93,12 +76,13 @@ export const SideBar: FunctionComponent> & {
}
const title = titleItem[itemLength - titlesLength + index]
const runTop = title.offsetTop - nav.offsetTop + 10
- const to = runTop - (nav.offsetHeight - title.offsetHeight) / 2
- scrollDirection(nav, to, immediate ? 0 : 0.3)
+ const to =
+ runTop - (nav.offsetHeight - title.offsetHeight) / 2 + title.offsetHeight
+ scroll(nav, to)
}
const getTitles = () => {
- const titles: TabsTitle[] = []
+ const titles: SideBarItemProps[] = []
React.Children.forEach(children, (child: any, idx) => {
if (React.isValidElement(child)) {
const props: any = child?.props
@@ -113,14 +97,13 @@ export const SideBar: FunctionComponent> & {
})
return titles
}
- const titles = useRef(getTitles())
+ const titles = useRef(getTitles())
const forceUpdate = useForceUpdate()
useEffect(() => {
titles.current = getTitles()
let current: string | number = ''
titles.current.forEach((title) => {
- // eslint-disable-next-line eqeqeq
- if (title.value == value) {
+ if (title.value === value) {
current = value
}
})
@@ -131,39 +114,37 @@ export const SideBar: FunctionComponent> & {
}
}, [children])
- const classes = classNames(classPrefix, `${classPrefix}-vertical`, className)
- const classesTitle = classNames(`${classPrefix}-titles`, {
- [`${classPrefix}-titles-scrollable`]: true,
- [`${classPrefix}-titles-${align}`]: align,
- })
+ const classes = classNames(classPrefix, className)
+ const classesTitle = classNames(
+ `${classPrefix}-titles`,
+ `${classPrefix}-titles-scrollable`
+ )
const getContentStyle = () => {
- // eslint-disable-next-line eqeqeq
- let index = titles.current.findIndex((t) => t.value == value)
+ let index = titles.current.findIndex((t) => t.value === value)
index = index < 0 ? 0 : index
return {
transform: `translate3d( 0,-${index * 100}%, 0)`,
- transitionDuration: `${duration}ms`,
+ transitionDuration: `${contentDuration}ms`,
}
}
useEffect(() => {
let index = titles.current.findIndex((t) => t.value === value)
index = index < 0 ? 0 : index
- setTimeout(() => {
+ const rafId = requestAnimationFrame(() => {
scrollIntoView(index)
})
+ return () => cancelAnimationFrame(rafId)
}, [value])
- const tabChange = (item: TabsTitle) => {
- onClick && onClick(item.value)
- if (item.disabled) {
- return
- }
+ const tabChange = (item: SideBarItemProps) => {
+ onClick?.(item.value)
+ if (item.disabled) return
setValue(item.value)
}
return (
-
+
{!!title && typeof title === 'function'
? title()
: titles.current.map((item) => {
@@ -176,17 +157,11 @@ export const SideBar: FunctionComponent
> & {
[`${classPrefix}-titles-item-active`]:
!item.disabled && String(item.value) === String(value),
[`${classPrefix}-titles-item-disabled`]: item.disabled,
- [`${classPrefix}-titles-item-${align}`]: align,
})}
ref={(ref: HTMLDivElement) => titleItemsRef.current.push(ref)}
key={item.value}
>
-
@@ -204,13 +179,9 @@ export const SideBar: FunctionComponent> & {
active: value === child.props.value,
}
- if (
- String(value) !== String(child.props.value || idx) &&
- autoHeight
- ) {
+ if (String(value) !== String(child.props.value || idx)) {
childProps = {
...childProps,
- autoHeightClassName: 'inactive',
}
}
return React.cloneElement(child, childProps)
diff --git a/src/packages/sidebaritem/sidebaritem.scss b/src/packages/sidebaritem/sidebaritem.scss
index cb71c81228..3dc1602aef 100644
--- a/src/packages/sidebaritem/sidebaritem.scss
+++ b/src/packages/sidebaritem/sidebaritem.scss
@@ -3,9 +3,9 @@
height: 100%;
flex-shrink: 0;
display: block;
- background-color: $tabs-tabpane-backgroundColor;
+ background-color: $sidebar-item-background;
color: $color-title;
- padding: $tabs-tabpane-padding;
+ padding: $sidebar-item-padding;
box-sizing: border-box;
overflow: auto;
diff --git a/src/packages/sidebaritem/sidebaritem.tsx b/src/packages/sidebaritem/sidebaritem.tsx
index f5d93c1f92..172b7cd607 100644
--- a/src/packages/sidebaritem/sidebaritem.tsx
+++ b/src/packages/sidebaritem/sidebaritem.tsx
@@ -1,9 +1,6 @@
import React, { FunctionComponent } from 'react'
import classNames from 'classnames'
-
-interface SideBarItemInnerProps {
- autoHeightClassName: string
-}
+import { mergeProps } from '@/utils/merge-props'
export interface SideBarItemProps {
title: string | number
@@ -19,13 +16,10 @@ const defaultProps = {
disabled: false,
} as SideBarItemProps
-export const SideBarItem: FunctionComponent<
- Partial
-> = (props) => {
- const { children, autoHeightClassName, className, disabled } = {
- ...defaultProps,
- ...props,
- }
+export const SideBarItem: FunctionComponent> = (
+ props
+) => {
+ const { children, className, disabled } = mergeProps(defaultProps, props)
const classPrefix = 'nut-sidebaritem'
const classes = classNames(
@@ -33,7 +27,6 @@ export const SideBarItem: FunctionComponent<
{
active: !disabled && (props as any).active,
},
- autoHeightClassName,
className
)
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
index ee8dc9720c..55e00568c4 100644
--- a/src/styles/variables.scss
+++ b/src/styles/variables.scss
@@ -2178,7 +2178,29 @@ $navbar-title-font-color: var(
--nutui-navbar-title-font-color,
$color-title
) !default;
-
+// sidebar(✅)
+$sidebar-background-color: var(
+ --nutui-sidebar-background-color,
+ $color-background
+) !default;
+$sidebar-border-radius: var(--nutui-sidebar-border-radius, 0) !default;
+$sidebar-width: var(--nutui-sidebar-width, 104px) !default;
+$sidebar-title-height: var(--nutui-sidebar-title-height, 52px) !default;
+$sidebar-inactive-font-size: var(
+ --nutui-sidebar-inactive-font-size,
+ $font-size-base
+) !default;
+$sidebar-active-font-size: var(
+ --nutui-sidebar-active-font-size,
+ $font-size-xl
+) !default;
+$sidebar-active-font-weight: var(
+ --nutui-sidebar-active-font-weight,
+ 500
+) !default;
+$sidebar-active-color: var(--nutui-sidebar-active-color, #fa2c19) !default;
+$sidebar-item-background: var(--nutui-sidebar-item-background, $white) !default;
+$sidebar-item-padding: var(--nutui-sidebar-item-padding, 24px 20px) !default;
// sidenavbar(✅)
$sidenavbar-content-bg-color: var(
--nutui-sidenavbar-content-bg-color,
From daff1647aac3bfac22894f0acc553e35062e328b Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Tue, 17 Dec 2024 18:42:45 +0800
Subject: [PATCH 03/14] chore: save my content
---
src/config.json | 16 +-
src/packages/sidebar/_test_/sidebar.spec.tsx | 20 ++
src/packages/sidebar/demo.taro.tsx | 51 +++
src/packages/sidebar/demos/taro/demo1.tsx | 25 ++
src/packages/sidebar/demos/taro/demo2.tsx | 22 ++
src/packages/sidebar/demos/taro/demo3.tsx | 28 ++
src/packages/sidebar/demos/taro/demo4.tsx | 25 ++
src/packages/sidebar/demos/taro/demo5.tsx | 27 ++
src/packages/sidebar/doc.en-US.md | 85 ++---
src/packages/sidebar/doc.md | 85 +++--
src/packages/sidebar/doc.taro.md | 83 ++---
src/packages/sidebar/doc.zh-TW.md | 81 +++--
src/packages/sidebar/index.taro.ts | 7 +-
src/packages/sidebar/index.ts | 2 +-
src/packages/sidebar/sidebar.taro.tsx | 293 ++++++++++++++----
src/packages/sidebar/sidebar.tsx | 63 ++--
src/packages/sidebar/types.ts | 18 ++
src/packages/sidebaritem/sidebaritem.taro.tsx | 17 +-
18 files changed, 682 insertions(+), 266 deletions(-)
create mode 100644 src/packages/sidebar/_test_/sidebar.spec.tsx
create mode 100644 src/packages/sidebar/demo.taro.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo1.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo2.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo3.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo4.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo5.tsx
create mode 100644 src/packages/sidebar/types.ts
diff --git a/src/config.json b/src/config.json
index cd63da9a4f..6bbef31200 100644
--- a/src/config.json
+++ b/src/config.json
@@ -344,17 +344,29 @@
"author": "hx"
},
{
- "version": "2.0.0",
+ "version": "3.0.0",
"name": "SideBar",
"type": "component",
"cName": "侧边栏导航",
- "desc": "用于内容选择和切换",
+ "desc": "用于侧边内容选择和切换",
"sort": 10,
"show": true,
"taro": true,
"author": "Alex.hxy",
"v15": true
},
+ {
+ "version": "3.0.0",
+ "name": "SideBarItem",
+ "type": "component",
+ "cName": "侧边栏导航子组件",
+ "desc": "用于侧边内容选择和切换",
+ "sort": 10,
+ "show": false,
+ "taro": true,
+ "author": "Alex.hxy",
+ "v15": true
+ },
{
"version": "2.0.0",
"name": "SideNavBarItem",
diff --git a/src/packages/sidebar/_test_/sidebar.spec.tsx b/src/packages/sidebar/_test_/sidebar.spec.tsx
new file mode 100644
index 0000000000..5eb9b185f8
--- /dev/null
+++ b/src/packages/sidebar/_test_/sidebar.spec.tsx
@@ -0,0 +1,20 @@
+import * as React from 'react'
+import { render } from '@testing-library/react'
+import '@testing-library/jest-dom'
+import { SideBar } from '../sidebar'
+
+const list = Array.from(new Array(3).keys())
+
+test('should render defaultValue correctly', async () => {
+ const { container } = render(
+
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ )
+ const item = container.querySelectorAll('.nut-sidebar-titles-item')[0]
+ expect(item).toHaveClass('nut-sidebar-titles-item-active')
+})
diff --git a/src/packages/sidebar/demo.taro.tsx b/src/packages/sidebar/demo.taro.tsx
new file mode 100644
index 0000000000..25a6a14c07
--- /dev/null
+++ b/src/packages/sidebar/demo.taro.tsx
@@ -0,0 +1,51 @@
+import React from 'react'
+import Taro from '@tarojs/taro'
+import { ScrollView, View } from '@tarojs/components'
+import { useTranslate } from '@/sites/assets/locale/taro'
+import Header from '@/sites/components/header'
+import Demo1 from './demos/taro/demo1'
+import Demo2 from './demos/taro/demo2'
+import Demo3 from './demos/taro/demo3'
+import Demo4 from './demos/taro/demo4'
+import Demo5 from './demos/taro/demo5'
+
+const TabsDemo = () => {
+ const [translated] = useTranslate({
+ 'zh-CN': {
+ basic: '基础用法',
+ disabled: '禁用选项',
+ matchByValue: '根据value匹配',
+ multiTitle: '多个标题',
+ setDuration: '设置滚动动画时长',
+ },
+ 'en-US': {
+ basic: 'Basic Usage',
+ disabled: 'Disabled',
+ matchByValue: 'Match By Value',
+ multiTitle: 'Multiple Titles',
+ setDuration: 'Set Scroll Animation Duration',
+ },
+ })
+
+ return (
+ <>
+
+
+ {translated.basic}
+
+ {translated.disabled}
+
+ {translated.matchByValue}
+
+ {translated.multiTitle}
+
+ {translated.setDuration}
+
+
+ >
+ )
+}
+
+export default TabsDemo
diff --git a/src/packages/sidebar/demos/taro/demo1.tsx b/src/packages/sidebar/demos/taro/demo1.tsx
new file mode 100644
index 0000000000..50a63962c3
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo1.tsx
@@ -0,0 +1,25 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react-taro'
+
+const Demo1 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ >
+ )
+}
+export default Demo1
diff --git a/src/packages/sidebar/demos/taro/demo2.tsx b/src/packages/sidebar/demos/taro/demo2.tsx
new file mode 100644
index 0000000000..a741d9eb14
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo2.tsx
@@ -0,0 +1,22 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react-taro'
+
+const Demo2 = () => {
+ const [value, setValue] = useState('0')
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ Content 1
+ Content 2
+
+
+ >
+ )
+}
+export default Demo2
diff --git a/src/packages/sidebar/demos/taro/demo3.tsx b/src/packages/sidebar/demos/taro/demo3.tsx
new file mode 100644
index 0000000000..5ff252e92d
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo3.tsx
@@ -0,0 +1,28 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react-taro'
+
+const Demo2 = () => {
+ const [value, setValue] = useState('b')
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+
+ Content 1
+
+
+ Content 2
+
+
+ Content 3
+
+
+ >
+ )
+}
+export default Demo2
diff --git a/src/packages/sidebar/demos/taro/demo4.tsx b/src/packages/sidebar/demos/taro/demo4.tsx
new file mode 100644
index 0000000000..f08ea9ef3b
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo4.tsx
@@ -0,0 +1,25 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react-taro'
+
+const Demo4 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(20).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ >
+ )
+}
+export default Demo4
diff --git a/src/packages/sidebar/demos/taro/demo5.tsx b/src/packages/sidebar/demos/taro/demo5.tsx
new file mode 100644
index 0000000000..515543da1e
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo5.tsx
@@ -0,0 +1,27 @@
+import React, { useState } from 'react'
+import { SideBar } from '@nutui/nutui-react-taro'
+
+const Demo5 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(20).keys())
+ return (
+ <>
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ >
+ )
+}
+export default Demo5
diff --git a/src/packages/sidebar/doc.en-US.md b/src/packages/sidebar/doc.en-US.md
index 64af02c249..5df1a1d15c 100644
--- a/src/packages/sidebar/doc.en-US.md
+++ b/src/packages/sidebar/doc.en-US.md
@@ -1,16 +1,16 @@
-# SideNavBar组件
+# SideBar component
-For content selection and switching
+Used for side content selection and switching
-## Import
+## Introduction
```tsx
-import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+import { SideBar } from '@nutui/nutui-react'
```
-## Demo
+## Sample code
-### Basic Usage
+### Basic usage
:::demo
@@ -18,7 +18,7 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
:::
-### Navigation Nesting (Up To Three Levels Recommended)
+### Disable option
:::demo
@@ -26,39 +26,52 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
:::
-## SideNavBar
+### Match based on value
-### Props
+:::demo
-| Property | Description | Type | Default |
-| --- | --- | --- | --- |
-| visible | whether the component is visible | `boolean` | `false` |
-| title | overall title | `string` | `-` |
-| width | mask width in percentage | `string` | `80%` |
-| position | popup position | `left` \| `right` | `left` |
-| indent | indent width | `number` | `20` |
-| onClose | Triggered when the mask is closed | `-` | `-` |
+
+
+:::
+
+### Multiple titles
+
+:::demo
+
+
+
+:::
+
+### Set the scroll animation duration
+
+:::demo
+
+
+
+:::
-## SubSideNavBar
+## SideBar
### Props
| Property | Description | Type | Default |
| --- | --- | --- | --- |
-| value | unique identifier for navigation | `string` \| `number` | `-` |
-| title | overall title | `string` | `-` |
-| open | whether the navigation is expanded by default | `boolean` | `true` |
-| onClick | Navigation click | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+| value | The key of the currently activated `item` | `string \| number` | `-` |
+| defaultValue | When value is not set, the default value of the key of `item` | `string \| number` | `-` |
+| contentDuration | content scroll animation duration | `number` | `0` |
+| sidebarDuration | Sidebar scroll animation duration | `number` | `0` |
+| onClick | Triggered when the label is clicked | `(index: string \| number) => void` | `-` |
+| onChange | Triggered when the currently active label changes | `(index: string \| number) => void` | `-` |
-## SideNavBarItem
+## SideBar.Item
### Props
| Property | Description | Type | Default |
| --- | --- | --- | --- |
-| value | unique identifier for navigation | `string` \| `number` | `-` |
-| title | overall title | `string` | `-` |
-| onClick | Navigation click | `({title: string, value: string \| number}) => void` | `-` |
+| title | title | `string` | `-` |
+| value | tag Key, matched identifier, defaults to index value | `string` \| `number` | `-` |
+| disabled | Whether to disable the label | `boolean` | `false` |
## Theming
@@ -68,13 +81,13 @@ The component provides the following CSS variables, which can be used to customi
| Name | Description | Default |
| --- | --- | --- |
-| \--nutui-sidenavbar-content-bg-color | sidebar navigation background color | `$white` |
-| \--nutui-sidenavbar-item-height | The height of each item in the sidebar | `40px` |
-| \--nutui-sidenavbar-title-padding | padding for title | `10px 8px 10px 20px` |
-| \--nutui-sidenavbar-title-background | The background color of the title | `$color-background` |
-| \--nutui-sidenavbar-title-color | The font color of the title | `$color-title` |
-| \--nutui-sidenavbar-sub-title-padding | Padding of subtitle | `10px 8px 10px 35px` |
-| \--nutui-sidenavbar-sub-title-background | Subtitle background color | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-title-color | Subtitle font color | `$color-title` |
-| \--nutui-sidenavbar-sub-list-background | option list background color | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-list-color | option list font color | `$color-title` |
+| \--nutui-sidebar-background-color | Sidebar navigation background color | `$color-background` |
+| \--nutui-sidebar-border-radius | Rounded corners of the sidebar | `0` |
+| \--nutui-sidebar-width | Sidebar width | `104px` |
+| \--nutui-sidebar-title-height | Sidebar title height | `52px` |
+| \--nutui-sidebar-inactive-font-size | Font size in normal state | `$font-size-base` |
+| \--nutui-sidebar-active-font-size | Font size in active state | `$font-size-xl` |
+| \--nutui-sidebar-active-font-weight | Font weight in active state | `500` |
+| \--nutui-sidebar-active-color | Font color in active state | `#fa2c19` |
+| \--nutui-sidebar-item-background | The background color of the content area | `$white` |
+| \--nutui-sidebar-item-padding, 24px | Padding of the content area | `24px 20px` |
diff --git a/src/packages/sidebar/doc.md b/src/packages/sidebar/doc.md
index 98135b2e7d..1d74e78959 100644
--- a/src/packages/sidebar/doc.md
+++ b/src/packages/sidebar/doc.md
@@ -1,11 +1,11 @@
-# SideNavBar组件
+# SideBar组件
-用于内容选择和切换
+用于侧边内容选择和切换
## 引入
```tsx
-import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+import { SideBar } from '@nutui/nutui-react'
```
## 示例代码
@@ -18,39 +18,60 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
:::
-## SideNavBar
+### 禁用选项
-### Props
+:::demo
-| 属性 | 说明 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| visible | 组件是否显示 | `boolean` | `false` |
-| title | 整体标题 | `string` | `-` |
-| width | 遮罩宽度百分比 | `string` | `80%` |
-| position | 弹出位置 | `left` \| `right` | `left` |
-| indent | 缩进宽度 | `number` | `20` |
-| onClose | 关闭遮罩时触发 | `-` | `-` |
+
+
+:::
+
+### 根据value匹配
+
+:::demo
+
+
+
+:::
+
+### 多个标题
+
+:::demo
+
+
+
+:::
+
+### 设置滚动动画时长
+
+:::demo
+
+
+
+:::
-## SubSideNavBar
+## SideBar
### Props
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
-| value | 导航唯一标识 | `string` \| `number` | `-` |
-| title | 整体标题 | `string` | `-` |
-| open | 导航是否默认展开 | `boolean` | `true` |
-| onClick | 导航点击 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+| value | 当前激活的`item`的key | `string \| number` | `-` |
+| defaultValue | 未设置value时,`item`的key的默认值 | `string \| number` | `-` |
+| contentDuration | 内容滚动动画时长 | `number` | `0` |
+| sidebarDuration | 侧栏滚动动画时长 | `number` | `0` |
+| onClick | 点击标签时触发 | `(index: string \| number) => void` | `-` |
+| onChange | 当前激活的标签改变时触发 | `(index: string \| number) => void` | `-` |
-## SideNavBarItem
+## SideBar.Item
### Props
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
-| value | 导航唯一标识 | `string` \| `number` | `-` |
-| title | 整体标题 | `string` | `-` |
-| onClick | 导航点击 | `({title: string, value: string \| number}) => void` | `-` |
+| title | 标题 | `string` | `-` |
+| value | 标签 Key , 匹配的标识符, 默认为索引值 | `string` \| `number` | `-` |
+| disabled | 是否禁用标签 | `boolean` | `false` |
## 主题定制
@@ -60,13 +81,13 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
| 名称 | 说明 | 默认值 |
| --- | --- | --- |
-| \--nutui-sidenavbar-content-bg-color | 侧边栏导航背景色 | `$white` |
-| \--nutui-sidenavbar-item-height | 侧边栏每项的高度 | `40px` |
-| \--nutui-sidenavbar-title-padding | 标题的内边距 | `10px 8px 10px 20px` |
-| \--nutui-sidenavbar-title-background | 标题的背景色 | `$color-background` |
-| \--nutui-sidenavbar-title-color | 标题的字体颜色 | `$color-title` |
-| \--nutui-sidenavbar-sub-title-padding | 子标题的内边距 | `10px 8px 10px 35px` |
-| \--nutui-sidenavbar-sub-title-background | 子标题背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-title-color | 子标题字体颜色 | `$color-title` |
-| \--nutui-sidenavbar-sub-list-background | 选项列表背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-list-color | 选项列表字体颜色 | `$color-title` |
+| \--nutui-sidebar-background-color | 侧边栏导航背景色 | `$color-background` |
+| \--nutui-sidebar-border-radius | 侧边栏的圆角 | `0` |
+| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
+| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
+| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
+| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-xl` |
+| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
+| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
+| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
+| \--nutui-sidebar-item-padding, 24px | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.taro.md b/src/packages/sidebar/doc.taro.md
index 1db5ec19e3..3562ca2b64 100644
--- a/src/packages/sidebar/doc.taro.md
+++ b/src/packages/sidebar/doc.taro.md
@@ -1,15 +1,11 @@
-# SideNavBar组件
+# SideBar组件
-用于内容选择和切换
+用于侧边内容选择和切换
## 引入
```tsx
-import {
- SideNavBar,
- SubSideNavBar,
- SideNavBarItem,
-} from '@nutui/nutui-react-taro'
+import { SideBar } from '@nutui/nutui-react-taro'
```
## 示例代码
@@ -22,7 +18,7 @@ import {
:::
-### 嵌套及回调
+### 禁用选项
:::demo
@@ -30,39 +26,52 @@ import {
:::
-## SideNavBar
+### 根据value匹配
-### Props
+:::demo
-| 属性 | 说明 | 类型 | 默认值 |
-| --- | --- | --- | --- |
-| visible | 组件是否显示 | `boolean` | `false` |
-| title | 整体标题 | `string` | `-` |
-| width | 遮罩宽度百分比 | `string` | `80%` |
-| position | 弹出位置 | `left` \| `right` | `left` |
-| indent | 缩进宽度 | `number` | `20` |
-| onClose | 关闭遮罩时触发 | `-` | `-` |
+
+
+:::
+
+### 多个标题
+
+:::demo
+
+
+
+:::
+
+### 设置滚动动画时长
+
+:::demo
+
+
+
+:::
-## SubSideNavBar
+## SideBar
### Props
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
-| key | 导航唯一标识 | `string` \| `number` | `-` |
-| title | 整体标题 | `string` | `-` |
-| open | 导航是否默认展开 | `boolean` | `true` |
-| onClick | 导航点击 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+| value | 当前激活的`item`的key | `string \| number` | `-` |
+| defaultValue | 未设置value时,`item`的key的默认值 | `string \| number` | `-` |
+| contentDuration | 内容滚动动画时长 | `number` | `0` |
+| sidebarDuration | 侧栏滚动动画时长 | `number` | `0` |
+| onClick | 点击标签时触发 | `(index: string \| number) => void` | `-` |
+| onChange | 当前激活的标签改变时触发 | `(index: string \| number) => void` | `-` |
-## SideNavBarItem
+## SideBar.Item
### Props
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
-| key | 导航唯一标识 | `string` \| `number` | `-` |
-| title | 整体标题 | `string` | `-` |
-| onClick | 导航点击 | `({title: string, value: string \| number}) => void` | `-` |
+| title | 标题 | `string` | `-` |
+| value | 标签 Key , 匹配的标识符, 默认为索引值 | `string` \| `number` | `-` |
+| disabled | 是否禁用标签 | `boolean` | `false` |
## 主题定制
@@ -72,13 +81,13 @@ import {
| 名称 | 说明 | 默认值 |
| --- | --- | --- |
-| \--nutui-sidenavbar-content-bg-color | 侧边栏导航背景色 | `$white` |
-| \--nutui-sidenavbar-item-height | 侧边栏每项的高度 | `40px` |
-| \--nutui-sidenavbar-title-padding | 标题的内边距 | `10px 8px 10px 20px` |
-| \--nutui-sidenavbar-title-background | 标题的背景色 | `$color-background` |
-| \--nutui-sidenavbar-title-color | 标题的字体颜色 | `$color-title` |
-| \--nutui-sidenavbar-sub-title-padding | 子标题的内边距 | `10px 8px 10px 35px` |
-| \--nutui-sidenavbar-sub-title-background | 子标题背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-title-color | 子标题字体颜色 | `$color-title` |
-| \--nutui-sidenavbar-sub-list-background | 选项列表背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-list-color | 选项列表字体颜色 | `$color-title` |
+| \--nutui-sidebar-background-color | 侧边栏导航背景色 | `$color-background` |
+| \--nutui-sidebar-border-radius | 侧边栏的圆角 | `0` |
+| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
+| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
+| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
+| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-xl` |
+| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
+| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
+| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
+| \--nutui-sidebar-item-padding, 24px | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.zh-TW.md b/src/packages/sidebar/doc.zh-TW.md
index d100e8ba5b..eed3d725d6 100644
--- a/src/packages/sidebar/doc.zh-TW.md
+++ b/src/packages/sidebar/doc.zh-TW.md
@@ -1,11 +1,11 @@
-# SideNavBar組件
+# SideBar組件
-用於內容選擇和切換
+用於側邊內容選擇和切換
## 引入
```tsx
-import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
+import { SideBar } from '@nutui/nutui-react'
```
## 示例代碼
@@ -18,7 +18,7 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
:::
-### 導航嵌套(建議最多三層)
+### 禁用選項
:::demo
@@ -26,41 +26,54 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
:::
-## SideNavBar
+### 根據value匹配
-### Props
+:::demo
-| 屬性 | 說明 | 類型 | 默認值 |
-| --- | --- | --- | --- |
-| visible | 組件是否顯示 | `boolean` | `false` |
-| title | 整體標題 | `string` | `-` |
-| width | 遮罩寬度百分比 | `string` | `80%` |
-| position | 彈出位置 | `left` \| `right` | `left` |
-| offset | 縮進寬度 | `number` | `20` |
-| onClose | 關閉遮罩時觸發 | `-` | `-` |
+
+
+:::
+
+### 多個標題
+
+:::demo
+
+
+
+:::
+
+### 設置滾動動畫時長
+
+:::demo
+
+
+
+:::
-## SubSideNavBar
+## SideBar
### Props
| 屬性 | 說明 | 類型 | 默認值 |
| --- | --- | --- | --- |
-| value | 導航唯一標識 | `string` \| `number` | `-` |
-| title | 整體標題 | `string` | `-` |
-| open | 導航是否默認展開 | `boolean` | `true` |
-| onClick | 導航點擊 | `({title: string, value: string \| number, isShow: boolean}) => void` | `-` |
+| value | 當前激活的`item`的key | `string \| number` | `-` |
+| defaultValue | 未設置value時,`item`的key的默認值 | `string \| number` | `-` |
+| contentDuration | 內容滾動動畫時長 | `number` | `0` |
+| sidebarDuration | 側欄滾動動畫時長 | `number` | `0` |
+| onClick | 點擊標簽時觸發 | `(index: string \| number) => void` | `-` |
+| onChange | 當前激活的標簽改變時觸發 | `(index: string \| number) => void` | `-` |
-## SideNavBarItem
+## SideBar.Item
### Props
| 屬性 | 說明 | 類型 | 默認值 |
| --- | --- | --- | --- |
-| value | 導航唯一標識 | `string` \| `number` | `-` |
-| title | 整體標題 | `string` | `-` |
-| onClick | 導航點擊 | `({title: string, value: string \| number}) => void` | `-` |
+| title | 標題 | `string` | `-` |
+| value | 標簽 Key , 匹配的標識符, 默認為索引值 | `string` \| `number` | `-` |
+| disabled | 是否禁用標簽 | `boolean` | `false` |
-## 主題定制
+## 主題定製
### 樣式變量
@@ -68,13 +81,13 @@ import { SideNavBar, SubSideNavBar, SideNavBarItem } from '@nutui/nutui-react'
| 名稱 | 說明 | 默認值 |
| --- | --- | --- |
-| \--nutui-sidenavbar-content-bg-color | 側邊欄導航背景色 | `$white` |
-| \--nutui-sidenavbar-item-height | 側邊欄每項的高度 | `40px` |
-| \--nutui-sidenavbar-title-padding | 標題的內邊距 | `10px 8px 10px 20px` |
-| \--nutui-sidenavbar-title-background | 標題的背景色 | `$color-background` |
-| \--nutui-sidenavbar-title-color | 標題的字體顏色 | `$color-title` |
-| \--nutui-sidenavbar-sub-title-padding | 子標題的內邊距 | `10px 8px 10px 35px` |
-| \--nutui-sidenavbar-sub-title-background | 子標題背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-title-color | 子標題字體顏色 | `$color-title` |
-| \--nutui-sidenavbar-sub-list-background | 選項列表背景色 | `$color-background-sunken` |
-| \--nutui-sidenavbar-sub-list-color | 選項列表字體顏色 | `$color-title` |
+| \--nutui-sidebar-background-color | 側邊欄導航背景色 | `$color-background` |
+| \--nutui-sidebar-border-radius | 側邊欄的圓角 | `0` |
+| \--nutui-sidebar-width | 側邊欄寬度 | `104px` |
+| \--nutui-sidebar-title-height | 側邊欄標題高度 | `52px` |
+| \--nutui-sidebar-inactive-font-size | 普通狀態下的字體大小 | `$font-size-base` |
+| \--nutui-sidebar-active-font-size | 激活狀態下的字體大小 | `$font-size-xl` |
+| \--nutui-sidebar-active-font-weight | 激活狀態下的字重 | `500` |
+| \--nutui-sidebar-active-color | 激活狀態下的字體顏色 | `#fa2c19` |
+| \--nutui-sidebar-item-background | 內容區域的背景色 | `$white` |
+| \--nutui-sidebar-item-padding, 24px | 內容區域的內邊距 | `24px 20px` |
diff --git a/src/packages/sidebar/index.taro.ts b/src/packages/sidebar/index.taro.ts
index 9a46581651..e7d26db3b8 100644
--- a/src/packages/sidebar/index.taro.ts
+++ b/src/packages/sidebar/index.taro.ts
@@ -1,4 +1,5 @@
-import { SideNavBar } from './sidebar.taro'
+import { SideBar } from './sidebar.taro'
-export type { SideNavBarProps } from './sidebar.taro'
-export default SideNavBar
+export type { SideBarProps } from './types'
+
+export default SideBar
diff --git a/src/packages/sidebar/index.ts b/src/packages/sidebar/index.ts
index 3e3500b0a2..105927bf4b 100644
--- a/src/packages/sidebar/index.ts
+++ b/src/packages/sidebar/index.ts
@@ -1,4 +1,4 @@
import { SideBar } from './sidebar'
-export type { SideBarProps } from './sidebar'
+export type { SideBarProps } from './types'
export default SideBar
diff --git a/src/packages/sidebar/sidebar.taro.tsx b/src/packages/sidebar/sidebar.taro.tsx
index c2c89928bb..1da8ca61d3 100644
--- a/src/packages/sidebar/sidebar.taro.tsx
+++ b/src/packages/sidebar/sidebar.taro.tsx
@@ -1,83 +1,240 @@
-import React, { FunctionComponent, useState, ReactNode } from 'react'
+import React, { FC, useEffect, useRef, useState } from 'react'
+import { ScrollView, View } from '@tarojs/components'
import classNames from 'classnames'
-import { View } from '@tarojs/components'
-import Popup from '@/packages/popup/index.taro'
-import { OffsetContext } from './context'
-import { BasicComponent, ComponentDefaults } from '@/utils/typings'
-
-export interface SideNavBarProps
- extends Omit, 'title'>,
- BasicComponent {
- title: ReactNode
- visible: boolean
- width: string
- indent: number
- position: 'left' | 'right'
- onClose: () => void
-}
+import Taro, { nextTick, createSelectorQuery } from '@tarojs/taro'
+import { ComponentDefaults } from '@/utils/typings'
+import { usePropsValue } from '@/utils/use-props-value'
+import { useForceUpdate } from '@/utils/use-force-update'
+import raf from '@/utils/raf'
+import useUuid from '@/utils/use-uuid'
+import { SideBarItemProps, SideBarProps } from './types'
+import SideBarItem from '@/packages/sidebaritem/index.taro'
+import { mergeProps } from '@/utils/merge-props'
const defaultProps = {
...ComponentDefaults,
- position: 'left',
- width: '80%',
-} as SideNavBarProps
-export const SideNavBar: FunctionComponent> = (
- props
-) => {
- const classPrefix = 'nut-sidenavbar'
+ contentDuration: 0,
+ sidebarDuration: 0,
+} as SideBarProps
+
+const classPrefix = 'nut-sidebar'
+export const SideBar: FC> & {
+ Item: typeof SideBarItem
+} = (props) => {
const {
- title,
- visible,
- width,
- position,
+ contentDuration,
+ sidebarDuration,
children,
+ onClick,
+ onChange,
className,
- onClose,
- indent,
...rest
- } = {
- ...defaultProps,
- ...props,
+ } = mergeProps(defaultProps, props)
+ const uuid = useUuid()
+ const [value, setValue] = usePropsValue({
+ value: props.value,
+ defaultValue: props.defaultValue,
+ finalValue: 0,
+ onChange,
+ })
+
+ const titleItemsRef = useRef([])
+ const navRef = useRef(null)
+
+ const getTitles = () => {
+ const titles: SideBarItemProps[] = []
+ React.Children.forEach(children, (child: any, idx) => {
+ if (React.isValidElement(child)) {
+ const props: any = child?.props
+ if (props?.title || props?.value) {
+ titles.push({
+ title: props.title,
+ value: props.value || idx,
+ disabled: props.disabled,
+ })
+ }
+ }
+ })
+ return titles
+ }
+
+ const titles = useRef(getTitles())
+ const forceUpdate = useForceUpdate()
+ useEffect(() => {
+ titles.current = getTitles()
+ let current: string | number = ''
+ titles.current.forEach((title) => {
+ if (title.value === value) {
+ current = value
+ }
+ })
+ if (current !== '' && current !== value) {
+ setValue(current)
+ } else {
+ forceUpdate()
+ }
+ }, [children])
+
+ const classes = classNames(classPrefix, className)
+ const classesTitle = classNames(
+ `${classPrefix}-titles`,
+ `${classPrefix}-titles-scrollable`
+ )
+ const getRect = (selector: string) => {
+ return new Promise((resolve) => {
+ createSelectorQuery()
+ .select(selector)
+ .boundingClientRect()
+ .exec((rect = []) => {
+ resolve(rect[0])
+ })
+ })
+ }
+ const getAllRect = (selector: string) => {
+ return new Promise((resolve) => {
+ createSelectorQuery()
+ .selectAll(selector)
+ .boundingClientRect()
+ .exec((rect = []) => {
+ resolve(rect[0])
+ })
+ })
}
- const innerIndent = indent ? Number(indent) : 20
- const [sidenavbarShow, setSidenavbarShow] = useState(true)
- const handleClick = () => {
- setSidenavbarShow(!sidenavbarShow)
+ type RectItem = {
+ bottom: number
+ dataset: { sid: string }
+ height: number
+ id: string
+ left: number
+ right: number
+ top: number
+ width: number
}
+ const scrollWithAnimation = useRef(false)
+ const navRectRef = useRef()
+ const titleRectRef = useRef([])
+ const [scrollTop, setScrollTop] = useState(0)
+ const scrollDirection = (to: number) => {
+ let count = 0
+ const frames = sidebarDuration === 0 ? 1 : Math.round(sidebarDuration / 16)
+ function animate() {
+ setScrollTop(to)
+ if (++count < frames) {
+ raf(animate)
+ }
+ }
+ animate()
+ }
+ const scrollIntoView = (index: number) => {
+ raf(() => {
+ Promise.all([
+ getRect(`#${classPrefix}-titles-${uuid} .${classPrefix}-list`),
+ getAllRect(
+ `#${classPrefix}-titles-${uuid} .${classPrefix}-titles-item`
+ ),
+ ]).then(([navRect, titleRects]: any) => {
+ navRectRef.current = navRect
+ titleRectRef.current = titleRects
+ const titleRect: RectItem = titleRectRef.current[index]
+ if (!titleRect) return
+ nextTick(() => {
+ scrollWithAnimation.current = true
+ })
+ scrollDirection(titleRect.height * (index - 1))
+ })
+ })
+ }
+
+ const getContentStyle = () => {
+ let index = titles.current.findIndex(
+ (t) => String(t.value) === String(value)
+ )
+ index = index < 0 ? 0 : index
+ return {
+ transform: `translate3d( 0,-${index * 100}%, 0)`,
+ transitionDuration: `${contentDuration}ms`,
+ }
+ }
+
+ useEffect(() => {
+ let index = titles.current.findIndex(
+ (t) => String(t.value) === String(value)
+ )
+ index = index < 0 ? 0 : index
+ scrollIntoView(index)
+ }, [value])
+
+ const tabChange = (item: SideBarItemProps, index: number) => {
+ onClick && onClick(item.value)
+ if (item.disabled) return
+ setValue(item.value)
+ }
+
return (
-
-
-
-
-
- {title}
-
-
-
- {children}
-
-
+
+
+
+ {titles.current.map((item, index) => {
+ return (
+ titleItemsRef.current.push(ref)}
+ id={`scrollIntoView${index}`}
+ onClick={(e) => {
+ tabChange(item, index)
+ }}
+ className={classNames(`${classPrefix}-titles-item`, {
+ [`${classPrefix}-titles-item-active`]:
+ !item.disabled && String(item.value) === String(value),
+ [`${classPrefix}-titles-item-disabled`]: item.disabled,
+ })}
+ key={item.value}
+ >
+
+ {item.title}
+
+
+ )
+ })}
+
+
+
+
+ {React.Children.map(children, (child, idx) => {
+ if (!React.isValidElement(child)) {
+ return null
+ }
+ let childProps = {
+ ...child.props,
+ active: value === child.props.value,
+ }
+ if (String(value) !== String(child.props.value || idx)) {
+ childProps = {
+ ...childProps,
+ }
+ }
+ return React.cloneElement(child, childProps)
+ })}
-
-
+
+
)
}
-SideNavBar.displayName = 'NutSideNavBar'
+SideBar.displayName = 'NutSideBar'
+SideBar.Item = SideBarItem
diff --git a/src/packages/sidebar/sidebar.tsx b/src/packages/sidebar/sidebar.tsx
index ea0e3c77f1..e3de30d33b 100644
--- a/src/packages/sidebar/sidebar.tsx
+++ b/src/packages/sidebar/sidebar.tsx
@@ -1,29 +1,13 @@
import React, { FC, useEffect, useRef } from 'react'
import classNames from 'classnames'
-import { BasicComponent, ComponentDefaults } from '@/utils/typings'
+import { ComponentDefaults } from '@/utils/typings'
import SideBarItem from '@/packages/sidebaritem'
import raf from '@/utils/raf'
import { usePropsValue } from '@/utils/use-props-value'
import { useForceUpdate } from '@/utils/use-force-update'
import { mergeProps } from '@/utils/merge-props'
-export type SideBarItemProps = {
- title: string
- disabled: boolean
- active?: boolean
- value: string | number
-}
-
-export interface SideBarProps extends BasicComponent {
- value: string | number
- defaultValue: string | number
- contentDuration: number
- sidebarDuration: number
- title: () => JSX.Element[]
- onChange: (index: string | number) => void
- onClick: (index: string | number) => void
- children?: React.ReactNode
-}
+import { SideBarItemProps, SideBarProps } from './types'
const defaultProps = {
...ComponentDefaults,
@@ -38,7 +22,6 @@ export const SideBar: FC> & {
const {
contentDuration,
sidebarDuration,
- title,
children,
onClick,
onChange,
@@ -145,28 +128,26 @@ export const SideBar: FC> & {
return (
- {!!title && typeof title === 'function'
- ? title()
- : titles.current.map((item) => {
- return (
-
{
- tabChange(item)
- }}
- className={classNames(`${classPrefix}-titles-item`, {
- [`${classPrefix}-titles-item-active`]:
- !item.disabled && String(item.value) === String(value),
- [`${classPrefix}-titles-item-disabled`]: item.disabled,
- })}
- ref={(ref: HTMLDivElement) => titleItemsRef.current.push(ref)}
- key={item.value}
- >
-
- {item.title}
-
-
- )
- })}
+ {titles.current.map((item) => {
+ return (
+
{
+ tabChange(item)
+ }}
+ className={classNames(`${classPrefix}-titles-item`, {
+ [`${classPrefix}-titles-item-active`]:
+ !item.disabled && String(item.value) === String(value),
+ [`${classPrefix}-titles-item-disabled`]: item.disabled,
+ })}
+ ref={(ref: HTMLDivElement) => titleItemsRef.current.push(ref)}
+ key={item.value}
+ >
+
+ {item.title}
+
+
+ )
+ })}
diff --git a/src/packages/sidebar/types.ts b/src/packages/sidebar/types.ts
new file mode 100644
index 0000000000..3bf5877ab7
--- /dev/null
+++ b/src/packages/sidebar/types.ts
@@ -0,0 +1,18 @@
+import { BasicComponent } from '@/utils/typings'
+
+export type SideBarItemProps = {
+ title: string
+ disabled: boolean
+ active?: boolean
+ value: string | number
+}
+
+export interface SideBarProps extends BasicComponent {
+ value: string | number
+ defaultValue: string | number
+ contentDuration: number
+ sidebarDuration: number
+ onChange: (index: string | number) => void
+ onClick: (index: string | number) => void
+ children?: React.ReactNode
+}
diff --git a/src/packages/sidebaritem/sidebaritem.taro.tsx b/src/packages/sidebaritem/sidebaritem.taro.tsx
index ae3391dfd4..8a1566ff8f 100644
--- a/src/packages/sidebaritem/sidebaritem.taro.tsx
+++ b/src/packages/sidebaritem/sidebaritem.taro.tsx
@@ -1,10 +1,7 @@
import React, { FunctionComponent } from 'react'
import classNames from 'classnames'
import { View } from '@tarojs/components'
-
-interface SideBarItemInnerProps {
- autoHeightClassName: string
-}
+import { mergeProps } from '@/utils/merge-props'
export interface SideBarItemProps {
title: string | number
@@ -20,13 +17,10 @@ const defaultProps = {
disabled: false,
} as SideBarItemProps
-export const SideBarItem: FunctionComponent<
- Partial
-> = (props) => {
- const { children, autoHeightClassName, className, disabled } = {
- ...defaultProps,
- ...props,
- }
+export const SideBarItem: FunctionComponent> = (
+ props
+) => {
+ const { children, className, disabled } = mergeProps(defaultProps, props)
const classPrefix = 'nut-sidebaritem'
const classes = classNames(
@@ -34,7 +28,6 @@ export const SideBarItem: FunctionComponent<
{
active: !disabled && (props as any).active,
},
- autoHeightClassName,
className
)
From 8010707e8a7ad7053ca33160e5f204121338dcf7 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Tue, 17 Dec 2024 19:54:35 +0800
Subject: [PATCH 04/14] fix: adopt some AI adivice
---
src/packages/sidebar/demos/h5/demo3.tsx | 4 ++--
src/packages/sidebar/demos/taro/demo3.tsx | 4 ++--
src/packages/sidebar/doc.en-US.md | 2 +-
src/packages/sidebar/doc.md | 2 +-
src/packages/sidebar/doc.taro.md | 2 +-
src/packages/sidebar/doc.zh-TW.md | 2 +-
src/packages/sidebar/sidebar.taro.tsx | 10 +++-------
src/packages/sidebar/sidebar.tsx | 10 +++-------
8 files changed, 14 insertions(+), 22 deletions(-)
diff --git a/src/packages/sidebar/demos/h5/demo3.tsx b/src/packages/sidebar/demos/h5/demo3.tsx
index 91e73389d5..1fe0937601 100644
--- a/src/packages/sidebar/demos/h5/demo3.tsx
+++ b/src/packages/sidebar/demos/h5/demo3.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import { SideBar } from '@nutui/nutui-react'
-const Demo2 = () => {
+const Demo3 = () => {
const [value, setValue] = useState('b')
return (
<>
@@ -25,4 +25,4 @@ const Demo2 = () => {
>
)
}
-export default Demo2
+export default Demo3
diff --git a/src/packages/sidebar/demos/taro/demo3.tsx b/src/packages/sidebar/demos/taro/demo3.tsx
index 5ff252e92d..6dab28f3e2 100644
--- a/src/packages/sidebar/demos/taro/demo3.tsx
+++ b/src/packages/sidebar/demos/taro/demo3.tsx
@@ -1,7 +1,7 @@
import React, { useState } from 'react'
import { SideBar } from '@nutui/nutui-react-taro'
-const Demo2 = () => {
+const Demo3 = () => {
const [value, setValue] = useState('b')
return (
<>
@@ -25,4 +25,4 @@ const Demo2 = () => {
>
)
}
-export default Demo2
+export default Demo3
diff --git a/src/packages/sidebar/doc.en-US.md b/src/packages/sidebar/doc.en-US.md
index 5df1a1d15c..d0504e3e75 100644
--- a/src/packages/sidebar/doc.en-US.md
+++ b/src/packages/sidebar/doc.en-US.md
@@ -90,4 +90,4 @@ The component provides the following CSS variables, which can be used to customi
| \--nutui-sidebar-active-font-weight | Font weight in active state | `500` |
| \--nutui-sidebar-active-color | Font color in active state | `#fa2c19` |
| \--nutui-sidebar-item-background | The background color of the content area | `$white` |
-| \--nutui-sidebar-item-padding, 24px | Padding of the content area | `24px 20px` |
+| \--nutui-sidebar-item-padding | Padding of the content area | `24px 20px` |
diff --git a/src/packages/sidebar/doc.md b/src/packages/sidebar/doc.md
index 1d74e78959..f4b966fa57 100644
--- a/src/packages/sidebar/doc.md
+++ b/src/packages/sidebar/doc.md
@@ -90,4 +90,4 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
-| \--nutui-sidebar-item-padding, 24px | 内容区域的内边距 | `24px 20px` |
+| \--nutui-sidebar-item-padding | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.taro.md b/src/packages/sidebar/doc.taro.md
index 3562ca2b64..95e3283461 100644
--- a/src/packages/sidebar/doc.taro.md
+++ b/src/packages/sidebar/doc.taro.md
@@ -90,4 +90,4 @@ import { SideBar } from '@nutui/nutui-react-taro'
| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
-| \--nutui-sidebar-item-padding, 24px | 内容区域的内边距 | `24px 20px` |
+| \--nutui-sidebar-item-padding | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.zh-TW.md b/src/packages/sidebar/doc.zh-TW.md
index eed3d725d6..2c044cd3b2 100644
--- a/src/packages/sidebar/doc.zh-TW.md
+++ b/src/packages/sidebar/doc.zh-TW.md
@@ -90,4 +90,4 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-active-font-weight | 激活狀態下的字重 | `500` |
| \--nutui-sidebar-active-color | 激活狀態下的字體顏色 | `#fa2c19` |
| \--nutui-sidebar-item-background | 內容區域的背景色 | `$white` |
-| \--nutui-sidebar-item-padding, 24px | 內容區域的內邊距 | `24px 20px` |
+| \--nutui-sidebar-item-padding | 內容區域的內邊距 | `24px 20px` |
diff --git a/src/packages/sidebar/sidebar.taro.tsx b/src/packages/sidebar/sidebar.taro.tsx
index 1da8ca61d3..42d8020fd2 100644
--- a/src/packages/sidebar/sidebar.taro.tsx
+++ b/src/packages/sidebar/sidebar.taro.tsx
@@ -68,11 +68,7 @@ export const SideBar: FC> & {
current = value
}
})
- if (current !== '' && current !== value) {
- setValue(current)
- } else {
- forceUpdate()
- }
+ forceUpdate()
}, [children])
const classes = classNames(classPrefix, className)
@@ -165,8 +161,8 @@ export const SideBar: FC> & {
}, [value])
const tabChange = (item: SideBarItemProps, index: number) => {
- onClick && onClick(item.value)
if (item.disabled) return
+ onClick?.(item.value)
setValue(item.value)
}
@@ -223,7 +219,7 @@ export const SideBar: FC> & {
...child.props,
active: value === child.props.value,
}
- if (String(value) !== String(child.props.value || idx)) {
+ if (String(value) !== String(child.props.value ?? idx)) {
childProps = {
...childProps,
}
diff --git a/src/packages/sidebar/sidebar.tsx b/src/packages/sidebar/sidebar.tsx
index e3de30d33b..f6cd035a00 100644
--- a/src/packages/sidebar/sidebar.tsx
+++ b/src/packages/sidebar/sidebar.tsx
@@ -72,7 +72,7 @@ export const SideBar: FC> & {
if (props?.title || props?.value) {
titles.push({
title: props.title,
- value: props.value || idx,
+ value: props.value ?? idx,
disabled: props.disabled,
})
}
@@ -90,11 +90,7 @@ export const SideBar: FC> & {
current = value
}
})
- if (current !== '' && current !== value) {
- setValue(current)
- } else {
- forceUpdate()
- }
+ forceUpdate()
}, [children])
const classes = classNames(classPrefix, className)
@@ -121,8 +117,8 @@ export const SideBar: FC> & {
}, [value])
const tabChange = (item: SideBarItemProps) => {
- onClick?.(item.value)
if (item.disabled) return
+ onClick?.(item.value)
setValue(item.value)
}
return (
From bec5d7924ebd62a70272e8398a695f6cdf16deac Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Tue, 17 Dec 2024 20:11:02 +0800
Subject: [PATCH 05/14] chore: add unit test rate
---
src/packages/sidebar/_test_/sidebar.spec.tsx | 33 +++++++++++++++++++-
1 file changed, 32 insertions(+), 1 deletion(-)
diff --git a/src/packages/sidebar/_test_/sidebar.spec.tsx b/src/packages/sidebar/_test_/sidebar.spec.tsx
index 5eb9b185f8..1e9445c0b9 100644
--- a/src/packages/sidebar/_test_/sidebar.spec.tsx
+++ b/src/packages/sidebar/_test_/sidebar.spec.tsx
@@ -1,5 +1,5 @@
import * as React from 'react'
-import { render } from '@testing-library/react'
+import { fireEvent, render } from '@testing-library/react'
import '@testing-library/jest-dom'
import { SideBar } from '../sidebar'
@@ -18,3 +18,34 @@ test('should render defaultValue correctly', async () => {
const item = container.querySelectorAll('.nut-sidebar-titles-item')[0]
expect(item).toHaveClass('nut-sidebar-titles-item-active')
})
+
+test('should choose and scroll to the right option', async () => {
+ const onChange = vi.fn()
+ const { container } = render(
+
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ )
+ const items = container.querySelectorAll('.nut-sidebar-titles-item')
+ fireEvent.click(items[1])
+ expect(onChange).toHaveBeenCalledWith(1)
+})
+test('disabled option', async () => {
+ const onChange = vi.fn()
+ const { container } = render(
+
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+ )
+ const items = container.querySelectorAll('.nut-sidebar-titles-item')
+ fireEvent.click(items[1])
+ expect(onChange).not.toHaveBeenCalled()
+})
From 4354a6317d41f682212b41cc010fd04253952a74 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Tue, 17 Dec 2024 20:21:50 +0800
Subject: [PATCH 06/14] chore: add unit test rate
---
src/packages/sidebar/_test_/sidebar.spec.tsx | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)
diff --git a/src/packages/sidebar/_test_/sidebar.spec.tsx b/src/packages/sidebar/_test_/sidebar.spec.tsx
index 1e9445c0b9..104a1d6cf3 100644
--- a/src/packages/sidebar/_test_/sidebar.spec.tsx
+++ b/src/packages/sidebar/_test_/sidebar.spec.tsx
@@ -49,3 +49,22 @@ test('disabled option', async () => {
fireEvent.click(items[1])
expect(onChange).not.toHaveBeenCalled()
})
+test('matchByValue', async () => {
+ const list1 = [
+ { value: 'a', title: 'Opt a' },
+ { value: 'b', title: 'Opt b' },
+ { value: 'c', title: 'Opt c' },
+ ]
+ const onChange = vi.fn()
+ const { container } = render(
+
+ {list1.map((item) => (
+
+ Content {item.value}
+
+ ))}
+
+ )
+ const items = container.querySelectorAll('.nut-sidebar-titles-item')
+ expect(items[1]).toHaveClass('nut-sidebar-titles-item-active')
+})
From 4539dc55bb8b4610aa3be3b5444c90bb1085546b Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Sun, 22 Dec 2024 15:25:17 +0800
Subject: [PATCH 07/14] feat: v15 style adaption
---
src/packages/sidebar/doc.en-US.md | 6 +++---
src/packages/sidebar/doc.md | 6 +++---
src/packages/sidebar/doc.taro.md | 6 +++---
src/packages/sidebar/doc.zh-TW.md | 6 +++---
src/packages/sidebar/sidebar.scss | 5 ++++-
src/styles/variables.scss | 9 ++++++---
6 files changed, 22 insertions(+), 16 deletions(-)
diff --git a/src/packages/sidebar/doc.en-US.md b/src/packages/sidebar/doc.en-US.md
index d0504e3e75..62fcbe55d0 100644
--- a/src/packages/sidebar/doc.en-US.md
+++ b/src/packages/sidebar/doc.en-US.md
@@ -86,8 +86,8 @@ The component provides the following CSS variables, which can be used to customi
| \--nutui-sidebar-width | Sidebar width | `104px` |
| \--nutui-sidebar-title-height | Sidebar title height | `52px` |
| \--nutui-sidebar-inactive-font-size | Font size in normal state | `$font-size-base` |
-| \--nutui-sidebar-active-font-size | Font size in active state | `$font-size-xl` |
-| \--nutui-sidebar-active-font-weight | Font weight in active state | `500` |
-| \--nutui-sidebar-active-color | Font color in active state | `#fa2c19` |
+| \--nutui-sidebar-active-font-size | Font size in active state | `$font-size-l` |
+| \--nutui-sidebar-active-font-weight | Font weight in active state | `$font-weight-bold` |
+| \--nutui-sidebar-active-color | Font color in active state | `$color-primary` |
| \--nutui-sidebar-item-background | The background color of the content area | `$white` |
| \--nutui-sidebar-item-padding | Padding of the content area | `24px 20px` |
diff --git a/src/packages/sidebar/doc.md b/src/packages/sidebar/doc.md
index f4b966fa57..03facfb84c 100644
--- a/src/packages/sidebar/doc.md
+++ b/src/packages/sidebar/doc.md
@@ -86,8 +86,8 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
-| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-xl` |
-| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
-| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
+| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-l` |
+| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `$font-weight-bold` |
+| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `$color-primary` |
| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
| \--nutui-sidebar-item-padding | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.taro.md b/src/packages/sidebar/doc.taro.md
index 95e3283461..7de3f340c6 100644
--- a/src/packages/sidebar/doc.taro.md
+++ b/src/packages/sidebar/doc.taro.md
@@ -86,8 +86,8 @@ import { SideBar } from '@nutui/nutui-react-taro'
| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
-| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-xl` |
-| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `500` |
-| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `#fa2c19` |
+| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-l` |
+| \--nutui-sidebar-active-font-weight | 激活状态下的字重 | `$font-weight-bold` |
+| \--nutui-sidebar-active-color | 激活状态下的字体颜色 | `$color-primary` |
| \--nutui-sidebar-item-background | 内容区域的背景色 | `$white` |
| \--nutui-sidebar-item-padding | 内容区域的内边距 | `24px 20px` |
diff --git a/src/packages/sidebar/doc.zh-TW.md b/src/packages/sidebar/doc.zh-TW.md
index 2c044cd3b2..9ec14acc85 100644
--- a/src/packages/sidebar/doc.zh-TW.md
+++ b/src/packages/sidebar/doc.zh-TW.md
@@ -86,8 +86,8 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-width | 側邊欄寬度 | `104px` |
| \--nutui-sidebar-title-height | 側邊欄標題高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通狀態下的字體大小 | `$font-size-base` |
-| \--nutui-sidebar-active-font-size | 激活狀態下的字體大小 | `$font-size-xl` |
-| \--nutui-sidebar-active-font-weight | 激活狀態下的字重 | `500` |
-| \--nutui-sidebar-active-color | 激活狀態下的字體顏色 | `#fa2c19` |
+| \--nutui-sidebar-active-font-size | 激活狀態下的字體大小 | `$font-size-l` |
+| \--nutui-sidebar-active-font-weight | 激活狀態下的字重 | `$font-weight-bold` |
+| \--nutui-sidebar-active-color | 激活狀態下的字體顏色 | `$color-primary` |
| \--nutui-sidebar-item-background | 內容區域的背景色 | `$white` |
| \--nutui-sidebar-item-padding | 內容區域的內邊距 | `24px 20px` |
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index a94af4d32e..322802e7b8 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -45,12 +45,15 @@
flex: none;
font-size: $sidebar-inactive-font-size;
&-text {
+ font-family: PingFangSC-Regular;
text-align: center;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
+ color: $color-text;
}
- &-active {
+ &-active .nut-sidebar-titles-item-text {
+ font-family: PingFangSC-Semibold;
color: $sidebar-active-color;
font-weight: $sidebar-active-font-weight;
font-size: $sidebar-active-font-size;
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
index 55e00568c4..cd7a0ac60c 100644
--- a/src/styles/variables.scss
+++ b/src/styles/variables.scss
@@ -2192,13 +2192,16 @@ $sidebar-inactive-font-size: var(
) !default;
$sidebar-active-font-size: var(
--nutui-sidebar-active-font-size,
- $font-size-xl
+ $font-size-l
) !default;
$sidebar-active-font-weight: var(
--nutui-sidebar-active-font-weight,
- 500
+ $font-weight-bold
+) !default;
+$sidebar-active-color: var(
+ --nutui-sidebar-active-color,
+ $color-primary
) !default;
-$sidebar-active-color: var(--nutui-sidebar-active-color, #fa2c19) !default;
$sidebar-item-background: var(--nutui-sidebar-item-background, $white) !default;
$sidebar-item-padding: var(--nutui-sidebar-item-padding, 24px 20px) !default;
// sidenavbar(✅)
From fc0bdbdb3e3fb2ef82f538d0d783a60fdf062969 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Sun, 22 Dec 2024 15:52:24 +0800
Subject: [PATCH 08/14] feat: migrate doc update
---
migrate-from-v2.md | 24 +++++++++++++++++-------
1 file changed, 17 insertions(+), 7 deletions(-)
diff --git a/migrate-from-v2.md b/migrate-from-v2.md
index ffcd44f21a..62faf04482 100644
--- a/migrate-from-v2.md
+++ b/migrate-from-v2.md
@@ -302,6 +302,16 @@ plugins: [
- `offset` 重命名为 `indent`
+#### SideBar
+
+- 新增SideBar组件
+- 支持属性value,用于当前激活的`item`的key
+- 支持属性defaultValue, 表示未设置value时,`item`的key的默认值
+- 支持属性contentDuration, 用于内容滚动动画时长
+- 支持属性sidebarDuration, 用于侧栏滚动动画时长
+- 支持属性onClick, 点击标签时触发
+- 支持属性onChange, 当前激活的标签改变时触发
+
#### Tabbar
- `unactiveColor` 重命名为 `inactiveColor`
@@ -527,11 +537,11 @@ plugins: [
- `maximize` 重命名为 `maxFileSize`
- `maximum` 重命名为 `maxCount`
-- `listType ` 重命名为 `previewType`
-- `isDeletable ` 重命名为 `deletable`
-- `isPreview` 重命名为 ` preview`
-- `defaultImg` 重命名为 ` previewUrl`
-- `defaultFileList` 重命名为 ` defaultValue`
+- `listType` 重命名为 `previewType`
+- `isDeletable` 重命名为 `deletable`
+- `isPreview` 重命名为 `preview`
+- `defaultImg` 重命名为 `previewUrl`
+- `defaultFileList` 重命名为 `defaultValue`
- `uploadIconTip` 重命名为 `uploadLabel`,类型变更为 `ReactNode`
- `onBeforeUpload` 重命名为 `beforeUpload`
- `onBeforeXhrUpload` 重命名为 `beforeXhrUpload`
@@ -616,7 +626,7 @@ plugins: [
- 移除 `isAsync`,通过 `checked`实现
- 移除 `activeColor` ,通过css变量`--nutui-switch-open-background-color`实现
- 移除 `inactiveColor`,通过css变量`--nutui-switch-close-background-color`实现
-- `activeText 属性类型更改为 `ReactNode`
+- `activeText 属性类型更改为`ReactNode`
- `inactiveText` 属性类型更改为 `ReactNode`
#### Toast
@@ -803,7 +813,7 @@ plugins: [
- 移除 `pageContent`,通过 indicator 实现
- `autoplay` 重命名为 `autoplay`
- `initPage` 重命名为 `defaultValue`
- - `paginationVisible` 重命名为 `indicator`,类型改为` ReactNode`
+ - `paginationVisible` 重命名为 `indicator`,类型改为`ReactNode`
- `isPreventDefault` 重命名为 `preventDefault`
- `isStopPropagation` 重命名为 `stopPropagation`
- `isCenter` 重命名为 `center`
From a6c6a7a00639d6bd06f4a57da977b9a2610767a6 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Thu, 26 Dec 2024 11:28:35 +0800
Subject: [PATCH 09/14] fix: review
---
src/packages/sidebar/demo.taro.tsx | 5 +++++
src/packages/sidebar/demo.tsx | 5 +++++
src/packages/sidebar/demos/h5/demo6.tsx | 27 +++++++++++++++++++++++
src/packages/sidebar/demos/taro/demo6.tsx | 27 +++++++++++++++++++++++
src/packages/sidebar/doc.en-US.md | 1 +
src/packages/sidebar/doc.md | 1 +
src/packages/sidebar/doc.taro.md | 1 +
src/packages/sidebar/doc.zh-TW.md | 1 +
src/packages/sidebar/sidebar.scss | 1 +
src/styles/variables.scss | 1 +
10 files changed, 70 insertions(+)
create mode 100644 src/packages/sidebar/demos/h5/demo6.tsx
create mode 100644 src/packages/sidebar/demos/taro/demo6.tsx
diff --git a/src/packages/sidebar/demo.taro.tsx b/src/packages/sidebar/demo.taro.tsx
index 25a6a14c07..9b50b5b2e9 100644
--- a/src/packages/sidebar/demo.taro.tsx
+++ b/src/packages/sidebar/demo.taro.tsx
@@ -8,6 +8,7 @@ import Demo2 from './demos/taro/demo2'
import Demo3 from './demos/taro/demo3'
import Demo4 from './demos/taro/demo4'
import Demo5 from './demos/taro/demo5'
+import Demo6 from './demos/taro/demo6'
const TabsDemo = () => {
const [translated] = useTranslate({
@@ -17,6 +18,7 @@ const TabsDemo = () => {
matchByValue: '根据value匹配',
multiTitle: '多个标题',
setDuration: '设置滚动动画时长',
+ padding: '内容区域留白边距',
},
'en-US': {
basic: 'Basic Usage',
@@ -24,6 +26,7 @@ const TabsDemo = () => {
matchByValue: 'Match By Value',
multiTitle: 'Multiple Titles',
setDuration: 'Set Scroll Animation Duration',
+ padding: 'Set Content Padding',
},
})
@@ -43,6 +46,8 @@ const TabsDemo = () => {
{translated.setDuration}
+ {translated.padding}
+
>
)
diff --git a/src/packages/sidebar/demo.tsx b/src/packages/sidebar/demo.tsx
index df27900dcc..1c9d9d52a0 100644
--- a/src/packages/sidebar/demo.tsx
+++ b/src/packages/sidebar/demo.tsx
@@ -5,6 +5,7 @@ import Demo2 from './demos/h5/demo2'
import Demo3 from './demos/h5/demo3'
import Demo4 from './demos/h5/demo4'
import Demo5 from './demos/h5/demo5'
+import Demo6 from './demos/h5/demo6'
const SideNavBarDemo = () => {
const [translated] = useTranslate({
@@ -14,6 +15,7 @@ const SideNavBarDemo = () => {
matchByValue: '根据value匹配',
multiTitle: '多个标题',
setDuration: '设置滚动动画时长',
+ padding: '内容区域留白边距',
},
'en-US': {
basic: 'Basic Usage',
@@ -21,6 +23,7 @@ const SideNavBarDemo = () => {
matchByValue: 'Match By Value',
multiTitle: 'Multiple Titles',
setDuration: 'Set Scroll Animation Duration',
+ padding: 'Set Content Padding',
},
})
@@ -37,6 +40,8 @@ const SideNavBarDemo = () => {
{translated.setDuration}
+ {translated.padding}
+
>
)
diff --git a/src/packages/sidebar/demos/h5/demo6.tsx b/src/packages/sidebar/demos/h5/demo6.tsx
new file mode 100644
index 0000000000..3ce3a8b274
--- /dev/null
+++ b/src/packages/sidebar/demos/h5/demo6.tsx
@@ -0,0 +1,27 @@
+import React, { useState } from 'react'
+import { ConfigProvider, SideBar } from '@nutui/nutui-react'
+
+const Demo6 = () => {
+ const [value, setValue] = useState
('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+
+ )
+}
+export default Demo6
diff --git a/src/packages/sidebar/demos/taro/demo6.tsx b/src/packages/sidebar/demos/taro/demo6.tsx
new file mode 100644
index 0000000000..1062c6ca78
--- /dev/null
+++ b/src/packages/sidebar/demos/taro/demo6.tsx
@@ -0,0 +1,27 @@
+import React, { useState } from 'react'
+import { ConfigProvider, SideBar } from '@nutui/nutui-react-taro'
+
+const Demo6 = () => {
+ const [value, setValue] = useState('0')
+ const list = Array.from(new Array(3).keys())
+ return (
+
+ {
+ setValue(value)
+ }}
+ >
+ {list.map((item) => (
+
+ Content {item + 1}
+
+ ))}
+
+
+ )
+}
+export default Demo6
diff --git a/src/packages/sidebar/doc.en-US.md b/src/packages/sidebar/doc.en-US.md
index 62fcbe55d0..a3fc90f201 100644
--- a/src/packages/sidebar/doc.en-US.md
+++ b/src/packages/sidebar/doc.en-US.md
@@ -84,6 +84,7 @@ The component provides the following CSS variables, which can be used to customi
| \--nutui-sidebar-background-color | Sidebar navigation background color | `$color-background` |
| \--nutui-sidebar-border-radius | Rounded corners of the sidebar | `0` |
| \--nutui-sidebar-width | Sidebar width | `104px` |
+| \--nutui-sidebar-max-width | Sidebar max width | `128px` |
| \--nutui-sidebar-title-height | Sidebar title height | `52px` |
| \--nutui-sidebar-inactive-font-size | Font size in normal state | `$font-size-base` |
| \--nutui-sidebar-active-font-size | Font size in active state | `$font-size-l` |
diff --git a/src/packages/sidebar/doc.md b/src/packages/sidebar/doc.md
index 03facfb84c..6e720a5e82 100644
--- a/src/packages/sidebar/doc.md
+++ b/src/packages/sidebar/doc.md
@@ -84,6 +84,7 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-background-color | 侧边栏导航背景色 | `$color-background` |
| \--nutui-sidebar-border-radius | 侧边栏的圆角 | `0` |
| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
+| \--nutui-sidebar-max-width | 侧边栏最大宽度 | `128px` |
| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-l` |
diff --git a/src/packages/sidebar/doc.taro.md b/src/packages/sidebar/doc.taro.md
index 7de3f340c6..b51fbdf7b0 100644
--- a/src/packages/sidebar/doc.taro.md
+++ b/src/packages/sidebar/doc.taro.md
@@ -84,6 +84,7 @@ import { SideBar } from '@nutui/nutui-react-taro'
| \--nutui-sidebar-background-color | 侧边栏导航背景色 | `$color-background` |
| \--nutui-sidebar-border-radius | 侧边栏的圆角 | `0` |
| \--nutui-sidebar-width | 侧边栏宽度 | `104px` |
+| \--nutui-sidebar-max-width | 侧边栏最大宽度 | `128` |
| \--nutui-sidebar-title-height | 侧边栏标题高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通状态下的字体大小 | `$font-size-base` |
| \--nutui-sidebar-active-font-size | 激活状态下的字体大小 | `$font-size-l` |
diff --git a/src/packages/sidebar/doc.zh-TW.md b/src/packages/sidebar/doc.zh-TW.md
index 9ec14acc85..52cb9ed793 100644
--- a/src/packages/sidebar/doc.zh-TW.md
+++ b/src/packages/sidebar/doc.zh-TW.md
@@ -84,6 +84,7 @@ import { SideBar } from '@nutui/nutui-react'
| \--nutui-sidebar-background-color | 側邊欄導航背景色 | `$color-background` |
| \--nutui-sidebar-border-radius | 側邊欄的圓角 | `0` |
| \--nutui-sidebar-width | 側邊欄寬度 | `104px` |
+| \--nutui-sidebar-max-width | 側邊欄最大寬度 | `128px` |
| \--nutui-sidebar-title-height | 側邊欄標題高度 | `52px` |
| \--nutui-sidebar-inactive-font-size | 普通狀態下的字體大小 | `$font-size-base` |
| \--nutui-sidebar-active-font-size | 激活狀態下的字體大小 | `$font-size-l` |
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index 322802e7b8..747195cbb5 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -18,6 +18,7 @@
border-radius: $sidebar-border-radius;
height: 100%;
width: $sidebar-width;
+ max-width: $sidebar-max-width;
flex-shrink: 0;
&::-webkit-scrollbar {
display: none;
diff --git a/src/styles/variables.scss b/src/styles/variables.scss
index d4917ffc13..abfde7945b 100644
--- a/src/styles/variables.scss
+++ b/src/styles/variables.scss
@@ -2152,6 +2152,7 @@ $sidebar-background-color: var(
) !default;
$sidebar-border-radius: var(--nutui-sidebar-border-radius, 0) !default;
$sidebar-width: var(--nutui-sidebar-width, 104px) !default;
+$sidebar-max-width: var(--nutui-sidebar-max-width, 128px) !default;
$sidebar-title-height: var(--nutui-sidebar-title-height, 52px) !default;
$sidebar-inactive-font-size: var(
--nutui-sidebar-inactive-font-size,
From e737a7c4b77a7dcc06b62893edfcac60389ab3ca Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Fri, 27 Dec 2024 10:13:54 +0800
Subject: [PATCH 10/14] fix: support word wrap
---
src/packages/sidebar/sidebar.scss | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index 747195cbb5..446bc05da6 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -48,10 +48,9 @@
&-text {
font-family: PingFangSC-Regular;
text-align: center;
- text-overflow: ellipsis;
- white-space: nowrap;
- overflow: hidden;
+ white-space: normal;
color: $color-text;
+ width: $sidebar-width;
}
&-active .nut-sidebar-titles-item-text {
font-family: PingFangSC-Semibold;
From 928c72a0bd68ef662c0d087711f1cee86d22aa08 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Fri, 27 Dec 2024 10:23:32 +0800
Subject: [PATCH 11/14] fix: support word wrap
---
src/packages/sidebar/_test_/sidebar.spec.tsx | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/packages/sidebar/_test_/sidebar.spec.tsx b/src/packages/sidebar/_test_/sidebar.spec.tsx
index 104a1d6cf3..25462fd1f5 100644
--- a/src/packages/sidebar/_test_/sidebar.spec.tsx
+++ b/src/packages/sidebar/_test_/sidebar.spec.tsx
@@ -51,7 +51,7 @@ test('disabled option', async () => {
})
test('matchByValue', async () => {
const list1 = [
- { value: 'a', title: 'Opt a' },
+ { value: 'a', title: 'Opt a Opt a Opt a Opt a' },
{ value: 'b', title: 'Opt b' },
{ value: 'c', title: 'Opt c' },
]
From 8c77a94db46f28a72ddb5832732fa1cd3bb0c58d Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Fri, 27 Dec 2024 15:52:37 +0800
Subject: [PATCH 12/14] fix: disabled
---
src/packages/sidebar/sidebar.scss | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index 446bc05da6..495651c855 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -43,13 +43,11 @@
justify-content: center;
height: $sidebar-title-height;
margin: 0;
- flex: none;
font-size: $sidebar-inactive-font-size;
+ color: $color-text;
&-text {
- font-family: PingFangSC-Regular;
text-align: center;
white-space: normal;
- color: $color-text;
width: $sidebar-width;
}
&-active .nut-sidebar-titles-item-text {
From e30d95fed9a3471346d0bd76df33942bc1159ec4 Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Fri, 27 Dec 2024 16:00:39 +0800
Subject: [PATCH 13/14] fix: make css easier
---
src/packages/sidebar/sidebar.scss | 3 ---
1 file changed, 3 deletions(-)
diff --git a/src/packages/sidebar/sidebar.scss b/src/packages/sidebar/sidebar.scss
index 495651c855..257bc57e72 100644
--- a/src/packages/sidebar/sidebar.scss
+++ b/src/packages/sidebar/sidebar.scss
@@ -13,7 +13,6 @@
}
&-titles {
background: $sidebar-background-color;
- box-sizing: border-box;
flex-direction: column;
border-radius: $sidebar-border-radius;
height: 100%;
@@ -37,12 +36,10 @@
}
&-item {
cursor: pointer;
- position: relative;
display: flex;
align-items: center;
justify-content: center;
height: $sidebar-title-height;
- margin: 0;
font-size: $sidebar-inactive-font-size;
color: $color-text;
&-text {
From 846e4c7afaaf1ec45e3ee3a0caf14c03b6d5432f Mon Sep 17 00:00:00 2001
From: "Alex.hxy" <1872591453@qq.com>
Date: Fri, 27 Dec 2024 17:15:29 +0800
Subject: [PATCH 14/14] fix: adjust some doc details
---
migrate-from-v2.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/migrate-from-v2.md b/migrate-from-v2.md
index f9d3077a37..1b596afe63 100644
--- a/migrate-from-v2.md
+++ b/migrate-from-v2.md
@@ -607,7 +607,7 @@ plugins: [
- 移除 `isAsync`,通过 `checked`实现
- 移除 `activeColor` ,通过css变量`--nutui-switch-open-background-color`实现
- 移除 `inactiveColor`,通过css变量`--nutui-switch-close-background-color`实现
-- `activeText 属性类型更改为`ReactNode`
+- `activeText` 属性类型更改为`ReactNode`
- `inactiveText` 属性类型更改为 `ReactNode`
#### Toast