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} > -
+
{item.title}
@@ -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