From 71a5a15fbc125c3aa559e9e78a85a6d1530c8b6c Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Wed, 17 Jun 2026 16:32:32 +0800 Subject: [PATCH 1/6] =?UTF-8?q?refactor(Rate):=20v16=E9=80=82=E9=85=8D=20-?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9Elayout/label=E5=B1=9E=E6=80=A7=EF=BC=8C?= =?UTF-8?q?=E9=87=8D=E6=9E=84=E5=B0=BA=E5=AF=B8=E4=BD=93=E7=B3=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 layout 属性支持水平/垂直两种布局 - 新增 label 属性支持标签文字,支持 ReactNode | ReactNode[] 实现每颗星独立标签 - 水平布局适配 12DP/16DP/20DP 三种尺寸 - 垂直布局适配 20DP/28DP 尺寸,大尺寸支持 flex 均分布局 - 12DP 星间距调整为 2px - 星星外层新增 .nut-rate-list 容器 - 补充垂直布局、带标签 demo 及文档 - 新增 layout/label/array-label 相关单测 Co-Authored-By: Claude Opus 4.6 (1M context) --- .../__test__/__snapshots__/rate.spec.tsx.snap | 28 +- src/packages/rate/__test__/rate.spec.tsx | 67 +++- src/packages/rate/demo.taro.tsx | 18 ++ src/packages/rate/demo.tsx | 18 ++ src/packages/rate/demos/h5/demo1.tsx | 4 +- src/packages/rate/demos/h5/demo13.tsx | 21 ++ src/packages/rate/demos/h5/demo14.tsx | 19 ++ src/packages/rate/demos/h5/demo9.tsx | 9 +- src/packages/rate/demos/taro/demo1.tsx | 4 +- src/packages/rate/demos/taro/demo13.tsx | 21 ++ src/packages/rate/demos/taro/demo14.tsx | 19 ++ src/packages/rate/demos/taro/demo9.tsx | 9 +- src/packages/rate/doc.en-US.md | 23 +- src/packages/rate/doc.md | 21 +- src/packages/rate/doc.taro.md | 23 +- src/packages/rate/doc.zh-TW.md | 23 +- src/packages/rate/index.taro.ts | 2 +- src/packages/rate/index.ts | 2 +- src/packages/rate/rate.scss | 304 +++++++++++++----- src/packages/rate/rate.taro.tsx | 127 +++++--- src/packages/rate/rate.tsx | 127 +++++--- src/styles/variables.scss | 7 +- src/types/spec/rate/base.ts | 3 + 23 files changed, 712 insertions(+), 187 deletions(-) create mode 100644 src/packages/rate/demos/h5/demo13.tsx create mode 100644 src/packages/rate/demos/h5/demo14.tsx create mode 100644 src/packages/rate/demos/taro/demo13.tsx create mode 100644 src/packages/rate/demos/taro/demo14.tsx diff --git a/src/packages/rate/__test__/__snapshots__/rate.spec.tsx.snap b/src/packages/rate/__test__/__snapshots__/rate.spec.tsx.snap index ff28a24779..2c1762cc6b 100644 --- a/src/packages/rate/__test__/__snapshots__/rate.spec.tsx.snap +++ b/src/packages/rate/__test__/__snapshots__/rate.spec.tsx.snap @@ -3,24 +3,28 @@ exports[`size test 1`] = `
- - - + + + +
diff --git a/src/packages/rate/__test__/rate.spec.tsx b/src/packages/rate/__test__/rate.spec.tsx index 7fecf8af7c..8d2b8c744a 100644 --- a/src/packages/rate/__test__/rate.spec.tsx +++ b/src/packages/rate/__test__/rate.spec.tsx @@ -33,17 +33,17 @@ test('props test', () => { ) } - const { getByTestId, container } = render() + const { container } = render() const valueEl = container.querySelector('.score') const el = container.querySelectorAll('.nut-rate-item') if (el && valueEl) { - expect(el.length).toBe(state.count) // count - expect(el[2].childNodes[0]).toHaveClass('nut-rate-item-icon') // active + expect(el.length).toBe(state.count) + expect(el[2].childNodes[0]).toHaveClass('nut-rate-item-icon') expect(el[2].childNodes[0].childNodes[0]).toHaveClass('nut-icon-HeartFill') - expect(el[3].childNodes[0]).toHaveClass('nut-rate-item-icon-disabled') // disabled + expect(el[3].childNodes[0]).toHaveClass('nut-rate-item-icon-disabled') expect(el[3].childNodes[0].childNodes[0]).toHaveClass('nut-icon-Heart') fireEvent.click(el[1]) - expect(valueEl.innerHTML).toBe('2') // onChange + expect(valueEl.innerHTML).toBe('2') } }) @@ -74,6 +74,7 @@ test('allowHalf test', () => { ) } }) + test('size test', () => { const { container } = render() const el = container.querySelector('.nut-rate-item') @@ -91,6 +92,62 @@ test('showScore test', () => { } }) +test('layout horizontal test', () => { + const { container } = render() + const root = container.querySelector('.nut-rate') + expect(root).toHaveClass('nut-rate-horizontal') + expect(container.querySelector('.nut-rate-list')).toBeTruthy() +}) + +test('layout vertical test', () => { + const { container } = render() + const root = container.querySelector('.nut-rate') + expect(root).toHaveClass('nut-rate-vertical') +}) + +test('label test horizontal', () => { + const { container } = render( + + ) + const label = container.querySelector('.nut-rate-label') + expect(label).toBeTruthy() + expect(label?.innerHTML).toBe('评分') + const root = container.querySelector('.nut-rate') + const list = container.querySelector('.nut-rate-list') + if (root && label && list) { + const children = Array.from(root.children) + expect(children.indexOf(label)).toBeLessThan(children.indexOf(list)) + } +}) + +test('label test vertical', () => { + const { container } = render( + + ) + const label = container.querySelector('.nut-rate-label') + expect(label).toBeTruthy() + expect(label?.innerHTML).toBe('非常满意') + const root = container.querySelector('.nut-rate') + const list = container.querySelector('.nut-rate-list') + if (root && label && list) { + const children = Array.from(root.children) + expect(children.indexOf(label)).toBeGreaterThan(children.indexOf(list)) + } +}) + +test('array label test vertical', () => { + const labels = ['不满意', '', '', '', '非常满意'] + const { container } = render( + + ) + const labelsRow = container.querySelector('.nut-rate-labels') + expect(labelsRow).toBeTruthy() + const items = container.querySelectorAll('.nut-rate-labels-item') + expect(items.length).toBe(5) + expect(items[0].innerHTML).toBe('不满意') + expect(items[4].innerHTML).toBe('非常满意') +}) + test('touchable', () => { const state = { count: 5, diff --git a/src/packages/rate/demo.taro.tsx b/src/packages/rate/demo.taro.tsx index 0c73c8d9a9..f13e997f8a 100644 --- a/src/packages/rate/demo.taro.tsx +++ b/src/packages/rate/demo.taro.tsx @@ -16,6 +16,8 @@ import Demo9 from './demos/taro/demo9' import Demo10 from './demos/taro/demo10' import Demo11 from './demos/taro/demo11' import Demo12 from './demos/taro/demo12' +import Demo13 from './demos/taro/demo13' +import Demo14 from './demos/taro/demo14' const RateDemo = () => { const [translated] = useTranslate({ @@ -32,6 +34,8 @@ const RateDemo = () => { event: '绑定事件', touchable: '滑动选择', touchend: '滑动事件', + verticalLayout: '上下布局', + withLabel: '带标签', }, 'zh-TW': { basic: '基礎用法', @@ -46,6 +50,8 @@ const RateDemo = () => { event: '綁定事件', touchable: '滑動選擇', touchend: '滑動事件', + verticalLayout: '上下佈局', + withLabel: '帶標籤', }, 'en-US': { basic: 'Basic Usage', @@ -60,6 +66,8 @@ const RateDemo = () => { event: 'Event', touchable: 'Touch to Select', touchend: 'Touch Event', + verticalLayout: 'Vertical Layout', + withLabel: 'With Label', }, }) const cellStyle: CSSProperties = { @@ -133,6 +141,16 @@ const RateDemo = () => { )} + + {translated.verticalLayout} + + + + + {translated.withLabel} + + + ) diff --git a/src/packages/rate/demo.tsx b/src/packages/rate/demo.tsx index 359adb703a..9d68f4b6e9 100644 --- a/src/packages/rate/demo.tsx +++ b/src/packages/rate/demo.tsx @@ -13,6 +13,8 @@ import Demo9 from './demos/h5/demo9' import Demo10 from './demos/h5/demo10' import Demo11 from './demos/h5/demo11' import Demo12 from './demos/h5/demo12' +import Demo13 from './demos/h5/demo13' +import Demo14 from './demos/h5/demo14' const RateDemo = () => { const [translated] = useTranslate({ @@ -29,6 +31,8 @@ const RateDemo = () => { event: '绑定事件', touchable: '滑动选择', touchevent: '滑动事件', + verticalLayout: '上下布局', + withLabel: '带标签', }, 'zh-TW': { basic: '基礎用法', @@ -43,6 +47,8 @@ const RateDemo = () => { event: '綁定事件', touchable: '滑動選擇', touchevent: '滑動事件', + verticalLayout: '上下佈局', + withLabel: '帶標籤', }, 'en-US': { basic: 'Basic Usage', @@ -57,6 +63,8 @@ const RateDemo = () => { event: 'Event', touchable: 'Touch to Select', touchevent: 'Touch Event', + verticalLayout: 'Vertical Layout', + withLabel: 'With Label', }, }) const cellStyle: CSSProperties = { @@ -126,6 +134,16 @@ const RateDemo = () => { + +

{translated.verticalLayout}

+ + + + +

{translated.withLabel}

+ + + ) diff --git a/src/packages/rate/demos/h5/demo1.tsx b/src/packages/rate/demos/h5/demo1.tsx index cdb18fbbbf..a297cab8f9 100644 --- a/src/packages/rate/demos/h5/demo1.tsx +++ b/src/packages/rate/demos/h5/demo1.tsx @@ -4,9 +4,9 @@ import { Rate, Space } from '@nutui/nutui-react' const Demo1 = () => { return ( - - + + ) } diff --git a/src/packages/rate/demos/h5/demo13.tsx b/src/packages/rate/demos/h5/demo13.tsx new file mode 100644 index 0000000000..93b6980477 --- /dev/null +++ b/src/packages/rate/demos/h5/demo13.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react' + +const Demo13 = () => { + return ( + + + + + ) +} +export default Demo13 diff --git a/src/packages/rate/demos/h5/demo14.tsx b/src/packages/rate/demos/h5/demo14.tsx new file mode 100644 index 0000000000..56c49510f0 --- /dev/null +++ b/src/packages/rate/demos/h5/demo14.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react' + +const Demo14 = () => { + return ( + + + + + + + ) +} +export default Demo14 diff --git a/src/packages/rate/demos/h5/demo9.tsx b/src/packages/rate/demos/h5/demo9.tsx index 3ba626cf83..439cfb0da1 100644 --- a/src/packages/rate/demos/h5/demo9.tsx +++ b/src/packages/rate/demos/h5/demo9.tsx @@ -1,7 +1,12 @@ import React from 'react' -import { Rate } from '@nutui/nutui-react' +import { Rate, Space } from '@nutui/nutui-react' const Demo9 = () => { - return + return ( + + + + + ) } export default Demo9 diff --git a/src/packages/rate/demos/taro/demo1.tsx b/src/packages/rate/demos/taro/demo1.tsx index 20f6942736..509f05488b 100644 --- a/src/packages/rate/demos/taro/demo1.tsx +++ b/src/packages/rate/demos/taro/demo1.tsx @@ -4,9 +4,9 @@ import { Rate, Space } from '@nutui/nutui-react-taro' const Demo1 = () => { return ( - - + + ) } diff --git a/src/packages/rate/demos/taro/demo13.tsx b/src/packages/rate/demos/taro/demo13.tsx new file mode 100644 index 0000000000..f37ff345e2 --- /dev/null +++ b/src/packages/rate/demos/taro/demo13.tsx @@ -0,0 +1,21 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react-taro' + +const Demo13 = () => { + return ( + + + + + ) +} +export default Demo13 diff --git a/src/packages/rate/demos/taro/demo14.tsx b/src/packages/rate/demos/taro/demo14.tsx new file mode 100644 index 0000000000..59c3ffc030 --- /dev/null +++ b/src/packages/rate/demos/taro/demo14.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react-taro' + +const Demo14 = () => { + return ( + + + + + + + ) +} +export default Demo14 diff --git a/src/packages/rate/demos/taro/demo9.tsx b/src/packages/rate/demos/taro/demo9.tsx index a3ecdd1088..e037f0842d 100644 --- a/src/packages/rate/demos/taro/demo9.tsx +++ b/src/packages/rate/demos/taro/demo9.tsx @@ -1,7 +1,12 @@ import React from 'react' -import { Rate } from '@nutui/nutui-react-taro' +import { Rate, Space } from '@nutui/nutui-react-taro' const Demo9 = () => { - return + return ( + + + + + ) } export default Demo9 diff --git a/src/packages/rate/doc.en-US.md b/src/packages/rate/doc.en-US.md index 029e68a4fa..52d8f0bb3d 100644 --- a/src/packages/rate/doc.en-US.md +++ b/src/packages/rate/doc.en-US.md @@ -106,6 +106,22 @@ import { Rate } from '@nutui/nutui-react' ::: +### Vertical Layout + +:::demo + + + +::: + +### With Label + +:::demo + + + +::: + ## Rate ### Props @@ -113,6 +129,8 @@ import { Rate } from '@nutui/nutui-react' | Property | Description | Type | Default | | --- | --- | --- | --- | | size | Score size | `large` \| `normal` \| `small` | `normal` | +| layout | Layout type | `horizontal` \| `vertical` | `horizontal` | +| label | Label text | `ReactNode` | `-` | | showScore | Show Score | `boolean` | `false` | | defaultValue | Uncontrolled star value | `number` | `0` | | value | Controlled star value | `number` | `0` | @@ -123,7 +141,7 @@ import { Rate } from '@nutui/nutui-react' | allowHalf | Half star or not | `boolean` | `false` | | readOnly | Read only | `boolean` | `false` | | disabled | Disable or not | `boolean` | `false` | -| touchable | Enable touch to select | `boolean` | `false` | +| touchable | Enable touch to select | `boolean` | `false` | | onChange | Event triggered when the current score is modified | `(value: number) => void` | `-` | | onTouchEnd | Event triggered when touch end | `(event: TouchEvent, value: number) => void` | `-` | @@ -138,8 +156,9 @@ The component provides the following CSS variables, which can be used to customi | \--nutui-rate-item-margin | spacing | `4px` | | \--nutui-rate-icon-color | icon activation color | `$color-primary-icon` | | \--nutui-rate-icon-inactive-color | icon inactive color | `$color-primary-icon-disabled` | -| \--nutui-rate-icon-size | icon size | `12px` | +| \--nutui-rate-icon-size | icon size | `16px` | | \--nutui-rate-font-color | Rating font color | `$color-primary-icon` | | \--nutui-rate-font-size | Rating font size | `12px` | +| \--nutui-rate-label-color | Label font color | `$color-text-disabled` | diff --git a/src/packages/rate/doc.md b/src/packages/rate/doc.md index c058dbb949..96e4072311 100644 --- a/src/packages/rate/doc.md +++ b/src/packages/rate/doc.md @@ -106,6 +106,22 @@ import { Rate } from '@nutui/nutui-react' ::: +### 上下布局 + +:::demo + + + +::: + +### 带标签 + +:::demo + + + +::: + ## Rate ### Props @@ -113,6 +129,8 @@ import { Rate } from '@nutui/nutui-react' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | +| layout | 布局方式 | `horizontal` \| `vertical` | `horizontal` | +| label | 标签文字 | `ReactNode` | `-` | | showScore | 展示评分 | `boolean` | `false` | | defaultValue | 非受控的 star 默认值 | `number` | `0` | | value | 受控的 star 数值 | `number` | `0` | @@ -138,8 +156,9 @@ import { Rate } from '@nutui/nutui-react' | \--nutui-rate-item-margin | 间距 | `4px` | | \--nutui-rate-icon-color | icon 激活颜色 | `$color-primary-icon` | | \--nutui-rate-icon-inactive-color | icon 未激活颜色 | `$color-primary-icon-disabled` | -| \--nutui-rate-icon-size | icon 尺寸 | `12px` | +| \--nutui-rate-icon-size | icon 尺寸 | `16px` | | \--nutui-rate-font-color | 评分字体颜色 | `$color-primary-icon` | | \--nutui-rate-font-size | 评分字体大小 | `12px` | +| \--nutui-rate-label-color | 标签字体颜色 | `$color-text-disabled` | diff --git a/src/packages/rate/doc.taro.md b/src/packages/rate/doc.taro.md index 5693c71d87..84eac8cd3f 100644 --- a/src/packages/rate/doc.taro.md +++ b/src/packages/rate/doc.taro.md @@ -106,6 +106,22 @@ import { Rate } from '@nutui/nutui-react-taro' ::: +### 上下布局 + +:::demo + + + +::: + +### 带标签 + +:::demo + + + +::: + ## Rate ### Props @@ -113,6 +129,8 @@ import { Rate } from '@nutui/nutui-react-taro' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | +| layout | 布局方式 | `horizontal` \| `vertical` | `horizontal` | +| label | 标签文字 | `ReactNode` | `-` | | showScore | 展示评分 | `boolean` | `false` | | defaultValue | 非受控的 star 默认值 | `number` | `0` | | value | 受控的 star 数值 | `number` | `0` | @@ -123,7 +141,7 @@ import { Rate } from '@nutui/nutui-react-taro' | allowHalf | 是否半星 | `boolean` | `false` | | readOnly | 是否只读 | `boolean` | `false` | | disabled | 是否禁用 | `boolean` | `false` | -| touchable | 是否允许滑动选择 | `boolean` | `false` | +| touchable | 是否允许滑动选择 | `boolean` | `false` | | onChange | 当前 star 数修改时触发 | `(value: number) => void` | `-` | | onTouchEnd | touch 滑动结束时触发 | `(event: TouchEvent, value: number) => void` | `-` | @@ -138,8 +156,9 @@ import { Rate } from '@nutui/nutui-react-taro' | \--nutui-rate-item-margin | 间距 | `4px` | | \--nutui-rate-icon-color | icon 激活颜色 | `$color-primary-icon` | | \--nutui-rate-icon-inactive-color | icon 未激活颜色 | `$color-primary-icon-disabled` | -| \--nutui-rate-icon-size | icon 尺寸 | `12px` | +| \--nutui-rate-icon-size | icon 尺寸 | `16px` | | \--nutui-rate-font-color | 评分字体颜色 | `$color-primary-icon` | | \--nutui-rate-font-size | 评分字体大小 | `12px` | +| \--nutui-rate-label-color | 标签字体颜色 | `$color-text-disabled` | diff --git a/src/packages/rate/doc.zh-TW.md b/src/packages/rate/doc.zh-TW.md index 67b7d6690f..68af471020 100644 --- a/src/packages/rate/doc.zh-TW.md +++ b/src/packages/rate/doc.zh-TW.md @@ -106,6 +106,22 @@ import { Rate } from '@nutui/nutui-react' ::: +### 上下佈局 + +:::demo + + + +::: + +### 帶標籤 + +:::demo + + + +::: + ## Rate ### Props @@ -113,6 +129,8 @@ import { Rate } from '@nutui/nutui-react' | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | +| layout | 佈局方式 | `horizontal` \| `vertical` | `horizontal` | +| label | 標籤文字 | `ReactNode` | `-` | | showScore | 展示評分 | `boolean` | `false` | | defaultValue | 非受控的 star 默認值 | `number` | `0` | | value | 受控的 star 數值 | `number` | `0` | @@ -123,7 +141,7 @@ import { Rate } from '@nutui/nutui-react' | allowHalf | 是否半星 | `boolean` | `false` | | readOnly | 是否只讀 | `boolean` | `false` | | disabled | 是否禁用 | `boolean` | `false` | -| touchable | 是否允許滑動選擇 | `boolean` | `false` | +| touchable | 是否允許滑動選擇 | `boolean` | `false` | | onChange | 當前 star 數修改時觸發 | `(value: number) => void` | `-` | | onTouchEnd | touch 滑動結束時觸發 | `(event: TouchEvent, value: number) => void` | `-` | @@ -138,8 +156,9 @@ import { Rate } from '@nutui/nutui-react' | \--nutui-rate-item-margin | 間距 | `4px` | | \--nutui-rate-icon-color | icon 激活顏色 | `$color-primary-icon` | | \--nutui-rate-icon-inactive-color | icon 未激活顏色 | `$color-primary-icon-disabled` | -| \--nutui-rate-icon-size | icon 尺寸 | `12px` | +| \--nutui-rate-icon-size | icon 尺寸 | `16px` | | \--nutui-rate-font-color | 評分字體顏色 | `$color-primary-icon` | | \--nutui-rate-font-size | 評分字體大小 | `12px` | +| \--nutui-rate-label-color | 標籤字體顏色 | `$color-text-disabled` | diff --git a/src/packages/rate/index.taro.ts b/src/packages/rate/index.taro.ts index add93669a6..37ba8dd971 100644 --- a/src/packages/rate/index.taro.ts +++ b/src/packages/rate/index.taro.ts @@ -1,4 +1,4 @@ import { Rate } from './rate.taro' -export type { RateSize, TaroRateProps as RateProps } from '@/types' +export type { RateSize, RateLayout, TaroRateProps as RateProps } from '@/types' export default Rate diff --git a/src/packages/rate/index.ts b/src/packages/rate/index.ts index bd6cbd9157..b1ff03ed64 100644 --- a/src/packages/rate/index.ts +++ b/src/packages/rate/index.ts @@ -1,4 +1,4 @@ import { Rate } from './rate' -export type { RateSize, WebRateProps as RateProps } from '@/types' +export type { RateSize, RateLayout, WebRateProps as RateProps } from '@/types' export default Rate diff --git a/src/packages/rate/rate.scss b/src/packages/rate/rate.scss index 319f5d60da..f05dbe24e0 100644 --- a/src/packages/rate/rate.scss +++ b/src/packages/rate/rate.scss @@ -14,6 +14,37 @@ } } + &-horizontal { + flex-direction: row; + align-items: center; + } + + &-vertical { + flex-direction: column; + align-items: center; + } + + &-list { + display: flex; + align-items: center; + } + + &-label { + color: $rate-label-color; + white-space: nowrap; + } + + &-labels { + display: flex; + width: 100%; + + &-item { + flex: 1; + text-align: center; + color: $rate-label-color; + } + } + &-item { display: flex; align-items: center; @@ -33,38 +64,6 @@ } } - &-normal { - margin-left: $rate-item-margin; - .nut-icon { - height: $rate-icon-size; - width: $rate-icon-size; - } - } - - &-large { - margin-left: calc($rate-item-margin * 2); - .nut-icon { - height: calc($rate-icon-size + 8px); - width: calc($rate-icon-size + 8px); - } - } - - &-small { - margin-left: calc($rate-item-margin / 2); - .nut-icon { - height: calc($rate-icon-size - 4px); - width: calc($rate-icon-size - 4px); - } - } - - &-normal, - &-large, - &-small { - &:first-child { - margin-left: 0; - } - } - &-icon { display: flex; align-items: center; @@ -107,85 +106,238 @@ color: $rate-font-color; font-family: 'JDZH-Regular'; - &-normal { - padding-left: $rate-item-margin; - font-size: $rate-font-size; + &-disabled { + color: $rate-icon-inactive-color; + } + } + + // horizontal layout + &-horizontal { + .nut-rate-item { + margin-left: $rate-item-margin; + &:first-child { + margin-left: 0; + } + } + + // 12DP - star gap 2px + .nut-rate-item-small { + margin-left: scale-px(2px); + &:first-child { + margin-left: 0; + } + .nut-icon { + height: scale-font-px(12px); + width: scale-font-px(12px); + } + } + + .nut-rate-item-normal { + .nut-icon { + height: scale-font-px(16px); + width: scale-font-px(16px); + } + } + + .nut-rate-item-large { + .nut-icon { + height: scale-font-px(20px); + width: scale-font-px(20px); + } + } + + .nut-rate-label-small { + font-size: $font-size-s; + margin-right: scale-px(4px); + } + + .nut-rate-label-normal { + font-size: $font-size-s; + margin-right: scale-px(12px); + } + + .nut-rate-label-large { + font-size: $font-size-base; + margin-right: scale-px(12px); + } + + .nut-rate-score-small { + padding-left: scale-px(4px); + font-size: $font-size-s; line-height: $line-height-s; } - &-large { - font-size: $rate-font-size-large; - line-height: $line-height-xl; - padding-left: calc($rate-item-margin * 2); + .nut-rate-score-normal { + padding-left: scale-px(12px); + font-size: $font-size-s; + line-height: $line-height-s; } - &-small { - font-size: $rate-font-size-small; - line-height: $line-height-xxs; - padding-left: calc($rate-item-margin / 2); + .nut-rate-score-large { + padding-left: scale-px(12px); + font-size: $font-size-base; + line-height: $line-height-base; } + } - &-disabled { - color: $rate-icon-inactive-color; + // vertical layout + &-vertical { + .nut-rate-list { + justify-content: center; + width: 100%; + } + + .nut-rate-item { + margin-left: $rate-item-margin; + &:first-child { + margin-left: 0; + } + } + + .nut-rate-item-small, + .nut-rate-item-normal { + .nut-icon { + height: scale-font-px(20px); + width: scale-font-px(20px); + } + } + + .nut-rate-item-large { + flex: 1; + justify-content: center; + + .nut-icon { + height: scale-font-px(28px); + width: scale-font-px(28px); + } + } + + .nut-rate-label-small, + .nut-rate-label-normal { + font-size: $font-size-xs; + margin-top: scale-px(6px); + } + + .nut-rate-label-large { + font-size: $font-size-s; + margin-top: scale-px(8px); + } + + .nut-rate-labels { + width: 100%; + } + + .nut-rate-labels-small, + .nut-rate-labels-normal { + margin-top: scale-px(6px); + + .nut-rate-labels-item { + font-size: $font-size-xs; + } + } + + .nut-rate-labels-large { + margin-top: scale-px(8px); + + .nut-rate-labels-item { + font-size: $font-size-s; + } + } + + .nut-rate-score-small, + .nut-rate-score-normal { + font-size: $font-size-xs; + line-height: $line-height-xs; + margin-top: scale-px(6px); + } + + .nut-rate-score-large { + font-size: $font-size-s; + line-height: $line-height-s; + margin-top: scale-px(8px); } } } [dir='rtl'] .nut-rate, .nut-rtl .nut-rate { - &-item { - margin-left: 0; - &:first-child { + &-horizontal { + .nut-rate-item { + margin-left: 0; + margin-right: $rate-item-margin; + + &:first-child { + margin-right: 0; + } + } + + .nut-rate-item-small { + margin-left: 0; + margin-right: scale-px(2px); + + &:first-child { + margin-right: 0; + } + } + + .nut-rate-label { margin-right: 0; } - &-normal { - margin-right: $rate-item-margin; + .nut-rate-label-small { + margin-left: scale-px(4px); } - &-large { - margin-right: calc($rate-item-margin * 2); + .nut-rate-label-normal { + margin-left: scale-px(12px); } - &-small { - margin-right: calc($rate-item-margin - 2px); + .nut-rate-label-large { + margin-left: scale-px(12px); } - &:last-child { - margin-left: 0; + .nut-rate-score { + padding-left: 0; } - &-half { - left: auto; - right: 0; + .nut-rate-score-small { + padding-right: scale-px(4px); } - &-icon { - &.nut-rate-item-icon.nut-rate-item-icon-half { - left: auto; - right: 0; - } + .nut-rate-score-normal { + padding-right: scale-px(12px); + } - &.nut-rate-item-icon::before { - left: auto; - right: auto; - } + .nut-rate-score-large { + padding-right: scale-px(12px); } } - &-score { - padding-left: 0; + &-vertical { + .nut-rate-item { + margin-left: 0; + margin-right: $rate-item-margin; - &-large { - padding-right: calc($rate-item-margin * 2); + &:first-child { + margin-right: 0; + } } + } + + &-item-half { + left: auto; + right: 0; + } - &-normal { - padding-right: $rate-item-margin; + &-item-icon { + &.nut-rate-item-icon.nut-rate-item-icon-half { + left: auto; + right: 0; } - &-small { - padding-right: calc($rate-item-margin - 2px); + &.nut-rate-item-icon::before { + left: auto; + right: auto; } } } diff --git a/src/packages/rate/rate.taro.tsx b/src/packages/rate/rate.taro.tsx index 000c68f296..ca3beeec46 100644 --- a/src/packages/rate/rate.taro.tsx +++ b/src/packages/rate/rate.taro.tsx @@ -1,6 +1,7 @@ import React, { FunctionComponent, ReactElement, + ReactNode, useCallback, useEffect, useLayoutEffect, @@ -19,6 +20,7 @@ import { TaroRateProps } from '@/types' const defaultProps = { ...ComponentDefaults, size: 'normal', + layout: 'horizontal', showScore: false, count: 5, min: 0, @@ -34,6 +36,8 @@ export const Rate: FunctionComponent> = (props) => { className, style, size, + layout, + label, showScore, count, value, @@ -187,10 +191,62 @@ export const Rate: FunctionComponent> = (props) => { } } + const isArrayLabel = Array.isArray(label) + + const renderSingleLabel = () => { + if (label == null || isArrayLabel) return null + return ( + + {label} + + ) + } + + const renderArrayLabels = () => { + if (!isArrayLabel) return null + return ( + + {(label as ReactNode[]).map((item, index) => ( + + {item} + + ))} + + ) + } + + const renderScore = () => { + if (!showScore) return null + return ( + + {score.toFixed(1)} + + ) + } + return ( > = (props) => { onTouchEnd={handleTouchEnd} onTouchCancel={handleTouchEnd} > - {countArray.map((n, index) => { - return ( - onClick(event, n)} - > + {layout === 'horizontal' && renderSingleLabel()} + + {countArray.map((n, index) => { + return ( score, - })} + className={`${classPrefix}-item ${classPrefix}-item-${size}`} + key={n} + ref={setRefs(index)} + onClick={(event) => onClick(event, n)} > - {renderIcon(n)} - - {allowHalf && score > n - 1 && ( onHalfClick(event, n)} + className={classNames(`${classPrefix}-item-icon`, { + [`${classPrefix}-item-icon-disabled`]: disabled || n > score, + })} > {renderIcon(n)} - )} - - ) - })} - {showScore ? ( - - {score.toFixed(1)} - - ) : null} + {allowHalf && score > n - 1 && ( + onHalfClick(event, n)} + > + {renderIcon(n)} + + )} + + ) + })} + + {layout === 'horizontal' && renderScore()} + {layout === 'vertical' && ( + <> + {renderScore()} + {isArrayLabel ? renderArrayLabels() : renderSingleLabel()} + + )} ) } diff --git a/src/packages/rate/rate.tsx b/src/packages/rate/rate.tsx index 3b503cfee2..fb7573000f 100644 --- a/src/packages/rate/rate.tsx +++ b/src/packages/rate/rate.tsx @@ -1,6 +1,7 @@ import React, { FunctionComponent, ReactElement, + ReactNode, useEffect, useRef, useState, @@ -16,6 +17,7 @@ import { WebRateProps } from '@/types' const defaultProps = { ...ComponentDefaults, size: 'normal', + layout: 'horizontal', showScore: false, count: 5, min: 0, @@ -31,6 +33,8 @@ export const Rate: FunctionComponent> = (props) => { className, style, size, + layout, + label, showScore, count, value, @@ -193,10 +197,62 @@ export const Rate: FunctionComponent> = (props) => { } }, []) + const isArrayLabel = Array.isArray(label) + + const renderSingleLabel = () => { + if (label == null || isArrayLabel) return null + return ( + + {label} + + ) + } + + const renderArrayLabels = () => { + if (!isArrayLabel) return null + return ( +
+ {(label as ReactNode[]).map((item, index) => ( + + {item} + + ))} +
+ ) + } + + const renderScore = () => { + if (!showScore) return null + return ( + + {score.toFixed(1)} + + ) + } + return (
> = (props) => { ref={rateRef} style={style} > - {countArray.map((n, index) => { - return ( -
onClick(event, n)} - > + {layout === 'horizontal' && renderSingleLabel()} +
+ {countArray.map((n, index) => { + return (
score, - })} + className={`${classPrefix}-item ${classPrefix}-item-${size}`} + key={n} + ref={setRefs(index)} + onClick={(event) => onClick(event, n)} > - {renderIcon(n)} -
- {allowHalf && score > n - 1 && (
onHalfClick(event, n)} + className={classNames(`${classPrefix}-item-icon`, { + [`${classPrefix}-item-icon-disabled`]: disabled || n > score, + })} > {renderIcon(n)}
- )} -
- ) - })} - {showScore ? ( - - {score.toFixed(1)} - - ) : null} + {allowHalf && score > n - 1 && ( +
onHalfClick(event, n)} + > + {renderIcon(n)} +
+ )} +
+ ) + })} +
+ {layout === 'horizontal' && renderScore()} + {layout === 'vertical' && ( + <> + {renderScore()} + {isArrayLabel ? renderArrayLabels() : renderSingleLabel()} + + )} ) } diff --git a/src/styles/variables.scss b/src/styles/variables.scss index fecc48c7b4..1ad90e86f2 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1261,11 +1261,12 @@ $rate-icon-inactive-color: var( --nutui-rate-icon-inactive-color, $color-primary-icon-disabled ) !default; -$rate-icon-size: var(--nutui-rate-icon-size, scale-font-px(12px)) !default; +$rate-icon-size: var(--nutui-rate-icon-size, scale-font-px(16px)) !default; $rate-font-color: var(--nutui-rate-font-color, $color-primary-icon) !default; $rate-font-size: var(--nutui-rate-font-size, $font-size-s) !default; -$rate-font-size-large: var(--nutui-rate-font-size-large, calc($rate-font-size + scale-font-px(6px))) !default; -$rate-font-size-small: var(--nutui-rate-font-size-small, calc($rate-font-size - scale-font-px(2px))) !default; +$rate-font-size-large: var(--nutui-rate-font-size-large, $font-size-base) !default; +$rate-font-size-small: var(--nutui-rate-font-size-small, $font-size-s) !default; +$rate-label-color: var(--nutui-rate-label-color, $color-text-disabled) !default; // tabbar(✅) $tabbar-height: var(--nutui-tabbar-height, scale-px(46px)) !default; diff --git a/src/types/spec/rate/base.ts b/src/types/spec/rate/base.ts index 6a67aca553..670172edfe 100644 --- a/src/types/spec/rate/base.ts +++ b/src/types/spec/rate/base.ts @@ -3,9 +3,12 @@ import { BasicComponent } from '@/utils/typings' import { UISize } from '../../base/atoms' export type RateSize = Extract +export type RateLayout = 'horizontal' | 'vertical' export interface BaseRate extends BasicComponent { size: RateSize + layout: RateLayout + label: ReactNode | ReactNode[] showScore: boolean count: number value: number From 16aa92ee87d619fc4ee2a6a9129e2006cbf8b775 Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Wed, 17 Jun 2026 16:35:51 +0800 Subject: [PATCH 2/6] =?UTF-8?q?feat(Rate):=20=E6=96=B0=E5=A2=9E=E9=80=89?= =?UTF-8?q?=E4=B8=AD=E8=BF=87=E6=B8=A1=E5=8A=A8=E7=94=BB=EF=BC=88=E5=B0=BA?= =?UTF-8?q?=E5=AF=B8=E2=89=A520px=E8=87=AA=E5=8A=A8=E5=90=AF=E7=94=A8?= =?UTF-8?q?=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 点击星星选中时播放 scale bounce 动画(1 → 1.25 → 1) - 仅在图标尺寸≥20px时启用(水平large、垂直normal/large) - 仅在评分增加时触发,减少时不动画 - 动画持续300ms,自动清除状态 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/packages/rate/rate.scss | 16 ++++++++++++++++ src/packages/rate/rate.taro.tsx | 18 ++++++++++++++++++ src/packages/rate/rate.tsx | 18 ++++++++++++++++++ 3 files changed, 52 insertions(+) diff --git a/src/packages/rate/rate.scss b/src/packages/rate/rate.scss index f05dbe24e0..03b8ab234b 100644 --- a/src/packages/rate/rate.scss +++ b/src/packages/rate/rate.scss @@ -92,6 +92,10 @@ left: auto; transform: none; } + + &-animate { + animation: nut-rate-bounce 0.3s ease-in-out; + } } } @@ -259,6 +263,18 @@ } } +@keyframes nut-rate-bounce { + 0% { + transform: scale(1); + } + 50% { + transform: scale(1.25); + } + 100% { + transform: scale(1); + } +} + [dir='rtl'] .nut-rate, .nut-rtl .nut-rate { &-horizontal { diff --git a/src/packages/rate/rate.taro.tsx b/src/packages/rate/rate.taro.tsx index ca3beeec46..03711f5db2 100644 --- a/src/packages/rate/rate.taro.tsx +++ b/src/packages/rate/rate.taro.tsx @@ -58,6 +58,16 @@ export const Rate: FunctionComponent> = (props) => { const classPrefix = 'nut-rate' + const shouldAnimate = layout === 'vertical' || size === 'large' + const [animatingIndex, setAnimatingIndex] = useState(-1) + + useEffect(() => { + if (animatingIndex >= 0) { + const timer = setTimeout(() => setAnimatingIndex(-1), 300) + return () => clearTimeout(timer) + } + }, [animatingIndex]) + const [countArray, setCountArray] = useState([1, 2, 3, 4, 5]) const [refs, setRefs] = useRefs() @@ -109,6 +119,9 @@ export const Rate: FunctionComponent> = (props) => { value = index } value = Math.max(value, min) + if (shouldAnimate && value > score) { + setAnimatingIndex(index - 1) + } setScore(value) } @@ -119,6 +132,9 @@ export const Rate: FunctionComponent> = (props) => { event.preventDefault() event.stopPropagation() const value = Math.max(min, n - 0.5) + if (shouldAnimate && value > score) { + setAnimatingIndex(n - 1) + } setScore(value) } @@ -273,6 +289,8 @@ export const Rate: FunctionComponent> = (props) => { score, + [`${classPrefix}-item-icon-animate`]: + animatingIndex === index, })} > {renderIcon(n)} diff --git a/src/packages/rate/rate.tsx b/src/packages/rate/rate.tsx index fb7573000f..2fd712dafb 100644 --- a/src/packages/rate/rate.tsx +++ b/src/packages/rate/rate.tsx @@ -55,6 +55,16 @@ export const Rate: FunctionComponent> = (props) => { const classPrefix = 'nut-rate' + const shouldAnimate = layout === 'vertical' || size === 'large' + const [animatingIndex, setAnimatingIndex] = useState(-1) + + useEffect(() => { + if (animatingIndex >= 0) { + const timer = setTimeout(() => setAnimatingIndex(-1), 300) + return () => clearTimeout(timer) + } + }, [animatingIndex]) + const [countArray, setCountArray] = useState([1, 2, 3, 4, 5]) const [refs, setRefs] = useRefs() @@ -103,6 +113,9 @@ export const Rate: FunctionComponent> = (props) => { value = index } value = Math.max(value, min) + if (shouldAnimate && value > score) { + setAnimatingIndex(index - 1) + } setScore(value) } @@ -110,6 +123,9 @@ export const Rate: FunctionComponent> = (props) => { event.preventDefault() event.stopPropagation() const value = Math.max(min, n - 0.5) + if (shouldAnimate && value > score) { + setAnimatingIndex(n - 1) + } setScore(value) } @@ -275,6 +291,8 @@ export const Rate: FunctionComponent> = (props) => {
score, + [`${classPrefix}-item-icon-animate`]: + animatingIndex === index, })} > {renderIcon(n)} From f959a54de617eded4bbf23b1902bf9f7c62884e8 Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Wed, 17 Jun 2026 16:38:09 +0800 Subject: [PATCH 3/6] =?UTF-8?q?docs(Rate):=20=E6=96=B0=E5=A2=9E=E8=BF=87?= =?UTF-8?q?=E6=B8=A1=E5=8A=A8=E7=94=BB=20demo?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- src/packages/rate/demo.taro.tsx | 9 +++++++++ src/packages/rate/demo.tsx | 9 +++++++++ src/packages/rate/demos/h5/demo15.tsx | 12 ++++++++++++ src/packages/rate/demos/taro/demo15.tsx | 12 ++++++++++++ src/packages/rate/doc.en-US.md | 8 ++++++++ src/packages/rate/doc.md | 8 ++++++++ src/packages/rate/doc.taro.md | 8 ++++++++ src/packages/rate/doc.zh-TW.md | 8 ++++++++ 8 files changed, 74 insertions(+) create mode 100644 src/packages/rate/demos/h5/demo15.tsx create mode 100644 src/packages/rate/demos/taro/demo15.tsx diff --git a/src/packages/rate/demo.taro.tsx b/src/packages/rate/demo.taro.tsx index f13e997f8a..2babef653a 100644 --- a/src/packages/rate/demo.taro.tsx +++ b/src/packages/rate/demo.taro.tsx @@ -18,6 +18,7 @@ import Demo11 from './demos/taro/demo11' import Demo12 from './demos/taro/demo12' import Demo13 from './demos/taro/demo13' import Demo14 from './demos/taro/demo14' +import Demo15 from './demos/taro/demo15' const RateDemo = () => { const [translated] = useTranslate({ @@ -36,6 +37,7 @@ const RateDemo = () => { touchend: '滑动事件', verticalLayout: '上下布局', withLabel: '带标签', + animation: '过渡动画', }, 'zh-TW': { basic: '基礎用法', @@ -52,6 +54,7 @@ const RateDemo = () => { touchend: '滑動事件', verticalLayout: '上下佈局', withLabel: '帶標籤', + animation: '過渡動畫', }, 'en-US': { basic: 'Basic Usage', @@ -68,6 +71,7 @@ const RateDemo = () => { touchend: 'Touch Event', verticalLayout: 'Vertical Layout', withLabel: 'With Label', + animation: 'Transition Animation', }, }) const cellStyle: CSSProperties = { @@ -151,6 +155,11 @@ const RateDemo = () => { + + {translated.animation} + + + ) diff --git a/src/packages/rate/demo.tsx b/src/packages/rate/demo.tsx index 9d68f4b6e9..621dc1baa3 100644 --- a/src/packages/rate/demo.tsx +++ b/src/packages/rate/demo.tsx @@ -15,6 +15,7 @@ import Demo11 from './demos/h5/demo11' import Demo12 from './demos/h5/demo12' import Demo13 from './demos/h5/demo13' import Demo14 from './demos/h5/demo14' +import Demo15 from './demos/h5/demo15' const RateDemo = () => { const [translated] = useTranslate({ @@ -33,6 +34,7 @@ const RateDemo = () => { touchevent: '滑动事件', verticalLayout: '上下布局', withLabel: '带标签', + animation: '过渡动画', }, 'zh-TW': { basic: '基礎用法', @@ -49,6 +51,7 @@ const RateDemo = () => { touchevent: '滑動事件', verticalLayout: '上下佈局', withLabel: '帶標籤', + animation: '過渡動畫', }, 'en-US': { basic: 'Basic Usage', @@ -65,6 +68,7 @@ const RateDemo = () => { touchevent: 'Touch Event', verticalLayout: 'Vertical Layout', withLabel: 'With Label', + animation: 'Transition Animation', }, }) const cellStyle: CSSProperties = { @@ -144,6 +148,11 @@ const RateDemo = () => { + +

{translated.animation}

+ + +
) diff --git a/src/packages/rate/demos/h5/demo15.tsx b/src/packages/rate/demos/h5/demo15.tsx new file mode 100644 index 0000000000..88825d6aaf --- /dev/null +++ b/src/packages/rate/demos/h5/demo15.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react' + +const Demo15 = () => { + return ( + + + + + ) +} +export default Demo15 diff --git a/src/packages/rate/demos/taro/demo15.tsx b/src/packages/rate/demos/taro/demo15.tsx new file mode 100644 index 0000000000..d095b26bee --- /dev/null +++ b/src/packages/rate/demos/taro/demo15.tsx @@ -0,0 +1,12 @@ +import React from 'react' +import { Rate, Space } from '@nutui/nutui-react-taro' + +const Demo15 = () => { + return ( + + + + + ) +} +export default Demo15 diff --git a/src/packages/rate/doc.en-US.md b/src/packages/rate/doc.en-US.md index 52d8f0bb3d..680a2fbbb7 100644 --- a/src/packages/rate/doc.en-US.md +++ b/src/packages/rate/doc.en-US.md @@ -122,6 +122,14 @@ import { Rate } from '@nutui/nutui-react' ::: +### Transition Animation + +:::demo + + + +::: + ## Rate ### Props diff --git a/src/packages/rate/doc.md b/src/packages/rate/doc.md index 96e4072311..df791c453a 100644 --- a/src/packages/rate/doc.md +++ b/src/packages/rate/doc.md @@ -122,6 +122,14 @@ import { Rate } from '@nutui/nutui-react' ::: +### 过渡动画 + +:::demo + + + +::: + ## Rate ### Props diff --git a/src/packages/rate/doc.taro.md b/src/packages/rate/doc.taro.md index 84eac8cd3f..ea09ae64b1 100644 --- a/src/packages/rate/doc.taro.md +++ b/src/packages/rate/doc.taro.md @@ -122,6 +122,14 @@ import { Rate } from '@nutui/nutui-react-taro' ::: +### 过渡动画 + +:::demo + + + +::: + ## Rate ### Props diff --git a/src/packages/rate/doc.zh-TW.md b/src/packages/rate/doc.zh-TW.md index 68af471020..f18f97b93d 100644 --- a/src/packages/rate/doc.zh-TW.md +++ b/src/packages/rate/doc.zh-TW.md @@ -122,6 +122,14 @@ import { Rate } from '@nutui/nutui-react' ::: +### 過渡動畫 + +:::demo + + + +::: + ## Rate ### Props From 1c94d7df06d431cd50b63e5025b62ef2b00aa733 Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Wed, 17 Jun 2026 16:50:58 +0800 Subject: [PATCH 4/6] =?UTF-8?q?fix(Rate):=20=E8=A1=A5=E5=85=85=E4=B8=BB?= =?UTF-8?q?=E9=A2=98=E5=8F=98=E9=87=8F=E6=96=87=E4=BB=B6=E4=B8=AD=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E7=9A=84=20$rate-label-color?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- src/styles/variables-daojia.scss | 1 + src/styles/variables-jmapp.scss | 1 + src/styles/variables-jrkf.scss | 1 + 3 files changed, 3 insertions(+) diff --git a/src/styles/variables-daojia.scss b/src/styles/variables-daojia.scss index 982b6bada4..3603c7d984 100644 --- a/src/styles/variables-daojia.scss +++ b/src/styles/variables-daojia.scss @@ -798,6 +798,7 @@ $rate-icon-inactive-color: var(--nutui-rate-icon-inactive-color, $rate-icon-size: var(--nutui-rate-icon-size, 12px) !default; $rate-font-color: var(--nutui-rate-font-color, $color-primary-icon) !default; $rate-font-size: var(--nutui-rate-font-size, 12px) !default; +$rate-label-color: var(--nutui-rate-label-color, $color-text-disabled) !default; // tabbar(✅) $tabbar-height: var(--nutui-tabbar-height, 46px) !default; diff --git a/src/styles/variables-jmapp.scss b/src/styles/variables-jmapp.scss index 699c9d6666..9f50ac70a0 100644 --- a/src/styles/variables-jmapp.scss +++ b/src/styles/variables-jmapp.scss @@ -1346,6 +1346,7 @@ $rate-font-color: var(--nutui-rate-font-color, $color-primary-icon) !default; $rate-font-size: var(--nutui-rate-font-size, 12px) !default; $rate-font-size-large: var(--nutui-rate-font-size-large, calc(#{$rate-font-size} + 6px)) !default; $rate-font-size-small: var(--nutui-rate-font-size-small, calc(#{$rate-font-size} - 2px)) !default; +$rate-label-color: var(--nutui-rate-label-color, $color-text-disabled) !default; // tabbar(✅) $tabbar-height: var(--nutui-tabbar-height, 50px) !default; diff --git a/src/styles/variables-jrkf.scss b/src/styles/variables-jrkf.scss index a39df2f708..088fb4ef61 100644 --- a/src/styles/variables-jrkf.scss +++ b/src/styles/variables-jrkf.scss @@ -1445,6 +1445,7 @@ $rate-font-color: var(--nutui-rate-font-color, $color-primary-icon) !default; $rate-font-size: var(--nutui-rate-font-size, 12px) !default; $rate-font-size-large: var(--nutui-rate-font-size-large, calc(#{$rate-font-size} + 6px)) !default; $rate-font-size-small: var(--nutui-rate-font-size-small, calc(#{$rate-font-size} - 2px)) !default; +$rate-label-color: var(--nutui-rate-label-color, $color-text-disabled) !default; $rate-item-margin: var(--nutui-rate-item-margin, 14px) !default; $rate-icon-color: var(--nutui-rate-icon-color, $color-primary) !default; $rate-icon-inactive-color: var( From a1ac0c244fed2ba95bd34c6370c744f30bd8ff08 Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Wed, 17 Jun 2026 16:52:32 +0800 Subject: [PATCH 5/6] =?UTF-8?q?chore(Rate):=20=E5=90=8C=E6=AD=A5=20NutCSSV?= =?UTF-8?q?ariables=20=E7=B1=BB=E5=9E=8B=E5=A3=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 构建自动生成,新增 nutuiRateLabelColor 变量类型 Co-Authored-By: Claude Opus 4.6 (1M context) --- src/packages/configprovider/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/packages/configprovider/types.ts b/src/packages/configprovider/types.ts index 73bfd07a94..2a48c1a81d 100644 --- a/src/packages/configprovider/types.ts +++ b/src/packages/configprovider/types.ts @@ -441,6 +441,7 @@ export type NutCSSVariables = | 'nutuiRateFontSize' | 'nutuiRateFontSizeLarge' | 'nutuiRateFontSizeSmall' + | 'nutuiRateLabelColor' | 'nutuiTabbarHeight' | 'nutuiTabbarActiveColor' | 'nutuiTabbarInactiveColor' From bd44d3f65d5e8e7f3fd8fe91105c84257195c16b Mon Sep 17 00:00:00 2001 From: xiyehutao <1254524557@qq.com> Date: Thu, 18 Jun 2026 13:52:36 +0800 Subject: [PATCH 6/6] =?UTF-8?q?refactor(Rate):=20=E5=B0=86=20layout=20?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E9=87=8D=E5=91=BD=E5=90=8D=E4=B8=BA=20direct?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.6 (1M context) --- src/packages/rate/__test__/rate.spec.tsx | 14 +++++++------- src/packages/rate/demos/h5/demo13.tsx | 4 ++-- src/packages/rate/demos/h5/demo14.tsx | 2 +- src/packages/rate/demos/h5/demo15.tsx | 2 +- src/packages/rate/demos/taro/demo13.tsx | 4 ++-- src/packages/rate/demos/taro/demo14.tsx | 2 +- src/packages/rate/demos/taro/demo15.tsx | 2 +- src/packages/rate/doc.en-US.md | 2 +- src/packages/rate/doc.md | 2 +- src/packages/rate/doc.taro.md | 2 +- src/packages/rate/doc.zh-TW.md | 2 +- src/packages/rate/index.taro.ts | 6 +++++- src/packages/rate/index.ts | 6 +++++- src/packages/rate/rate.taro.tsx | 14 +++++++------- src/packages/rate/rate.tsx | 14 +++++++------- src/types/spec/rate/base.ts | 4 ++-- 16 files changed, 45 insertions(+), 37 deletions(-) diff --git a/src/packages/rate/__test__/rate.spec.tsx b/src/packages/rate/__test__/rate.spec.tsx index 8d2b8c744a..fa0167f7ea 100644 --- a/src/packages/rate/__test__/rate.spec.tsx +++ b/src/packages/rate/__test__/rate.spec.tsx @@ -92,22 +92,22 @@ test('showScore test', () => { } }) -test('layout horizontal test', () => { - const { container } = render() +test('direction horizontal test', () => { + const { container } = render() const root = container.querySelector('.nut-rate') expect(root).toHaveClass('nut-rate-horizontal') expect(container.querySelector('.nut-rate-list')).toBeTruthy() }) -test('layout vertical test', () => { - const { container } = render() +test('direction vertical test', () => { + const { container } = render() const root = container.querySelector('.nut-rate') expect(root).toHaveClass('nut-rate-vertical') }) test('label test horizontal', () => { const { container } = render( - + ) const label = container.querySelector('.nut-rate-label') expect(label).toBeTruthy() @@ -122,7 +122,7 @@ test('label test horizontal', () => { test('label test vertical', () => { const { container } = render( - + ) const label = container.querySelector('.nut-rate-label') expect(label).toBeTruthy() @@ -138,7 +138,7 @@ test('label test vertical', () => { test('array label test vertical', () => { const labels = ['不满意', '', '', '', '非常满意'] const { container } = render( - + ) const labelsRow = container.querySelector('.nut-rate-labels') expect(labelsRow).toBeTruthy() diff --git a/src/packages/rate/demos/h5/demo13.tsx b/src/packages/rate/demos/h5/demo13.tsx index 93b6980477..ea0bbb1de2 100644 --- a/src/packages/rate/demos/h5/demo13.tsx +++ b/src/packages/rate/demos/h5/demo13.tsx @@ -6,12 +6,12 @@ const Demo13 = () => { diff --git a/src/packages/rate/demos/h5/demo14.tsx b/src/packages/rate/demos/h5/demo14.tsx index 56c49510f0..3d60549184 100644 --- a/src/packages/rate/demos/h5/demo14.tsx +++ b/src/packages/rate/demos/h5/demo14.tsx @@ -9,7 +9,7 @@ const Demo14 = () => { diff --git a/src/packages/rate/demos/h5/demo15.tsx b/src/packages/rate/demos/h5/demo15.tsx index 88825d6aaf..1b14584c47 100644 --- a/src/packages/rate/demos/h5/demo15.tsx +++ b/src/packages/rate/demos/h5/demo15.tsx @@ -5,7 +5,7 @@ const Demo15 = () => { return ( - + ) } diff --git a/src/packages/rate/demos/taro/demo13.tsx b/src/packages/rate/demos/taro/demo13.tsx index f37ff345e2..6c7c1323fe 100644 --- a/src/packages/rate/demos/taro/demo13.tsx +++ b/src/packages/rate/demos/taro/demo13.tsx @@ -6,12 +6,12 @@ const Demo13 = () => { diff --git a/src/packages/rate/demos/taro/demo14.tsx b/src/packages/rate/demos/taro/demo14.tsx index 59c3ffc030..4528fbf160 100644 --- a/src/packages/rate/demos/taro/demo14.tsx +++ b/src/packages/rate/demos/taro/demo14.tsx @@ -9,7 +9,7 @@ const Demo14 = () => { diff --git a/src/packages/rate/demos/taro/demo15.tsx b/src/packages/rate/demos/taro/demo15.tsx index d095b26bee..a0b540db3d 100644 --- a/src/packages/rate/demos/taro/demo15.tsx +++ b/src/packages/rate/demos/taro/demo15.tsx @@ -5,7 +5,7 @@ const Demo15 = () => { return ( - + ) } diff --git a/src/packages/rate/doc.en-US.md b/src/packages/rate/doc.en-US.md index 680a2fbbb7..e2add16d5d 100644 --- a/src/packages/rate/doc.en-US.md +++ b/src/packages/rate/doc.en-US.md @@ -137,7 +137,7 @@ import { Rate } from '@nutui/nutui-react' | Property | Description | Type | Default | | --- | --- | --- | --- | | size | Score size | `large` \| `normal` \| `small` | `normal` | -| layout | Layout type | `horizontal` \| `vertical` | `horizontal` | +| direction | Direction | `horizontal` \| `vertical` | `horizontal` | | label | Label text | `ReactNode` | `-` | | showScore | Show Score | `boolean` | `false` | | defaultValue | Uncontrolled star value | `number` | `0` | diff --git a/src/packages/rate/doc.md b/src/packages/rate/doc.md index df791c453a..af81919392 100644 --- a/src/packages/rate/doc.md +++ b/src/packages/rate/doc.md @@ -137,7 +137,7 @@ import { Rate } from '@nutui/nutui-react' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | -| layout | 布局方式 | `horizontal` \| `vertical` | `horizontal` | +| direction | 方向 | `horizontal` \| `vertical` | `horizontal` | | label | 标签文字 | `ReactNode` | `-` | | showScore | 展示评分 | `boolean` | `false` | | defaultValue | 非受控的 star 默认值 | `number` | `0` | diff --git a/src/packages/rate/doc.taro.md b/src/packages/rate/doc.taro.md index ea09ae64b1..f97caf52b6 100644 --- a/src/packages/rate/doc.taro.md +++ b/src/packages/rate/doc.taro.md @@ -137,7 +137,7 @@ import { Rate } from '@nutui/nutui-react-taro' | 属性 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | -| layout | 布局方式 | `horizontal` \| `vertical` | `horizontal` | +| direction | 方向 | `horizontal` \| `vertical` | `horizontal` | | label | 标签文字 | `ReactNode` | `-` | | showScore | 展示评分 | `boolean` | `false` | | defaultValue | 非受控的 star 默认值 | `number` | `0` | diff --git a/src/packages/rate/doc.zh-TW.md b/src/packages/rate/doc.zh-TW.md index f18f97b93d..332c5fe083 100644 --- a/src/packages/rate/doc.zh-TW.md +++ b/src/packages/rate/doc.zh-TW.md @@ -137,7 +137,7 @@ import { Rate } from '@nutui/nutui-react' | 屬性 | 說明 | 類型 | 默認值 | | --- | --- | --- | --- | | size | star 尺寸 | `large` \| `normal` \| `small` | `normal` | -| layout | 佈局方式 | `horizontal` \| `vertical` | `horizontal` | +| direction | 方向 | `horizontal` \| `vertical` | `horizontal` | | label | 標籤文字 | `ReactNode` | `-` | | showScore | 展示評分 | `boolean` | `false` | | defaultValue | 非受控的 star 默認值 | `number` | `0` | diff --git a/src/packages/rate/index.taro.ts b/src/packages/rate/index.taro.ts index 37ba8dd971..b1ca1e41dc 100644 --- a/src/packages/rate/index.taro.ts +++ b/src/packages/rate/index.taro.ts @@ -1,4 +1,8 @@ import { Rate } from './rate.taro' -export type { RateSize, RateLayout, TaroRateProps as RateProps } from '@/types' +export type { + RateSize, + RateDirection, + TaroRateProps as RateProps, +} from '@/types' export default Rate diff --git a/src/packages/rate/index.ts b/src/packages/rate/index.ts index b1ff03ed64..346b2ad5e5 100644 --- a/src/packages/rate/index.ts +++ b/src/packages/rate/index.ts @@ -1,4 +1,8 @@ import { Rate } from './rate' -export type { RateSize, RateLayout, WebRateProps as RateProps } from '@/types' +export type { + RateSize, + RateDirection, + WebRateProps as RateProps, +} from '@/types' export default Rate diff --git a/src/packages/rate/rate.taro.tsx b/src/packages/rate/rate.taro.tsx index 03711f5db2..e4dc1d5b4d 100644 --- a/src/packages/rate/rate.taro.tsx +++ b/src/packages/rate/rate.taro.tsx @@ -20,7 +20,7 @@ import { TaroRateProps } from '@/types' const defaultProps = { ...ComponentDefaults, size: 'normal', - layout: 'horizontal', + direction: 'horizontal', showScore: false, count: 5, min: 0, @@ -36,7 +36,7 @@ export const Rate: FunctionComponent> = (props) => { className, style, size, - layout, + direction, label, showScore, count, @@ -58,7 +58,7 @@ export const Rate: FunctionComponent> = (props) => { const classPrefix = 'nut-rate' - const shouldAnimate = layout === 'vertical' || size === 'large' + const shouldAnimate = direction === 'vertical' || size === 'large' const [animatingIndex, setAnimatingIndex] = useState(-1) useEffect(() => { @@ -262,7 +262,7 @@ export const Rate: FunctionComponent> = (props) => { > = (props) => { onTouchEnd={handleTouchEnd} onTouchCancel={handleTouchEnd} > - {layout === 'horizontal' && renderSingleLabel()} + {direction === 'horizontal' && renderSingleLabel()} {countArray.map((n, index) => { return ( @@ -311,8 +311,8 @@ export const Rate: FunctionComponent> = (props) => { ) })} - {layout === 'horizontal' && renderScore()} - {layout === 'vertical' && ( + {direction === 'horizontal' && renderScore()} + {direction === 'vertical' && ( <> {renderScore()} {isArrayLabel ? renderArrayLabels() : renderSingleLabel()} diff --git a/src/packages/rate/rate.tsx b/src/packages/rate/rate.tsx index 2fd712dafb..54e99e384d 100644 --- a/src/packages/rate/rate.tsx +++ b/src/packages/rate/rate.tsx @@ -17,7 +17,7 @@ import { WebRateProps } from '@/types' const defaultProps = { ...ComponentDefaults, size: 'normal', - layout: 'horizontal', + direction: 'horizontal', showScore: false, count: 5, min: 0, @@ -33,7 +33,7 @@ export const Rate: FunctionComponent> = (props) => { className, style, size, - layout, + direction, label, showScore, count, @@ -55,7 +55,7 @@ export const Rate: FunctionComponent> = (props) => { const classPrefix = 'nut-rate' - const shouldAnimate = layout === 'vertical' || size === 'large' + const shouldAnimate = direction === 'vertical' || size === 'large' const [animatingIndex, setAnimatingIndex] = useState(-1) useEffect(() => { @@ -268,7 +268,7 @@ export const Rate: FunctionComponent> = (props) => {
> = (props) => { ref={rateRef} style={style} > - {layout === 'horizontal' && renderSingleLabel()} + {direction === 'horizontal' && renderSingleLabel()}
{countArray.map((n, index) => { return ( @@ -313,8 +313,8 @@ export const Rate: FunctionComponent> = (props) => { ) })}
- {layout === 'horizontal' && renderScore()} - {layout === 'vertical' && ( + {direction === 'horizontal' && renderScore()} + {direction === 'vertical' && ( <> {renderScore()} {isArrayLabel ? renderArrayLabels() : renderSingleLabel()} diff --git a/src/types/spec/rate/base.ts b/src/types/spec/rate/base.ts index 670172edfe..de90280ef1 100644 --- a/src/types/spec/rate/base.ts +++ b/src/types/spec/rate/base.ts @@ -3,11 +3,11 @@ import { BasicComponent } from '@/utils/typings' import { UISize } from '../../base/atoms' export type RateSize = Extract -export type RateLayout = 'horizontal' | 'vertical' +export type RateDirection = 'horizontal' | 'vertical' export interface BaseRate extends BasicComponent { size: RateSize - layout: RateLayout + direction: RateDirection label: ReactNode | ReactNode[] showScore: boolean count: number