diff --git a/components/progress/progress.tsx b/components/progress/progress.tsx index e8fdd7aa43..f51340a049 100644 --- a/components/progress/progress.tsx +++ b/components/progress/progress.tsx @@ -12,10 +12,13 @@ import useConfigInject from '../config-provider/hooks/useConfigInject'; import devWarning from '../vc-util/devWarning'; import { progressProps, progressStatuses } from './props'; import type { VueNode } from '../_util/type'; +import useStyle from './style'; +import classNames from '../_util/classNames'; export default defineComponent({ compatConfig: { MODE: 3 }, name: 'AProgress', + inheritAttrs: false, props: initDefaultProps(progressProps(), { type: 'line', percent: 0, @@ -26,8 +29,9 @@ export default defineComponent({ strokeLinecap: 'round', }), slots: ['format'], - setup(props, { slots }) { + setup(props, { slots, attrs }) { const { prefixCls, direction } = useConfigInject('progress', props); + const [wrapSSR, hashId] = useStyle(prefixCls); devWarning( props.successPercent == undefined, 'Progress', @@ -37,6 +41,7 @@ export default defineComponent({ const { type, showInfo, size } = props; const pre = prefixCls.value; return { + [hashId.value]: true, [pre]: true, [`${pre}-${(type === 'dashboard' && 'circle') || type}`]: true, [`${pre}-show-info`]: showInfo, @@ -93,6 +98,7 @@ export default defineComponent({ return () => { const { type, steps, strokeColor, title } = props; + const { class: cls, ...restAttrs } = attrs; const progressInfo = renderProcessInfo(); let progress: VueNode; @@ -120,15 +126,14 @@ export default defineComponent({ ); } - const classNames = { - ...classString.value, + const classes = classNames(classString.value, { [`${prefixCls.value}-status-${progressStatus.value}`]: true, - }; + }); - return ( -
+ return wrapSSR( +
{progress} -
+
, ); }; }, diff --git a/components/progress/style/index.less b/components/progress/style/index.less deleted file mode 100644 index 9ba9914378..0000000000 --- a/components/progress/style/index.less +++ /dev/null @@ -1,210 +0,0 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; - -@progress-prefix-cls: ~'@{ant-prefix}-progress'; - -.@{progress-prefix-cls} { - .reset-component(); - - display: inline-block; - - &-line { - position: relative; - width: 100%; - font-size: @font-size-base; - } - - &-steps { - display: inline-block; - - &-outer { - display: flex; - flex-direction: row; - align-items: center; - } - - &-item { - flex-shrink: 0; - min-width: 2px; - margin-right: 2px; - background: @progress-steps-item-bg; - transition: all 0.3s; - - &-active { - background: @progress-default-color; - } - } - } - - &-small&-line, - &-small&-line &-text .@{iconfont-css-prefix} { - font-size: @font-size-sm; - } - - &-outer { - display: inline-block; - width: 100%; - margin-right: 0; - padding-right: 0; - .@{progress-prefix-cls}-show-info & { - margin-right: ~'calc(-2em - 8px)'; - padding-right: ~'calc(2em + 8px)'; - } - } - - &-inner { - position: relative; - display: inline-block; - width: 100%; - overflow: hidden; - vertical-align: middle; - background-color: @progress-remaining-color; - border-radius: @progress-radius; - } - - &-circle-trail { - stroke: @progress-remaining-color; - } - - &-circle-path { - animation: ~'@{ant-prefix}-progress-appear' 0.3s; - } - - &-inner:not(.@{ant-prefix}-progress-circle-gradient) { - .@{ant-prefix}-progress-circle-path { - stroke: @progress-default-color; - } - } - - &-success-bg, - &-bg { - position: relative; - background-color: @progress-default-color; - border-radius: @progress-radius; - transition: all 0.4s @ease-out-circ 0s; - } - - &-success-bg { - position: absolute; - top: 0; - left: 0; - background-color: @success-color; - } - - &-text { - display: inline-block; - width: 2em; - margin-left: 8px; - color: @progress-info-text-color; - font-size: @progress-text-font-size; - line-height: 1; - white-space: nowrap; - text-align: left; - vertical-align: middle; - word-break: normal; - .@{iconfont-css-prefix} { - font-size: @font-size-base; - } - } - - &-status-active { - .@{progress-prefix-cls}-bg::before { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 0; - background: @component-background; - border-radius: 10px; - opacity: 0; - animation: ~'@{ant-prefix}-progress-active' 2.4s @ease-out-quint infinite; - content: ''; - } - } - - &-status-exception { - .@{progress-prefix-cls}-bg { - background-color: @error-color; - } - .@{progress-prefix-cls}-text { - color: @error-color; - } - } - - &-status-exception &-inner:not(.@{progress-prefix-cls}-circle-gradient) { - .@{progress-prefix-cls}-circle-path { - stroke: @error-color; - } - } - - &-status-success { - .@{progress-prefix-cls}-bg { - background-color: @success-color; - } - .@{progress-prefix-cls}-text { - color: @success-color; - } - } - - &-status-success &-inner:not(.@{progress-prefix-cls}-circle-gradient) { - .@{progress-prefix-cls}-circle-path { - stroke: @success-color; - } - } - - &-circle &-inner { - position: relative; - line-height: 1; - background-color: transparent; - } - - &-circle &-text { - position: absolute; - top: 50%; - left: 50%; - width: 100%; - margin: 0; - padding: 0; - color: @progress-text-color; - font-size: @progress-circle-text-font-size; - line-height: 1; - white-space: normal; - text-align: center; - transform: translate(-50%, -50%); - - .@{iconfont-css-prefix} { - font-size: (14 / 12em); - } - } - - &-circle&-status-exception { - .@{progress-prefix-cls}-text { - color: @error-color; - } - } - - &-circle&-status-success { - .@{progress-prefix-cls}-text { - color: @success-color; - } - } -} - -@keyframes ~"@{ant-prefix}-progress-active" { - 0% { - transform: translateX(-100%) scaleX(0); - opacity: 0.1; - } - - 20% { - transform: translateX(-100%) scaleX(0); - opacity: 0.5; - } - - 100% { - transform: translateX(0) scaleX(1); - opacity: 0; - } -} - -@import './rtl'; diff --git a/components/progress/style/index.ts b/components/progress/style/index.ts new file mode 100644 index 0000000000..76a210e71e --- /dev/null +++ b/components/progress/style/index.ts @@ -0,0 +1,274 @@ +import type { CSSObject } from '../../_util/cssinjs'; +import { Keyframes } from '../../_util/cssinjs'; +import type { FullToken, GenerateStyle } from '../../theme/internal'; +import { genComponentStyleHook, mergeToken } from '../../theme/internal'; +import { resetComponent } from '../../_style'; + +export interface ComponentToken {} + +interface ProgressToken extends FullToken<'Progress'> { + progressLineRadius: number; + progressInfoTextColor: string; + progressRemainingColor: string; + progressDefaultColor: string; + progressStepMinWidth: number; + progressStepMarginInlineEnd: number; + progressActiveMotionDuration: string; +} + +const antProgressActive = new Keyframes('antProgressActive', { + '0%': { + transform: 'translateX(-100%) scaleX(0)', + opacity: 0.1, + }, + '20%': { + transform: 'translateX(-100%) scaleX(0)', + opacity: 0.5, + }, + to: { + transform: 'translateX(0) scaleX(1)', + opacity: 0, + }, +}); + +const genBaseStyle: GenerateStyle = token => { + const { componentCls: progressCls, iconCls: iconPrefixCls } = token; + + return { + [progressCls]: { + ...resetComponent(token), + + display: 'inline-block', + + '&-rtl': { + direction: 'rtl', + }, + + '&-line': { + position: 'relative', + width: '100%', + fontSize: token.fontSize, + marginInlineEnd: token.marginXS, + marginBottom: token.marginXS, + }, + + [`${progressCls}-outer`]: { + display: 'inline-block', + width: '100%', + }, + + [`&${progressCls}-show-info`]: { + [`${progressCls}-outer`]: { + marginInlineEnd: `calc(-2em - ${token.marginXS}px)`, + paddingInlineEnd: `calc(2em + ${token.paddingXS}px)`, + }, + }, + + [`${progressCls}-inner`]: { + position: 'relative', + display: 'inline-block', + width: '100%', + overflow: 'hidden', + verticalAlign: 'middle', + backgroundColor: token.progressRemainingColor, + borderRadius: token.progressLineRadius, + }, + + [`${progressCls}-inner:not(${progressCls}-circle-gradient)`]: { + [`${progressCls}-circle-path`]: { + stroke: token.colorInfo, + }, + }, + + [`${progressCls}-success-bg, ${progressCls}-bg`]: { + position: 'relative', + backgroundColor: token.colorInfo, + borderRadius: token.progressLineRadius, + transition: `all ${token.motionDurationSlow} ${token.motionEaseInOutCirc}`, + }, + + [`${progressCls}-success-bg`]: { + position: 'absolute', + insetBlockStart: 0, + insetInlineStart: 0, + backgroundColor: token.colorSuccess, + }, + + [`${progressCls}-text`]: { + display: 'inline-block', + width: '2em', + marginInlineStart: token.marginXS, + color: token.progressInfoTextColor, + lineHeight: 1, + whiteSpace: 'nowrap', + textAlign: 'start', + verticalAlign: 'middle', + wordBreak: 'normal', + [iconPrefixCls]: { + fontSize: token.fontSize, + }, + }, + + [`&${progressCls}-status-active`]: { + [`${progressCls}-bg::before`]: { + position: 'absolute', + inset: 0, + backgroundColor: token.colorBgContainer, + borderRadius: token.progressLineRadius, + opacity: 0, + animationName: antProgressActive, + animationDuration: token.progressActiveMotionDuration, + animationTimingFunction: token.motionEaseOutQuint, + animationIterationCount: 'infinite', + content: '""', + }, + }, + + [`&${progressCls}-status-exception`]: { + [`${progressCls}-bg`]: { + backgroundColor: token.colorError, + }, + [`${progressCls}-text`]: { + color: token.colorError, + }, + }, + + [`&${progressCls}-status-exception ${progressCls}-inner:not(${progressCls}-circle-gradient)`]: + { + [`${progressCls}-circle-path`]: { + stroke: token.colorError, + }, + }, + + [`&${progressCls}-status-success`]: { + [`${progressCls}-bg`]: { + backgroundColor: token.colorSuccess, + }, + [`${progressCls}-text`]: { + color: token.colorSuccess, + }, + }, + + [`&${progressCls}-status-success ${progressCls}-inner:not(${progressCls}-circle-gradient)`]: { + [`${progressCls}-circle-path`]: { + stroke: token.colorSuccess, + }, + }, + }, + }; +}; + +const genCircleStyle: GenerateStyle = token => { + const { componentCls: progressCls, iconCls: iconPrefixCls } = token; + + return { + [progressCls]: { + [`${progressCls}-circle-trail`]: { + stroke: token.progressRemainingColor, + }, + + [`&${progressCls}-circle ${progressCls}-inner`]: { + position: 'relative', + lineHeight: 1, + backgroundColor: 'transparent', + }, + + [`&${progressCls}-circle ${progressCls}-text`]: { + position: 'absolute', + insetBlockStart: '50%', + insetInlineStart: 0, + width: '100%', + margin: 0, + padding: 0, + color: token.colorText, + lineHeight: 1, + whiteSpace: 'normal', + textAlign: 'center', + transform: 'translateY(-50%)', + + [iconPrefixCls]: { + fontSize: `${token.fontSize / token.fontSizeSM}em`, + }, + }, + + [`${progressCls}-circle&-status-exception`]: { + [`${progressCls}-text`]: { + color: token.colorError, + }, + }, + + [`${progressCls}-circle&-status-success`]: { + [`${progressCls}-text`]: { + color: token.colorSuccess, + }, + }, + }, + [`${progressCls}-inline-circle`]: { + lineHeight: 1, + [`${progressCls}-inner`]: { + verticalAlign: 'bottom', + }, + }, + }; +}; + +const genStepStyle: GenerateStyle = (token: ProgressToken): CSSObject => { + const { componentCls: progressCls } = token; + + return { + [progressCls]: { + [`${progressCls}-steps`]: { + display: 'inline-block', + '&-outer': { + display: 'flex', + flexDirection: 'row', + alignItems: 'center', + }, + '&-item': { + flexShrink: 0, + minWidth: token.progressStepMinWidth, + marginInlineEnd: token.progressStepMarginInlineEnd, + backgroundColor: token.progressRemainingColor, + transition: `all ${token.motionDurationSlow}`, + + '&-active': { + backgroundColor: token.colorInfo, + }, + }, + }, + }, + }; +}; + +const genSmallLine: GenerateStyle = (token: ProgressToken): CSSObject => { + const { componentCls: progressCls, iconCls: iconPrefixCls } = token; + + return { + [progressCls]: { + [`${progressCls}-small&-line, ${progressCls}-small&-line ${progressCls}-text ${iconPrefixCls}`]: + { + fontSize: token.fontSizeSM, + }, + }, + }; +}; + +export default genComponentStyleHook('Progress', token => { + const progressStepMarginInlineEnd = token.marginXXS / 2; + + const progressToken = mergeToken(token, { + progressLineRadius: 100, // magic for capsule shape, should be a very large number + progressInfoTextColor: token.colorText, + progressDefaultColor: token.colorInfo, + progressRemainingColor: token.colorFillSecondary, + progressStepMarginInlineEnd, + progressStepMinWidth: progressStepMarginInlineEnd, + progressActiveMotionDuration: '2.4s', + }); + return [ + genBaseStyle(progressToken), + genCircleStyle(progressToken), + genStepStyle(progressToken), + genSmallLine(progressToken), + ]; +}); diff --git a/components/progress/style/index.tsx b/components/progress/style/index.tsx deleted file mode 100644 index 3a3ab0de59..0000000000 --- a/components/progress/style/index.tsx +++ /dev/null @@ -1,2 +0,0 @@ -import '../../style/index.less'; -import './index.less'; diff --git a/components/progress/style/rtl.less b/components/progress/style/rtl.less deleted file mode 100644 index 0756b5f847..0000000000 --- a/components/progress/style/rtl.less +++ /dev/null @@ -1,37 +0,0 @@ -@import '../../style/themes/index'; -@import '../../style/mixins/index'; - -@progress-prefix-cls: ~'@{ant-prefix}-progress'; - -.@{progress-prefix-cls} { - &-rtl { - direction: rtl; - } - - &-outer { - .@{progress-prefix-cls}-show-info & { - .@{progress-prefix-cls}-rtl& { - margin-right: 0; - margin-left: ~'calc(-2em - 8px)'; - padding-right: 0; - padding-left: ~'calc(2em + 8px)'; - } - } - } - - &-success-bg { - .@{progress-prefix-cls}-rtl & { - right: 0; - left: auto; - } - } - - &-line &-text, - &-steps &-text { - .@{progress-prefix-cls}-rtl& { - margin-right: 8px; - margin-left: 0; - text-align: right; - } - } -} diff --git a/components/style.ts b/components/style.ts index 338d6438b8..0ab8e11ce1 100644 --- a/components/style.ts +++ b/components/style.ts @@ -38,7 +38,7 @@ import './calendar/style'; import './date-picker/style'; import './slider/style'; import './table/style'; -import './progress/style'; +// import './progress/style'; import './timeline/style'; import './input-number/style'; import './transfer/style'; diff --git a/components/theme/interface/components.ts b/components/theme/interface/components.ts index 8e7a5bf3cb..be28a99e60 100644 --- a/components/theme/interface/components.ts +++ b/components/theme/interface/components.ts @@ -26,7 +26,7 @@ import type { ComponentToken as ModalComponentToken } from '../../modal/style'; import type { ComponentToken as NotificationComponentToken } from '../../notification/style'; import type { ComponentToken as PopconfirmComponentToken } from '../../popconfirm/style'; import type { ComponentToken as PopoverComponentToken } from '../../popover/style'; -// import type { ComponentToken as ProgressComponentToken } from '../../progress/style'; +import type { ComponentToken as ProgressComponentToken } from '../../progress/style'; // import type { ComponentToken as RadioComponentToken } from '../../radio/style'; // import type { ComponentToken as RateComponentToken } from '../../rate/style'; // import type { ComponentToken as ResultComponentToken } from '../../result/style'; @@ -109,7 +109,7 @@ export interface ComponentTokenMap { Tooltip?: TooltipComponentToken; // Table?: TableComponentToken; // Space?: SpaceComponentToken; - // Progress?: ProgressComponentToken; + Progress?: ProgressComponentToken; // Tour?: TourComponentToken; // QRCode?: QRCodeComponentToken; // App?: AppComponentToken;