Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(comp:progress): decimal numbers are display error #1382

Merged
merged 1 commit into from
Jan 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/components/config/src/defaultConfig.ts
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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} />
}
},
})