Skip to content

Commit a770eb3

Browse files
tangjinzhoufanhaoyuanJohn60676axetroyzanllp
authored
Refactor progress (#4358)
* fix: timepicker error border not show #4331 * fix(UploadDragger): fix UploadDrager no export (#4334) * refactor(switch): support customize checked value #4329 (#4332) * refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimize * style: uncheckedValue to unCheckedValue * test: update snap * feat: udpate switch ts * docs: remove ie11 * fix: tree-select throw error when use slot title * fix: TypeScript definition of Table interface for typescript 4.3.5 (#4353) * fix type for typescript 4.3.5 * Update interface.ts close #4296 * fix: dropdown submenu style error #4351 close #4351 * fix(notification): 完善notification类型 (#4346) * refactor(progress): use composition API (#4355) * refactor(progress): use composition API * refactor(vc-progress): update * refactor: progress * refactor: progress * fix: timepicker error border not show #4331 * fix(UploadDragger): fix UploadDrager no export (#4334) * refactor(switch): support customize checked value #4329 (#4332) * refactor(switch): support customize checked value #4329 * test: add test case * refactor: update props name * refactor: update ts * refactor: optimize * style: uncheckedValue to unCheckedValue * test: update snap * feat: udpate switch ts * docs: remove ie11 * fix: tree-select throw error when use slot title * fix: TypeScript definition of Table interface for typescript 4.3.5 (#4353) * fix type for typescript 4.3.5 * Update interface.ts close #4296 * fix: dropdown submenu style error #4351 close #4351 * fix(notification): 完善notification类型 (#4346) * refactor(progress): use composition API (#4355) * refactor(progress): use composition API * refactor(vc-progress): update * refactor: progress * refactor: progress Co-authored-by: Jarvis <[email protected]> Co-authored-by: John <[email protected]> Co-authored-by: 艾斯特洛 <[email protected]> Co-authored-by: zanllp <[email protected]>
1 parent f7b39e2 commit a770eb3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1399
-794
lines changed

CHANGELOG.en-US.md

-1
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,6 @@
437437

438438
### Compatibility adjustment
439439

440-
- The minimum supported version of IE is IE 11.
441440
- The minimum supported version of Vue is Vue 3.0.
442441

443442
#### Adjusted API

CHANGELOG.zh-CN.md

-1
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,6 @@
440440

441441
### 兼容性调整
442442

443-
- IE 最低支持版本为 IE 11。
444443
- Vue 最低支持版本为 Vue 3.0。
445444

446445
#### 调整的 API

README-zh_CN.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ An enterprise-class UI components based on Ant Design and Vue 3.
2828

2929
## 支持环境
3030

31-
- 现代浏览器和 IE11 及以上。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性)
31+
- 现代浏览器。1.x 版本支持 IE 9+(需要 [polyfills](https://www.antdv.com/docs/vue/getting-started-cn/#兼容性)
3232
- 支持服务端渲染。
3333
- [Electron](https://electronjs.org/)
3434
- 支持 Vue 2 和 Vue 3

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ English | [简体中文](./README-zh_CN.md)
2828

2929
## Environment Support
3030

31-
- Modern browsers and Internet Explorer 11+. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#Compatibility))
31+
- Modern browsers. v1.x support Internet Explorer 9+ (with [polyfills](https://www.antdv.com/docs/vue/getting-started/#Compatibility))
3232
- Server-side Rendering
3333
- Support Vue 2 & Vue 3
3434
- [Electron](https://electronjs.org/)

components/_util/hooks/useRef.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@ import type { Ref } from 'vue';
22
import { onBeforeUpdate, ref } from 'vue';
33

44
export type UseRef = [(el: any, key: string | number) => void, Ref<any>];
5-
5+
export type Refs = Record<string | number, any>;
66
export const useRef = (): UseRef => {
7-
const refs = ref<any>({});
7+
const refs = ref<Refs>({});
88
const setRef = (el: any, key: string | number) => {
99
refs.value[key] = el;
1010
};
@@ -13,3 +13,5 @@ export const useRef = (): UseRef => {
1313
});
1414
return [setRef, refs];
1515
};
16+
17+
export default useRef;

components/components.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,6 @@ export {
192192

193193
export type { UploadProps } from './upload';
194194

195-
export { default as Upload } from './upload';
195+
export { default as Upload, UploadDragger } from './upload';
196196

197197
export { default as LocaleProvider } from './locale-provider';

components/dropdown/dropdown.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ const Dropdown = defineComponent({
6363
// menu should be focusable in dropdown defaultly
6464
const overlayProps = overlayNode && getPropsData(overlayNode);
6565
const { selectable = false, focusable = true } = (overlayProps || {}) as any;
66-
const expandIcon = (
66+
const expandIcon = () => (
6767
<span class={`${prefixCls}-menu-submenu-arrow`}>
6868
<RightOutlined class={`${prefixCls}-menu-submenu-arrow-icon`} />
6969
</span>

components/dropdown/style/index.less

+3-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@
6868
&-submenu-popup {
6969
position: absolute;
7070
z-index: @zindex-dropdown;
71+
background: transparent;
72+
box-shadow: none;
73+
transform-origin: 0 0;
7174

7275
> .@{dropdown-prefix-cls}-menu {
7376
transform-origin: 0 0;
@@ -81,7 +84,6 @@
8184
ul {
8285
margin-right: 0.3em;
8386
margin-left: 0.3em;
84-
padding: 0;
8587
}
8688
}
8789

components/locale-provider/__tests__/__snapshots__/index.test.js.snap

+51-51
Large diffs are not rendered by default.

components/menu/src/Menu.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ export const menuProps = {
4949
triggerSubMenuAction: { type: String as PropType<TriggerSubMenuAction>, default: 'hover' },
5050

5151
getPopupContainer: Function as PropType<(node: HTMLElement) => HTMLElement>,
52+
53+
expandIcon: Function as PropType<(p?: { isOpen: boolean; [key: string]: any }) => any>,
5254
};
5355

5456
export type MenuProps = Partial<ExtractPropTypes<typeof menuProps>>;
@@ -66,6 +68,7 @@ export default defineComponent({
6668
'click',
6769
'update:activeKey',
6870
],
71+
slots: ['expandIcon'],
6972
setup(props, { slots, emit }) {
7073
const { prefixCls, direction } = useConfigInject('menu', props);
7174
const store = ref<Record<string, StoreMenuInfo>>({});
@@ -371,6 +374,7 @@ export default defineComponent({
371374
unRegisterMenuInfo,
372375
selectedSubMenuEventKeys,
373376
isRootMenu: true,
377+
expandIcon: props.expandIcon || slots.expandIcon,
374378
});
375379
return () => {
376380
const childList = flattenChildren(slots.default?.());

components/menu/src/SubMenu.tsx

+6-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const subMenuProps = {
2424
popupOffset: Array as PropType<number[]>,
2525
internalPopupClose: Boolean,
2626
eventKey: String,
27+
expandIcon: Function as PropType<(p?: { isOpen: boolean; [key: string]: any }) => any>,
2728
};
2829

2930
export type SubMenuProps = Partial<ExtractPropTypes<typeof subMenuProps>>;
@@ -32,7 +33,7 @@ export default defineComponent({
3233
name: 'ASubMenu',
3334
inheritAttrs: false,
3435
props: subMenuProps,
35-
slots: ['icon', 'title'],
36+
slots: ['icon', 'title', 'expandIcon'],
3637
emits: ['titleClick', 'mouseenter', 'mouseleave'],
3738
setup(props, { slots, attrs, emit }) {
3839
useProvideFirstLevel(false);
@@ -84,6 +85,7 @@ export default defineComponent({
8485
selectedSubMenuEventKeys,
8586
motion,
8687
defaultMotions,
88+
expandIcon: menuExpandIcon,
8789
} = useInjectMenu();
8890

8991
registerMenuInfo(eventKey, menuInfo);
@@ -226,6 +228,7 @@ export default defineComponent({
226228
const icon = getPropsSlot(slots, props, 'icon');
227229
const title = renderTitle(getPropsSlot(slots, props, 'title'), icon);
228230
const subMenuPrefixClsValue = subMenuPrefixCls.value;
231+
const expandIcon = props.expandIcon || slots.expandIcon || menuExpandIcon;
229232
let titleNode = (
230233
<div
231234
style={directionStyle.value}
@@ -244,8 +247,8 @@ export default defineComponent({
244247
{title}
245248

246249
{/* Only non-horizontal mode shows the icon */}
247-
{mode.value !== 'horizontal' && slots.expandIcon ? (
248-
slots.expandIcon({ ...props, isOpen: open.value })
250+
{mode.value !== 'horizontal' && expandIcon ? (
251+
expandIcon({ ...props, isOpen: open.value })
249252
) : (
250253
<i class={`${subMenuPrefixClsValue}-arrow`} />
251254
)}

components/menu/src/hooks/useMenuContext.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ export interface MenuContextProps {
7777

7878
// // Icon
7979
// itemIcon?: RenderIconType;
80-
// expandIcon?: RenderIconType;
80+
expandIcon?: (p?: { isOpen: boolean; [key: string]: any }) => any;
8181

8282
// // Function
8383
onItemClick: MenuClickEventHandler;

components/notification/index.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ function notice(args: NotificationArgsProps) {
212212
);
213213
}
214214

215-
const api: any = {
215+
const apiBase = {
216216
open: notice,
217217
close(key: string) {
218218
Object.keys(notificationInstance).forEach(cacheKey =>
@@ -228,7 +228,11 @@ const api: any = {
228228
},
229229
};
230230

231-
['success', 'info', 'warning', 'error'].forEach(type => {
231+
type NotificationApi = typeof apiBase &
232+
Record<IconType | 'warn', (args: Omit<NotificationArgsProps, 'type'>) => void>;
233+
const api = apiBase as any as NotificationApi;
234+
const iconTypes: IconType[] = ['success', 'info', 'warning', 'error'];
235+
iconTypes.forEach(type => {
232236
api[type] = args =>
233237
api.open({
234238
...args,

components/progress/Circle.tsx

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import type { CSSProperties } from 'vue';
2+
import { computed, defineComponent } from 'vue';
3+
import { presetPrimaryColors } from '@ant-design/colors';
4+
import { Circle as VCCircle } from '../vc-progress';
5+
import { getSuccessPercent, validProgress } from './utils';
6+
import type { ProgressProps } from './props';
7+
import { progressProps } from './props';
8+
9+
export type CircleProps = ProgressProps;
10+
11+
function getPercentage({ percent, success, successPercent }: CircleProps) {
12+
const realSuccessPercent = validProgress(getSuccessPercent({ success, successPercent }));
13+
return [realSuccessPercent, validProgress(validProgress(percent) - realSuccessPercent)];
14+
}
15+
16+
export default defineComponent({
17+
inheritAttrs: false,
18+
props: progressProps(),
19+
setup(props, { slots }) {
20+
const gapDeg = computed(() => {
21+
// Support gapDeg = 0 when type = 'dashboard'
22+
if (props.gapDegree || props.gapDegree === 0) {
23+
return props.gapDegree;
24+
}
25+
if (props.type === 'dashboard') {
26+
return 75;
27+
}
28+
return undefined;
29+
});
30+
31+
const circleStyle = computed<CSSProperties>(() => {
32+
const circleSize = props.width || 120;
33+
return {
34+
width: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
35+
height: typeof circleSize === 'number' ? `${circleSize}px` : circleSize,
36+
fontSize: `${circleSize * 0.15 + 6}px`,
37+
};
38+
});
39+
40+
const circleWidth = computed(() => props.strokeWidth || 6);
41+
const gapPos = computed(
42+
() => props.gapPosition || (props.type === 'dashboard' && 'bottom') || 'top',
43+
);
44+
45+
// using className to style stroke color
46+
const strokeColor = computed(() => [presetPrimaryColors.green, props.strokeColor || null]);
47+
const percent = computed(() => getPercentage(props));
48+
const isGradient = computed(
49+
() => Object.prototype.toString.call(props.strokeColor) === '[object Object]',
50+
);
51+
52+
const wrapperClassName = computed(() => ({
53+
[`${props.prefixCls}-inner`]: true,
54+
[`${props.prefixCls}-circle-gradient`]: isGradient.value,
55+
}));
56+
57+
return () => (
58+
<div class={wrapperClassName.value} style={circleStyle.value}>
59+
<VCCircle
60+
percent={percent.value}
61+
strokeWidth={circleWidth.value}
62+
trailWidth={circleWidth.value}
63+
strokeColor={strokeColor.value}
64+
strokeLinecap={props.strokeLinecap}
65+
trailColor={props.trailColor}
66+
prefixCls={props.prefixCls}
67+
gapDegree={gapDeg.value}
68+
gapPosition={gapPos.value}
69+
/>
70+
{slots.default?.()}
71+
</div>
72+
);
73+
},
74+
});

components/progress/Line.tsx

+128
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
import type { CSSProperties, ExtractPropTypes, PropType } from 'vue';
2+
import { computed, defineComponent } from 'vue';
3+
import type { Direction } from '../config-provider';
4+
import PropTypes from '../_util/vue-types';
5+
import type { StringGradients, ProgressGradient } from './props';
6+
import { progressProps } from './props';
7+
import { getSuccessPercent, validProgress } from './utils';
8+
9+
const lineProps = {
10+
...progressProps(),
11+
prefixCls: PropTypes.string,
12+
direction: {
13+
type: String as PropType<Direction>,
14+
},
15+
};
16+
17+
export type LineProps = Partial<ExtractPropTypes<typeof lineProps>>;
18+
19+
/**
20+
* {
21+
* '0%': '#afc163',
22+
* '75%': '#009900',
23+
* '50%': 'green', ====> '#afc163 0%, #66FF00 25%, #00CC00 50%, #009900 75%, #ffffff 100%'
24+
* '25%': '#66FF00',
25+
* '100%': '#ffffff'
26+
* }
27+
*/
28+
export const sortGradient = (gradients: StringGradients) => {
29+
let tempArr = [];
30+
Object.keys(gradients).forEach(key => {
31+
const formattedKey = parseFloat(key.replace(/%/g, ''));
32+
if (!isNaN(formattedKey)) {
33+
tempArr.push({
34+
key: formattedKey,
35+
value: gradients[key],
36+
});
37+
}
38+
});
39+
tempArr = tempArr.sort((a, b) => a.key - b.key);
40+
return tempArr.map(({ key, value }) => `${value} ${key}%`).join(', ');
41+
};
42+
43+
/**
44+
* Then this man came to realize the truth: Besides six pence, there is the moon. Besides bread and
45+
* butter, there is the bug. And... Besides women, there is the code.
46+
*
47+
* @example
48+
* {
49+
* "0%": "#afc163",
50+
* "25%": "#66FF00",
51+
* "50%": "#00CC00", // ====> linear-gradient(to right, #afc163 0%, #66FF00 25%,
52+
* "75%": "#009900", // #00CC00 50%, #009900 75%, #ffffff 100%)
53+
* "100%": "#ffffff"
54+
* }
55+
*/
56+
export const handleGradient = (strokeColor: ProgressGradient, directionConfig: Direction) => {
57+
const {
58+
from = '#1890ff',
59+
to = '#1890ff',
60+
direction = directionConfig === 'rtl' ? 'to left' : 'to right',
61+
...rest
62+
} = strokeColor;
63+
if (Object.keys(rest).length !== 0) {
64+
const sortedGradients = sortGradient(rest as StringGradients);
65+
return { backgroundImage: `linear-gradient(${direction}, ${sortedGradients})` };
66+
}
67+
return { backgroundImage: `linear-gradient(${direction}, ${from}, ${to})` };
68+
};
69+
70+
export default defineComponent({
71+
name: 'Line',
72+
props: lineProps,
73+
setup(props, { slots }) {
74+
const backgroundProps = computed(() => {
75+
const { strokeColor, direction } = props;
76+
return strokeColor && typeof strokeColor !== 'string'
77+
? handleGradient(strokeColor, direction)
78+
: {
79+
background: strokeColor,
80+
};
81+
});
82+
83+
const trailStyle = computed(() =>
84+
props.trailColor
85+
? {
86+
backgroundColor: props.trailColor,
87+
}
88+
: undefined,
89+
);
90+
91+
const percentStyle = computed<CSSProperties>(() => {
92+
const { percent, strokeWidth, strokeLinecap, size } = props;
93+
return {
94+
width: `${validProgress(percent)}%`,
95+
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
96+
borderRadius: strokeLinecap === 'square' ? 0 : '',
97+
...(backgroundProps.value as any),
98+
};
99+
});
100+
101+
const successPercent = computed(() => {
102+
return getSuccessPercent(props);
103+
});
104+
const successPercentStyle = computed<CSSProperties>(() => {
105+
const { strokeWidth, size, strokeLinecap, success } = props;
106+
return {
107+
width: `${validProgress(successPercent.value)}%`,
108+
height: `${strokeWidth || (size === 'small' ? 6 : 8)}px`,
109+
borderRadius: strokeLinecap === 'square' ? 0 : '',
110+
backgroundColor: success?.strokeColor,
111+
};
112+
});
113+
114+
return () => (
115+
<>
116+
<div class={`${props.prefixCls}-outer`}>
117+
<div class={`${props.prefixCls}-inner`} style={trailStyle.value}>
118+
<div class={`${props.prefixCls}-bg`} style={percentStyle.value} />
119+
{successPercent.value !== undefined ? (
120+
<div class={`${props.prefixCls}-success-bg`} style={successPercentStyle.value} />
121+
) : null}
122+
</div>
123+
</div>
124+
{slots.default?.()}
125+
</>
126+
);
127+
},
128+
});

0 commit comments

Comments
 (0)