Skip to content

Commit

Permalink
fix(comp:progress): decimal numbers are display error (#1382)
Browse files Browse the repository at this point in the history
  • Loading branch information
liuzaijiang committed Jan 3, 2023
1 parent 1300c13 commit e474fa5
Show file tree
Hide file tree
Showing 17 changed files with 121 additions and 217 deletions.
4 changes: 4 additions & 0 deletions packages/components/config/src/defaultConfig.ts
Expand Up @@ -232,6 +232,10 @@ export const defaultConfig: GlobalConfig = {
strokeLinecap: 'round',
size: 'md',
format: (percent: number) => percent + '%',
icon: {
success: 'check',
exception: 'close',
},
},
radio: {
size: 'md',
Expand Down
4 changes: 1 addition & 3 deletions packages/components/config/src/types.ts
Expand Up @@ -365,10 +365,8 @@ export interface PopoverConfig {
export interface ProgressConfig {
size: ProgressSize
format: ProgressFormat
defaultCircleStrokeWidth?: string | number
strokeWidth?: string | number
strokeLinecap: 'round' | 'square'
icon?: Partial<ProgressIcons>
icon: Partial<ProgressIcons>
}

export interface RadioConfig {
Expand Down
3 changes: 3 additions & 0 deletions packages/components/progress/__tests__/progress.spec.ts
Expand Up @@ -28,6 +28,9 @@ describe('Progress', () => {
await wrapper.setProps({ percent: 50 })
expect(wrapper.text()).toBe('50%')

await wrapper.setProps({ percent: 60.7 })
expect(wrapper.text()).toBe('60.7%')

await wrapper.setProps({ percent: 100 })
expect(wrapper.text()).toBe('')
})
Expand Down
25 changes: 16 additions & 9 deletions packages/components/progress/demo/Round.vue
@@ -1,11 +1,18 @@
<template>
<IxProgress stroke-linecap="square" :percent="75" />
<IxProgress stroke-linecap="square" :percent="75" type="circle" />
<IxProgress stroke-linecap="square" :percent="75" type="dashboard" />
<IxSpace vertical block>
<IxRadioGroup v-model:value="valueRef">
<IxRadio value="square">square</IxRadio>
<IxRadio value="round">round</IxRadio>
</IxRadioGroup>
<IxProgress :strokeLinecap="valueRef" :percent="75" />
<IxProgress :strokeLinecap="valueRef" :percent="75" type="circle" />
<IxProgress :strokeLinecap="valueRef" :percent="75" type="dashboard" />
</IxSpace>
</template>
<style scoped>
.ix-progress-circle {
margin-right: 8px;
margin-bottom: 5px;
}
</style>
<script lang="ts" setup>
import { ref } from 'vue'
import { type ProgressStrokeLinecap } from '@idux/components/progress'
const valueRef = ref<ProgressStrokeLinecap>('square')
</script>
6 changes: 3 additions & 3 deletions packages/components/progress/docs/Api.zh.md
Expand Up @@ -16,22 +16,22 @@
| `trailColor` | 未完成的分段的颜色 | `string` | - | - | - |
| `strokeColor` | 进度条的色彩 | `string` | - | - | - |
| `strokeLinecap` | 进度条的样式 | `'round' \| 'square'` | `'round'` || `seer` 主题默认为 `'square'` |
| `icons` | 进度条状态图标 | `{ success: string \| VNode, exception: string \| VNode }` | - || - |
| `icons` | 进度条状态图标 | `{ success: string \| VNode, exception: string \| VNode }` | `{success: 'check', exception: 'close'}` || - |

`type="line"`

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `size` | 进度条尺寸 | `lg \| 'md' \| 'sm'` | `'md'` || - |
| `strokeColor` | 进度条的色彩,传入 object 时为渐变 | `string` \| { from: string; to: string; direction: string } | - | - | - |
| `strokeColor` | 进度条的色彩,传入 object 时为渐变 | `string` \| `{ from: string; to: string; direction: string }` | - | - | - |
| `strokeWidth` | 进度条线的宽度,单位 px | `number` | 10 | - | - |

`type="circle"`

| 名称 | 说明 | 类型 | 默认值 | 全局配置 | 备注 |
| --- | --- | --- | --- | --- | --- |
| `width` | 圆形进度条画布宽度,单位 px | `number` | 132 | - | - |
| `strokeColor` | 圆形进度条的色彩,传入 object 时为渐变 | `string \| object` | - | - | - |
| `strokeColor` | 圆形进度条的色彩,传入 object 时为渐变 | `string` \| `{ from: string; to: string; direction: string }` | - | - | - |
| `strokeWidth` | 圆形进度条线的宽度,单位是进度条画布宽度的百分比 | `number` | 6 | - | - |

`type="dashboard"`
Expand Down
56 changes: 26 additions & 30 deletions packages/components/progress/src/Circle.tsx
Expand Up @@ -5,16 +5,15 @@
* found in the LICENSE file at https://github.com/IDuxFE/idux/blob/main/LICENSE
*/

import { ComputedRef, computed, defineComponent, inject, ref } from 'vue'
import { ComputedRef, computed, defineComponent, inject } from 'vue'

import { isObject } from 'lodash-es'

import { convertNumber, uniqueId } from '@idux/cdk/utils'

import ProgressInfo from './ProgressInfo'
import { useProps } from './composables/useProps'
import { progressContext } from './tokens'
import { ConvertProgressSuccess, ProgressGapPositionType, ProgressProps, StringGradients } from './types'
import { ProgressGapPositionType, ProgressProps, StringGradients } from './types'
import { handleCircleGradient } from './util'

export interface CalcSharedProperties {
Expand All @@ -31,48 +30,46 @@ const defaultStrokeWidth = 6

export default defineComponent({
name: 'IxProgressCircle',
setup() {
const { props, config, mergedPrefixCls, percent, formattedSuccess } = inject(progressContext)!
setup(_, { slots }) {
const { props, mergedPrefixCls, mergedStrokeLinecap, percent, successPercent } = inject(progressContext)!

const circleMergedPrefixCls = computed(() => `${mergedPrefixCls.value}-circle`)
const computedProps = useProps(props, config)

const strokeWidth = computed(() =>
convertNumber(computedProps.value.strokeWidth ?? config.defaultCircleStrokeWidth, defaultStrokeWidth),
)
const isGradient = computed(() => isObject(computedProps.value.strokeColor))
const linearGradientId = ref(`ix-progress-gradient-${uniqueId()}`)
const strokeWidth = computed(() => convertNumber(props.strokeWidth, defaultStrokeWidth))
const isGradient = computed(() => isObject(props.strokeColor))
const linearGradientId = computed(() => `${mergedPrefixCls.value}-gradient-${uniqueId()}`)

const calcSharedProperties = computed<CalcSharedProperties>(() => {
const isCircle = computedProps.value.type === 'circle'
const isCircle = props.type === 'circle'
const radius = 50 - strokeWidth.value / 2
return {
isGradient: isGradient.value,
percent: percent.value,
linearGradientId: linearGradientId.value,
radius,
gapPosition: computedProps.value.gapPosition ?? (isCircle ? 'top' : 'bottom'),
gapPosition: props.gapPosition ?? (isCircle ? 'top' : 'bottom'),
len: Math.PI * 2 * radius,
gapDegree: convertNumber(computedProps.value.gapDegree ?? (isCircle ? 0 : 75)),
gapDegree: convertNumber(props.gapDegree ?? (isCircle ? 0 : 75)),
}
})
const circleGradient = computed(() => {
return isGradient.value ? handleCircleGradient(computedProps.value.strokeColor as StringGradients) : []
return isGradient.value ? handleCircleGradient(props.strokeColor as StringGradients) : []
})
const pathString = usePathString(calcSharedProperties)
const trailPathStyle = useTrailPathStyle(calcSharedProperties)
const strokePath = useCirclePath(calcSharedProperties, computedProps.value, percent, formattedSuccess)
const strokePath = useCirclePath(calcSharedProperties, circleMergedPrefixCls, props, percent, successPercent)

const trailPathAttr = computed(() => ({
stroke: computedProps.value.trailColor ?? '#f5f5f5',
stroke: props.trailColor ?? '#f5f5f5',
'fill-opacity': '0',
'stroke-linecap': computedProps.value.strokeLinecap,
'stroke-linecap': mergedStrokeLinecap.value,
'stroke-width': strokeWidth.value,
d: pathString.value,
}))
const strokePathAttr = computed(() => ({
'fill-opacity': '0',
'stroke-linecap': computedProps.value.strokeLinecap,
'stroke-width': computedProps.value.percent ? strokeWidth.value : 0,
'stroke-linecap': mergedStrokeLinecap.value,
'stroke-width': percent.value ? strokeWidth.value : 0,
d: pathString.value,
}))

Expand All @@ -85,9 +82,9 @@ export default defineComponent({
}
})
const circleStyle = computed(() => ({
width: computedProps.value.width && `${computedProps.value.width}px`,
height: computedProps.value.width && `${computedProps.value.width}px`,
fontSize: computedProps.value.width && `${convertNumber(computedProps.value.width) * 0.15 + 6}px`,
width: props.width && `${props.width}px`,
height: props.width && `${props.width}px`,
fontSize: props.width && `${convertNumber(props.width) * 0.15 + 6}px`,
}))

const renderDefs = () => {
Expand Down Expand Up @@ -127,7 +124,7 @@ export default defineComponent({
></path>
{renderStrokePath()}
</svg>
<ProgressInfo />
<ProgressInfo v-slots={slots} />
</div>
)
},
Expand Down Expand Up @@ -184,15 +181,14 @@ function useTrailPathStyle(calcSharedProperties: ComputedRef<CalcSharedPropertie

function useCirclePath(
calcSharedProperties: ComputedRef<CalcSharedProperties>,
circleMergedPrefixCls: ComputedRef<string>,
props: ProgressProps,
percent: ComputedRef<number>,
success: ComputedRef<ConvertProgressSuccess>,
successPercent: ComputedRef<number>,
) {
return computed(() => {
const successPercent = success.value.percent

const { gapDegree, len, isGradient, linearGradientId } = calcSharedProperties.value
const strokeProgress = successPercent > 0 ? [successPercent, percent.value] : [percent.value]
const strokeProgress = successPercent.value > 0 ? [successPercent.value, percent.value] : [percent.value]
const successColor = props.success?.strokeColor

return strokeProgress
Expand All @@ -201,8 +197,8 @@ function useCirclePath(
return {
stroke: isGradient && !hasSuccessPercent ? `url(#${linearGradientId})` : undefined,
strokeClasses: [
!isGradient && hasSuccessPercent ? 'ix-progress-circle-success' : '',
isGradient ? '' : 'ix-progress-circle-bg',
!isGradient && hasSuccessPercent ? `${circleMergedPrefixCls.value}-success` : '',
isGradient ? '' : `${circleMergedPrefixCls.value}-bg`,
],
strokePathStyle: {
stroke: !isGradient ? (hasSuccessPercent ? successColor : (props.strokeColor as string)) : undefined,
Expand Down
36 changes: 16 additions & 20 deletions packages/components/progress/src/Line.tsx
Expand Up @@ -10,57 +10,53 @@ import { computed, defineComponent, inject, ref } from 'vue'
import { isObject } from 'lodash-es'

import ProgressInfo from './ProgressInfo'
import { useProps } from './composables/useProps'
import { progressContext } from './tokens'
import { handleGradient } from './util'

export default defineComponent({
name: 'IxProgressLine',
setup() {
const { props, config, mergedPrefixCls, percent, formattedSuccess } = inject(progressContext)!
const computedProps = useProps(props, config)
setup(_, { slots }) {
const { props, mergedPrefixCls, mergedSize, mergedStrokeLinecap, percent, successPercent } =
inject(progressContext)!

const lineMergedPrefixCls = computed(() => `${mergedPrefixCls.value}-line`)

const elementRef = ref<HTMLDivElement>()
const lineClasses = computed(() => {
const classes = computed(() => {
const prefixCls = lineMergedPrefixCls.value

return {
[prefixCls]: true,
[`${prefixCls}-${computedProps.value.size}`]: true,
[`${prefixCls}-round`]: computedProps.value.strokeLinecap === 'round',
[`${prefixCls}-${mergedSize.value}`]: true,
[`${prefixCls}-round`]: mergedStrokeLinecap.value === 'round',
}
})
const innerStyle = computed(() => ({
background: computedProps.value.trailColor ?? '',
background: props.trailColor,
}))
const successStyle = computed(() => ({
height: computedProps.value.strokeWidth && `${computedProps.value.strokeWidth}px`,
width: `${formattedSuccess.value.percent ?? 0}%`,
background: formattedSuccess.value.strokeColor ?? '',
height: `${props.strokeWidth}px`,
width: `${successPercent.value}%`,
background: props.success?.strokeColor,
}))
const bgStyle = computed(() => ({
height: computedProps.value.strokeWidth && `${computedProps.value.strokeWidth}px`,
height: `${props.strokeWidth}px`,
width: `${percent.value}%`,
background: isObject(computedProps.value.strokeColor)
? handleGradient(computedProps.value.strokeColor, elementRef.value)
: computedProps.value.strokeColor ?? '',
background: isObject(props.strokeColor) ? handleGradient(props.strokeColor, elementRef.value) : props.strokeColor,
}))

return () => {
const prefixCls = lineMergedPrefixCls.value

return (
<div ref={elementRef} class={lineClasses.value}>
<div ref={elementRef} class={classes.value}>
<div class={`${prefixCls}-outer`}>
<div class={`${prefixCls}-inner`} style={innerStyle.value}>
{computedProps.value.success?.percent && (
<div class={`${prefixCls}-success-bg`} style={successStyle.value}></div>
)}
{!!successPercent.value && <div class={`${prefixCls}-success-bg`} style={successStyle.value}></div>}
<div class={`${prefixCls}-bg`} style={bgStyle.value}></div>
</div>
</div>
<ProgressInfo />
<ProgressInfo v-slots={slots} />
</div>
)
}
Expand Down
27 changes: 19 additions & 8 deletions packages/components/progress/src/Progress.tsx
Expand Up @@ -11,10 +11,9 @@ import { useGlobalConfig } from '@idux/components/config'

import Circle from './Circle'
import Line from './Line'
import { useStatus } from './composables/useStatus'
import { progressContext } from './tokens'
import { progressProps } from './types'
import { convertPercent } from './util'
import { progressProps, progressStatus } from './types'
import { convertPercent, fullPercent } from './util'

export default defineComponent({
name: 'IxProgress',
Expand All @@ -25,9 +24,20 @@ export default defineComponent({
const mergedPrefixCls = computed(() => `${common.prefixCls}-progress`)

const percent = computed(() => convertPercent(props.percent))
const formattedSuccess = computed(() => ({ ...props.success, percent: convertPercent(props.success?.percent) }))
const successPercent = computed(() => convertPercent(props.success?.percent))
const mergedSize = computed(() => props.size ?? config.size)
const mergedStrokeLinecap = computed(() => props.strokeLinecap ?? config.strokeLinecap)

const status = useStatus(props, percent, formattedSuccess)
const status = computed(() => {
if (
!progressStatus.includes(props.status!) &&
(percent.value >= fullPercent || successPercent.value >= fullPercent)
) {
return 'success'
}

return props.status ?? 'normal'
})

const classes = computed(() => {
const prefixCls = mergedPrefixCls.value
Expand All @@ -40,16 +50,17 @@ export default defineComponent({
provide(progressContext, {
props,
config,
slots,
mergedPrefixCls,
mergedSize,
mergedStrokeLinecap,
percent,
formattedSuccess,
successPercent,
status,
})

return () => {
const ProgressComponent = props.type === 'line' ? Line : Circle
return <ProgressComponent class={classes.value} />
return <ProgressComponent v-slots={slots} class={classes.value} />
}
},
})

0 comments on commit e474fa5

Please sign in to comment.