diff --git a/src/packages/progress/__tests__/__snapshots__/progress.spec.tsx.snap b/src/packages/progress/__tests__/__snapshots__/progress.spec.tsx.snap index 80701d06e4..e9c9b19f36 100644 --- a/src/packages/progress/__tests__/__snapshots__/progress.spec.tsx.snap +++ b/src/packages/progress/__tests__/__snapshots__/progress.spec.tsx.snap @@ -10,7 +10,7 @@ exports[`should render progress when use props 1`] = ` >
diff --git a/src/packages/progress/__tests__/progress.spec.tsx b/src/packages/progress/__tests__/progress.spec.tsx index 81e0413f8b..b455f02565 100644 --- a/src/packages/progress/__tests__/progress.spec.tsx +++ b/src/packages/progress/__tests__/progress.spec.tsx @@ -13,7 +13,9 @@ test('should render different height and color when use color height props', asy ) const inner = container.querySelector('.nut-progress-inner') - expect(inner?.getAttribute('style')).toBe('width: 50%; background: blue;') + expect(inner?.getAttribute('style')).toBe( + 'width: 50%; background: blue; transition: width 300ms ease-in-out;' + ) }) test('should show percent when use showText props', () => { @@ -21,3 +23,54 @@ test('should show percent when use showText props', () => { const text = container.querySelector('.nut-progress-text') expect(text).toBeTruthy() }) +test('should render with custom style props', () => { + const { container } = render( + + ) + const inner = container.querySelector('.nut-progress-text') + expect(inner).toHaveStyle({ + fontSize: '16px', + }) + const outerDiv = container.querySelector('.nut-progress-outer') + expect(outerDiv).toHaveStyle({ + borderRadius: '8px', + }) +}) + +test('should handle animation mode and duration', () => { + const onActiveEndMock = vi.fn() + const { container, rerender } = render( + + ) + + const inner = container.querySelector('.nut-progress-inner') + expect(inner?.getAttribute('style')).toContain( + 'transition: width 500ms ease-in-out' + ) + + // 测试动画完成回调 + rerender( + + ) + setTimeout(() => { + expect(onActiveEndMock).toHaveBeenCalled() + }, 600) +}) + +test('should render with aria-label', () => { + const { container } = render( + + ) + const progressDiv = container.querySelector('.nut-progress') + expect(progressDiv?.getAttribute('aria-label')).toBe('当前进度50%') +}) diff --git a/src/packages/progress/demo.taro.tsx b/src/packages/progress/demo.taro.tsx index f1cbffca24..5b0750bab3 100644 --- a/src/packages/progress/demo.taro.tsx +++ b/src/packages/progress/demo.taro.tsx @@ -11,6 +11,7 @@ import Demo5 from './demos/taro/demo5' import Demo6 from './demos/taro/demo6' import Demo7 from './demos/taro/demo7' import Demo8 from './demos/taro/demo8' +import Demo9 from './demos/taro/demo9' const ProgressDemo = () => { const [translated] = useTranslate({ @@ -23,16 +24,18 @@ const ProgressDemo = () => { statusDisplay: '状态显示', dynamicChange: '动态改变', lazy: '延迟加载数据', + activeMode: '设置动画时长与播放方式', }, 'zh-TW': { basic: '基礎用法', - customStyle: '設置顏色與寛度', + customStyle: '設置顏色與寬度', noShowPercentage: '顯示百分比', customContent: '自定義顯示內容', customSize: '自定義尺寸', statusDisplay: '狀態顯示', dynamicChange: '動態改變', - lazy: '延迟加载数据', + lazy: '延遲加載數據', + activeMode: '設置動畫時長與播放方式', }, 'en-US': { basic: 'Basic Usage', @@ -43,6 +46,7 @@ const ProgressDemo = () => { statusDisplay: 'Status Display', dynamicChange: 'Dynamic Change', lazy: 'Delay Time', + activeMode: 'Duration And Animation Mode', }, }) @@ -71,6 +75,8 @@ const ProgressDemo = () => { )} + {translated.activeMode} + ) diff --git a/src/packages/progress/demo.tsx b/src/packages/progress/demo.tsx index b67be254bc..a58feaf69e 100644 --- a/src/packages/progress/demo.tsx +++ b/src/packages/progress/demo.tsx @@ -8,6 +8,7 @@ import Demo5 from './demos/h5/demo5' import Demo6 from './demos/h5/demo6' import Demo7 from './demos/h5/demo7' import Demo8 from './demos/h5/demo8' +import Demo9 from './demos/h5/demo9' const ProgressDemo = () => { const [translated] = useTranslate({ @@ -20,16 +21,18 @@ const ProgressDemo = () => { statusDisplay: '状态显示', dynamicChange: '动态改变', lazy: '延迟加载数据', + activeMode: '设置动画时长与播放方式', }, 'zh-TW': { basic: '基礎用法', - customStyle: '設置顏色與寛度', + customStyle: '設置顏色與寬度', noShowPercentage: '顯示百分比', customContent: '自定義顯示內容', customSize: '自定義尺寸', statusDisplay: '狀態顯示', dynamicChange: '動態改變', - lazy: '延迟加载数据', + lazy: '延遲加載數據', + activeMode: '設置動畫時長與播放方式', }, 'en-US': { basic: 'Basic Usage', @@ -40,6 +43,7 @@ const ProgressDemo = () => { statusDisplay: 'Status Display', dynamicChange: 'Dynamic Change', lazy: 'Delay Time', + activeMode: 'Duration And Animation Mode', }, }) @@ -62,6 +66,8 @@ const ProgressDemo = () => {

{translated.lazy}

+

{translated.activeMode}

+ ) diff --git a/src/packages/progress/demos/h5/demo4.tsx b/src/packages/progress/demos/h5/demo4.tsx index d5251f632b..4a53c6f486 100644 --- a/src/packages/progress/demos/h5/demo4.tsx +++ b/src/packages/progress/demos/h5/demo4.tsx @@ -3,15 +3,22 @@ import { Progress, Image, Cell } from '@nutui/nutui-react' const Demo4 = () => { return ( - - - - - + <> + + + 已完成15/30 + + + + + + + + ) } export default Demo4 diff --git a/src/packages/progress/demos/h5/demo9.tsx b/src/packages/progress/demos/h5/demo9.tsx new file mode 100644 index 0000000000..852a571e95 --- /dev/null +++ b/src/packages/progress/demos/h5/demo9.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react' +import { Cell, Button, Progress } from '@nutui/nutui-react' + +const Demo7 = () => { + const [value, setValue] = useState(0) + return ( + + + + + + + + + + + ) +} +export default Demo7 diff --git a/src/packages/progress/demos/taro/demo4.tsx b/src/packages/progress/demos/taro/demo4.tsx index 2740c9fdf7..50d7ed16b4 100644 --- a/src/packages/progress/demos/taro/demo4.tsx +++ b/src/packages/progress/demos/taro/demo4.tsx @@ -3,15 +3,22 @@ import { Progress, Image, Cell } from '@nutui/nutui-react-taro' const Demo4 = () => { return ( - - - - - + <> + + + 已完成15/30 + + + + + + + + ) } export default Demo4 diff --git a/src/packages/progress/demos/taro/demo9.tsx b/src/packages/progress/demos/taro/demo9.tsx new file mode 100644 index 0000000000..90c97ac73a --- /dev/null +++ b/src/packages/progress/demos/taro/demo9.tsx @@ -0,0 +1,39 @@ +import React, { useState } from 'react' +import { Cell, Button, Progress, pxTransform } from '@nutui/nutui-react-taro' + +const Demo7 = () => { + const [value, setValue] = useState(0) + return ( + + + + + + + + + + + ) +} +export default Demo7 diff --git a/src/packages/progress/doc.en-US.md b/src/packages/progress/doc.en-US.md index 5f3b032a54..85f6530563 100644 --- a/src/packages/progress/doc.en-US.md +++ b/src/packages/progress/doc.en-US.md @@ -74,6 +74,12 @@ import { Progress } from '@nutui/nutui-react' ::: +### Set animation duration and playback mode + +:::demo + +::: + ## Progress ### Props @@ -88,6 +94,12 @@ import { Progress } from '@nutui/nutui-react' | animated | Whether to show animation | `boolean` | `false` | | lazy | Show animation when intersect | `boolean` | `false` | | delay | Delay time to set percent, ms | `number` | `0` | +| borderRadius | Progress bar corner size | `string` | `0` | +| fontSize | Progress text size | `string` | `12px` | +| activeMode | Animation playback mode | `forwards \| backwards` | `forwards` | +| duration | Animation completion time (in milliseconds) | `number` | `30` | +| ariaLabel | AccessibilityLabel | `string` | `-` | +| onActiveEnd | Callback function after animation is completed | `() => void` | `-` | ## Theming @@ -101,9 +113,9 @@ The component provides the following CSS variables, which can be used to customi | \--nutui-progress-border-radius | borderRadius | `12px` | | \--nutui-progress-color | progress color | `linear-gradient(135deg, #FF0F23 0%, #fa6419 100%)` | | \--nutui-progress-background | progress background | `#f3f3f3` | -| \--nutui-progress-text-color | text color | `$color-primary-text` | +| \--nutui-progress-text-color | text color | `$color-text-help` | | \--nutui-progress-text-padding | text padding | `0 5px` | -| \--nutui-progress-text-font-size | text fontSize | `9px` | +| \--nutui-progress-text-font-size | text fontSize | `13px` | | \--nutui-progress-text-position-top | text top | `-4px` | | \--nutui-progress-text-position-bottom | text bottom | `-4px` | | \--nutui-progress-text-border-radius | text borderRadius | `5px` | diff --git a/src/packages/progress/doc.md b/src/packages/progress/doc.md index 447bbd3baa..7a3164589d 100644 --- a/src/packages/progress/doc.md +++ b/src/packages/progress/doc.md @@ -74,6 +74,12 @@ import { Progress } from '@nutui/nutui-react' ::: +### 设置动画时长与播放方式 + +:::demo + +::: + ## Progress ### Props @@ -88,6 +94,12 @@ import { Progress } from '@nutui/nutui-react' | animated | 是否展示动画效果 | `boolean` | `false` | | lazy | 每次进入可视区展示进度条动画 | `boolean` | `false` | | delay | 延迟数据加载时长,单位 ms | `number` | `0` | +| borderRadius | 进度条圆角大小 | `string` | `0` | +| fontSize | 进度文字大小 | `string` | `12px` | +| activeMode | 动画播放方式 | `forwards \| backwards` | `forwards` | +| duration | 动画完成时间(单位:毫秒) | `number` | `30` | +| ariaLabel | 无障碍标签 | `string` | `-` | +| onActiveEnd | 动画完成后的回调函数 | `() => void` | `-` | ## 主题定制 @@ -101,9 +113,9 @@ import { Progress } from '@nutui/nutui-react' | \--nutui-progress-border-radius | 进度条边框圆角 | `12px` | | \--nutui-progress-color | 进度条颜色 | `linear-gradient(135deg, #FF0F23 0%, #fa6419 100%)` | | \--nutui-progress-background | 进度条背景色 | `#f3f3f3` | -| \--nutui-progress-text-color | 文本颜色 | `$color-primary-text` | +| \--nutui-progress-text-color | 文本颜色 | `$color-text-help` | | \--nutui-progress-text-padding | 文本内边距 | `0 5px` | -| \--nutui-progress-text-font-size | 文本字体大小 | `9px` | +| \--nutui-progress-text-font-size | 文本字体大小 | `13px` | | \--nutui-progress-text-position-top | 文本定位 top | `-4px` | | \--nutui-progress-text-position-bottom | 文本定位 bottom | `-4px` | | \--nutui-progress-text-border-radius | 文本边框圆角 | `5px` | diff --git a/src/packages/progress/doc.taro.md b/src/packages/progress/doc.taro.md index 402264bb9f..f3ba4e2bf9 100644 --- a/src/packages/progress/doc.taro.md +++ b/src/packages/progress/doc.taro.md @@ -74,6 +74,12 @@ import { Progress } from '@nutui/nutui-react-taro' ::: +### 设置动画时长与播放方式 + +:::demo + +::: + ## Progress ### Props @@ -88,6 +94,12 @@ import { Progress } from '@nutui/nutui-react-taro' | animated | 是否展示动画效果 | `boolean` | `false` | | lazy | 每次进入可视区展示进度条动画 | `boolean` | `false` | | delay | 延迟数据加载时长,单位 ms | `number` | `0` | +| borderRadius | 进度条圆角大小 | `string` | `0` | +| fontSize | 进度文字大小 | `string` | `12px` | +| activeMode | 动画播放方式 | `forwards \| backwards` | `forwards` | +| duration | 动画完成时间(单位:毫秒) | `number` | `30` | +| ariaLabel | 无障碍标签 | `string` | `-` | +| onActiveEnd | 动画完成后的回调函数 | `() => void` | `-` | ## 主题定制 @@ -101,9 +113,9 @@ import { Progress } from '@nutui/nutui-react-taro' | \--nutui-progress-border-radius | 进度条边框圆角 | `12px` | | \--nutui-progress-color | 进度条颜色 | `linear-gradient(135deg, #FF0F23 0%, #fa6419 100%)` | | \--nutui-progress-background | 进度条背景色 | `#f3f3f3` | -| \--nutui-progress-text-color | 文本颜色 | `$color-primary-text` | +| \--nutui-progress-text-color | 文本颜色 | `$color-text-help` | | \--nutui-progress-text-padding | 文本内边距 | `0 5px` | -| \--nutui-progress-text-font-size | 文本字体大小 | `9px` | +| \--nutui-progress-text-font-size | 文本字体大小 | `13px` | | \--nutui-progress-text-position-top | 文本定位 top | `-4px` | | \--nutui-progress-text-position-bottom | 文本定位 bottom | `-4px` | | \--nutui-progress-text-border-radius | 文本边框圆角 | `5px` | diff --git a/src/packages/progress/doc.zh-TW.md b/src/packages/progress/doc.zh-TW.md index 34ce57ef2f..fa93f275f8 100644 --- a/src/packages/progress/doc.zh-TW.md +++ b/src/packages/progress/doc.zh-TW.md @@ -74,6 +74,12 @@ import { Progress } from '@nutui/nutui-react' ::: +### 設置動畫時長與播放方式 + +:::demo + +::: + ## Progress ### Props @@ -88,6 +94,12 @@ import { Progress } from '@nutui/nutui-react' | animated | 是否展示動畫效果 | `boolean` | `false` | | lazy | 每次進入可視區展示進度條動畫 | `boolean` | `false` | | delay | 延遲數據加載時長,單位 ms | `number` | `0` | +| borderRadius | 進度條圓角大小 | `string` | `0` | +| fontSize | 進度文字大小 | `string` | `12px` | +| activeMode | 動畫播放方式 | `forwards \| backwards` | `forwards` | +| duration | 動畫完成時間(單位:毫秒) | `number` | `30` | +| ariaLabel | 無障礙標簽 | `string` | `-` | +| onActiveEnd | 動畫完成後的回調函數 | `() => void` | `-` | ## 主題定制 @@ -101,9 +113,9 @@ import { Progress } from '@nutui/nutui-react' | \--nutui-progress-border-radius | 進度條邊框圓角 | `12px` | | \--nutui-progress-color | 進度條顏色 | `linear-gradient(135deg, #FF0F23 0%, #fa6419 100%)` | | \--nutui-progress-background | 進度條背景色 | `#f3f3f3` | -| \--nutui-progress-text-color | 文本顏色 | `$color-primary-text` | +| \--nutui-progress-text-color | 文本顏色 | `$color-text-help` | | \--nutui-progress-text-padding | 文本內邊距 | `0 5px` | -| \--nutui-progress-text-font-size | 文本字體大小 | `9px` | +| \--nutui-progress-text-font-size | 文本字體大小 | `13px` | | \--nutui-progress-text-position-top | 文本定位 top | `-4px` | | \--nutui-progress-text-position-bottom | 文本定位 bottom | `-4px` | | \--nutui-progress-text-border-radius | 文本邊框圓角 | `5px` | diff --git a/src/packages/progress/progress.scss b/src/packages/progress/progress.scss index aaf0574783..9b7a7685e3 100644 --- a/src/packages/progress/progress.scss +++ b/src/packages/progress/progress.scss @@ -5,11 +5,10 @@ width: 100%; &-outer { - flex: auto; + flex: 1; border-radius: $progress-border-radius; height: $progress-height; background: $progress-background; - .nut-progress-active:before { content: ''; position: absolute; @@ -35,26 +34,11 @@ &-text { display: flex; align-items: center; - position: absolute; - top: $progress-text-position-top; - bottom: $progress-text-position-bottom; transition: all 0.4s; - transform: translate(-50%); - - &-inner { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - height: 100%; - width: 100%; - color: $progress-text-color; - padding: $progress-text-padding; - border-radius: $progress-text-border-radius; - font-size: $progress-text-font-size; - line-height: 1; - background: $progress-text-background; - } + margin-left: 12px; + color: $color-text-help; + font-family: PingFang SC; + font-size: $progress-text-font-size; } @keyframes progressActive { diff --git a/src/packages/progress/progress.taro.tsx b/src/packages/progress/progress.taro.tsx index 98af8c5b6f..2b48bd8492 100644 --- a/src/packages/progress/progress.taro.tsx +++ b/src/packages/progress/progress.taro.tsx @@ -34,6 +34,17 @@ export const Progress: FunctionComponent< children, lazy, delay, + // tc + showInfo, + borderRadius, + fontSize, + activeColor, + backgroundColor, + active, + activeMode, + duration, + ariaLabel, + onActiveEnd, ...rest } = { ...defaultProps, @@ -41,27 +52,45 @@ export const Progress: FunctionComponent< } const classPrefix = 'nut-progress' + const effectiveShowText = props.showText ?? showInfo ?? defaultProps.showText + const effectiveColor = props.color ?? activeColor ?? defaultProps.color + const effectiveBgColor = + props.background ?? backgroundColor ?? defaultProps.background + const effectiveAnimated = props.animated ?? active ?? defaultProps.animated const classesInner = classNames({ [`${classPrefix}-inner`]: true, - [`${classPrefix}-active`]: animated, + [`${classPrefix}-active`]: effectiveAnimated, }) - const stylesOuter: React.CSSProperties = { - width: '100%', - backgroundColor: background, - } - const [displayPercent, setDispalyPercent] = useState(percent) + const getStyles = () => { + // 基础样式 + const baseStyles = { + height: strokeWidth && pxTransform(Number(strokeWidth)), + borderRadius: + borderRadius && pxTransform(parseInt(borderRadius.toString())), + } + const transitionStyle = { + transition: `width ${duration || 300}ms ease-in-out`, + } - const stylesInner: React.CSSProperties = { - width: `${displayPercent}%`, - background: color || '#FF0F23', + return { + outer: { + width: '100%', + backgroundColor: effectiveBgColor, + ...baseStyles, + }, + inner: { + width: `${displayPercent}%`, + background: effectiveColor || '#FF0F23', + ...baseStyles, + ...transitionStyle, + }, + } } - if (strokeWidth) { - stylesOuter.height = pxTransform(Number(strokeWidth)) - stylesInner.height = pxTransform(Number(strokeWidth)) - } + const { outer: stylesOuter, inner: stylesInner } = getStyles() + const handlePercent = () => { let timer: any = null if (delay) { @@ -77,8 +106,22 @@ export const Progress: FunctionComponent< } } useEffect(() => { - setDispalyPercent(percent) - }, [percent]) + let timer: any = null + if (activeMode === 'backwards') { + setDispalyPercent(0) + timer = setTimeout(() => { + setDispalyPercent(percent) + }, duration || 300) + } else { + setDispalyPercent(percent) + } + + return () => { + if (timer) { + clearTimeout(timer) + } + } + }, [percent, activeMode, duration]) const [intersecting, setIntersecting] = useState(false) const progressRef = useRef(null) @@ -163,7 +206,8 @@ export const Progress: FunctionComponent< } const computeInnerStyle = () => { const style: any = { - backgroundColor: color || '#ff0f23', + backgroundColor: effectiveColor || '#ff0f23', + fontSize: fontSize && pxTransform(parseInt(fontSize.toString())), } if (harmony()) { style.width = harmony() @@ -178,50 +222,24 @@ export const Progress: FunctionComponent< id={selector} className={classNames(classPrefix, className)} style={style} + aria-label={ariaLabel} {...(rest as any)} > + + {effectiveShowText && ( + - {showText && ( - - - {children || ( - - {`${percent}%`} - - )} - - - )} + {children || `${percent}%`} - + )} ) } diff --git a/src/packages/progress/progress.tsx b/src/packages/progress/progress.tsx index a6eebf1031..9c7e7ae506 100644 --- a/src/packages/progress/progress.tsx +++ b/src/packages/progress/progress.tsx @@ -29,6 +29,12 @@ export const Progress: FunctionComponent< children, lazy, delay, + borderRadius, + fontSize, + activeMode, + duration, + ariaLabel, + onActiveEnd, ...rest } = { ...defaultProps, @@ -44,6 +50,7 @@ export const Progress: FunctionComponent< const stylesOuter: React.CSSProperties = { height: `${strokeWidth}px`, + borderRadius: borderRadius && parseInt(borderRadius.toString()), background, } @@ -52,11 +59,27 @@ export const Progress: FunctionComponent< const stylesInner: React.CSSProperties = { width: `${displayPercent}%`, background: color || '#FF0F23', + borderRadius: borderRadius && parseInt(borderRadius.toString()), + transition: `width ${duration || 300}ms ease-in-out`, } useEffect(() => { - setDispalyPercent(percent) - }, [percent]) + let timer: any = null + if (activeMode === 'backwards') { + setDispalyPercent(0) + timer = setTimeout(() => { + setDispalyPercent(percent) + }, duration || 300) + } else { + setDispalyPercent(percent) + } + + return () => { + if (timer) { + clearTimeout(timer) + } + } + }, [percent, activeMode, duration]) const [intersecting, setIntersecting] = useState(false) @@ -112,33 +135,26 @@ export const Progress: FunctionComponent< ref={progressRef} className={classNames(classPrefix, className)} style={style} + aria-label={ariaLabel} {...rest} >
-
- {showText && ( -
- {children || ( -
- {percent}% -
- )} -
- )} -
+
{ + onActiveEnd?.() + }} + />
+ {showText && ( +
+ {children || `${percent}%`} +
+ )}
) } diff --git a/src/styles/variables.scss b/src/styles/variables.scss index 095ae69393..a7ea02b8b3 100644 --- a/src/styles/variables.scss +++ b/src/styles/variables.scss @@ -1665,14 +1665,14 @@ $progress-background: var( $progress-border-radius: var(--nutui-progress-border-radius, 12px) !default; $progress-text-color: var( --nutui-progress-text-color, - $color-primary-text + $color-text-help ) !default; $progress-text-background: var( --nutui-progress-text-background, $color-primary-gradient-1 ) !default; $progress-text-padding: var(--nutui-progress-text-padding, 0 5px) !default; -$progress-text-font-size: var(--nutui-progress-text-font-size, 9px) !default; +$progress-text-font-size: var(--nutui-progress-text-font-size, 13px) !default; $progress-text-position-top: var( --nutui-progress-text-position-top, -4px diff --git a/src/types/spec/progress/base.ts b/src/types/spec/progress/base.ts index 015b313d89..09dac4968d 100644 --- a/src/types/spec/progress/base.ts +++ b/src/types/spec/progress/base.ts @@ -9,4 +9,10 @@ export interface BaseProgress extends BaseProps { animated: boolean lazy: boolean delay: number + borderRadius: string + fontSize: string + activeMode: string + duration: number + ariaLabel: string + onActiveEnd: () => void } diff --git a/src/types/spec/progress/taro.ts b/src/types/spec/progress/taro.ts index 2fb310f7cc..9360370aea 100644 --- a/src/types/spec/progress/taro.ts +++ b/src/types/spec/progress/taro.ts @@ -1,3 +1,8 @@ import { BaseProgress } from './base' -export interface TaroProgressProps extends BaseProgress {} +export interface TaroProgressProps extends BaseProgress { + showInfo: boolean + activeColor: string + backgroundColor: string + active: boolean +}