refactor: button
							parent
							
								
									389b233a40
								
							
						
					
					
						commit
						61c19a81c2
					
				|  | @ -1,4 +1,4 @@ | |||
| import { defineComponent } from 'vue'; | ||||
| import { computed, defineComponent } from 'vue'; | ||||
| import { flattenChildren } from '../_util/props-util'; | ||||
| import PropTypes from '../_util/vue-types'; | ||||
| import useConfigInject from '../_util/hooks/useConfigInject'; | ||||
|  | @ -21,10 +21,8 @@ export default defineComponent({ | |||
|   props: buttonGroupProps, | ||||
|   setup(props, { slots }) { | ||||
|     const { prefixCls, direction } = useConfigInject('btn-group', props); | ||||
| 
 | ||||
|     return () => { | ||||
|     const classes = computed(() => { | ||||
|       const { size } = props; | ||||
| 
 | ||||
|       // large => lg | ||||
|       // small => sm | ||||
|       let sizeCls = ''; | ||||
|  | @ -38,12 +36,14 @@ export default defineComponent({ | |||
|         default: | ||||
|           break; | ||||
|       } | ||||
|       const classes = { | ||||
|       return { | ||||
|         [`${prefixCls.value}`]: true, | ||||
|         [`${prefixCls.value}-${sizeCls}`]: sizeCls, | ||||
|         [`${prefixCls.value}-rtl`]: direction.value === 'rtl', | ||||
|       }; | ||||
|       return <div class={classes}>{flattenChildren(slots.default?.())}</div>; | ||||
|     }); | ||||
|     return () => { | ||||
|       return <div class={classes.value}>{flattenChildren(slots.default?.())}</div>; | ||||
|     }; | ||||
|   }, | ||||
| }); | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ import { | |||
|   onBeforeUnmount, | ||||
|   onMounted, | ||||
|   onUpdated, | ||||
|   Ref, | ||||
|   ref, | ||||
|   Text, | ||||
|   watch, | ||||
|  | @ -19,6 +20,8 @@ import devWarning from '../vc-util/devWarning'; | |||
| import type { ButtonType } from './buttonTypes'; | ||||
| import type { VNode } from 'vue'; | ||||
| 
 | ||||
| type Loading = boolean | number; | ||||
| 
 | ||||
| const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/; | ||||
| const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar); | ||||
| const props = buttonTypes(); | ||||
|  | @ -38,18 +41,41 @@ export default defineComponent({ | |||
|     const { prefixCls, autoInsertSpaceInButton, direction } = useConfigInject('btn', props); | ||||
| 
 | ||||
|     const buttonNodeRef = ref<HTMLElement>(null); | ||||
|     const delayTimeout = ref(undefined); | ||||
|     const iconCom = ref<VNode>(null); | ||||
|     const children = ref<VNode[]>([]); | ||||
|     const delayTimeoutRef = ref(undefined); | ||||
|     let isNeedInserted = false; | ||||
| 
 | ||||
|     const sLoading = ref(props.loading); | ||||
|     const innerLoading: Ref<Loading> = ref(false); | ||||
|     const hasTwoCNChar = ref(false); | ||||
| 
 | ||||
|     const autoInsertSpace = computed(() => autoInsertSpaceInButton.value !== false); | ||||
| 
 | ||||
|     const getClasses = () => { | ||||
|       const { type, shape, size, ghost, block, danger } = props; | ||||
|     // =============== Update Loading =============== | ||||
|     const loadingOrDelay = computed(() => | ||||
|       typeof props.loading === 'object' && props.loading.delay | ||||
|         ? props.loading.delay || true | ||||
|         : !!props.loading, | ||||
|     ); | ||||
| 
 | ||||
|     watch( | ||||
|       loadingOrDelay, | ||||
|       (val) => { | ||||
|         clearTimeout(delayTimeoutRef.value); | ||||
|         if (typeof loadingOrDelay.value === 'number') { | ||||
|           delayTimeoutRef.value = window.setTimeout(() => { | ||||
|             innerLoading.value = val; | ||||
|           }, loadingOrDelay.value); | ||||
|         } else { | ||||
|           innerLoading.value = val; | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
|         immediate: true, | ||||
|       }, | ||||
|     ); | ||||
| 
 | ||||
|     const classes = computed(() => { | ||||
|       const { type, shape, size, ghost, block, danger } = props; | ||||
|       const pre = prefixCls.value; | ||||
|       // large => lg | ||||
|       // small => sm | ||||
|       let sizeCls = ''; | ||||
|  | @ -63,22 +89,20 @@ export default defineComponent({ | |||
|         default: | ||||
|           break; | ||||
|       } | ||||
|       const iconType = sLoading.value ? 'loading' : iconCom.value; | ||||
|       return { | ||||
|         [attrs.class as string]: attrs.class, | ||||
|         [`${prefixCls.value}`]: true, | ||||
|         [`${prefixCls.value}-${type}`]: type, | ||||
|         [`${prefixCls.value}-${shape}`]: shape, | ||||
|         [`${prefixCls.value}-${sizeCls}`]: sizeCls, | ||||
|         [`${prefixCls.value}-icon-only`]: children.value.length === 0 && !!iconType, | ||||
|         [`${prefixCls.value}-loading`]: sLoading.value, | ||||
|         [`${prefixCls.value}-background-ghost`]: ghost && !isUnborderedButtonType(type), | ||||
|         [`${prefixCls.value}-two-chinese-chars`]: hasTwoCNChar.value && autoInsertSpace.value, | ||||
|         [`${prefixCls.value}-block`]: block, | ||||
|         [`${prefixCls.value}-dangerous`]: !!danger, | ||||
|         [`${prefixCls.value}-rtl`]: direction.value === 'rtl', | ||||
|         [`${pre}`]: true, | ||||
|         [`${pre}-${type}`]: type, | ||||
|         [`${pre}-${shape}`]: shape, | ||||
|         [`${pre}-${sizeCls}`]: sizeCls, | ||||
|         [`${pre}-loading`]: innerLoading.value, | ||||
|         [`${pre}-background-ghost`]: ghost && !isUnborderedButtonType(type), | ||||
|         [`${pre}-two-chinese-chars`]: hasTwoCNChar.value && autoInsertSpace.value, | ||||
|         [`${pre}-block`]: block, | ||||
|         [`${pre}-dangerous`]: !!danger, | ||||
|         [`${pre}-rtl`]: direction.value === 'rtl', | ||||
|       }; | ||||
|     }; | ||||
|     }); | ||||
| 
 | ||||
|     const fixTwoCNChar = () => { | ||||
|       // Fix for HOC usage like <FormatMessage /> | ||||
|  | @ -88,7 +112,7 @@ export default defineComponent({ | |||
|       } | ||||
|       const buttonText = node.textContent; | ||||
| 
 | ||||
|       if (isNeedInserted() && isTwoCNChar(buttonText)) { | ||||
|       if (isNeedInserted && isTwoCNChar(buttonText)) { | ||||
|         if (!hasTwoCNChar.value) { | ||||
|           hasTwoCNChar.value = true; | ||||
|         } | ||||
|  | @ -98,7 +122,7 @@ export default defineComponent({ | |||
|     }; | ||||
|     const handleClick = (event: Event) => { | ||||
|       // https://github.com/ant-design/ant-design/issues/30207 | ||||
|       if (sLoading.value || props.disabled) { | ||||
|       if (innerLoading.value || props.disabled) { | ||||
|         event.preventDefault(); | ||||
|         return; | ||||
|       } | ||||
|  | @ -117,9 +141,6 @@ export default defineComponent({ | |||
|       return child; | ||||
|     }; | ||||
| 
 | ||||
|     const isNeedInserted = () => | ||||
|       children.value.length === 1 && !iconCom.value && !isUnborderedButtonType(props.type); | ||||
| 
 | ||||
|     watchEffect(() => { | ||||
|       devWarning( | ||||
|         !(props.ghost && isUnborderedButtonType(props.type)), | ||||
|  | @ -128,50 +149,45 @@ export default defineComponent({ | |||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     watch( | ||||
|       () => props.loading, | ||||
|       (val, preVal) => { | ||||
|         if (preVal && typeof preVal !== 'boolean') { | ||||
|           clearTimeout(delayTimeout.value); | ||||
|         } | ||||
|         if (val && typeof val !== 'boolean' && val.delay) { | ||||
|           delayTimeout.value = setTimeout(() => { | ||||
|             sLoading.value = !!val; | ||||
|           }, val.delay); | ||||
|         } else { | ||||
|           sLoading.value = !!val; | ||||
|         } | ||||
|       }, | ||||
|       { | ||||
|         immediate: true, | ||||
|       }, | ||||
|     ); | ||||
| 
 | ||||
|     onMounted(fixTwoCNChar); | ||||
|     onUpdated(fixTwoCNChar); | ||||
| 
 | ||||
|     onBeforeUnmount(() => { | ||||
|       delayTimeout.value && clearTimeout(delayTimeout.value); | ||||
|       delayTimeoutRef.value && clearTimeout(delayTimeoutRef.value); | ||||
|     }); | ||||
| 
 | ||||
|     return () => { | ||||
|       iconCom.value = getPropsSlot(slots, props, 'icon'); | ||||
|       children.value = flattenChildren(getPropsSlot(slots, props)); | ||||
|       const children = flattenChildren(getPropsSlot(slots, props)); | ||||
| 
 | ||||
|       const icon = getPropsSlot(slots, props, 'icon'); | ||||
| 
 | ||||
|       isNeedInserted = children.length === 1 && !icon && !isUnborderedButtonType(props.type); | ||||
| 
 | ||||
|       const { type, htmlType, disabled, href, title, target } = props; | ||||
|       const classes = getClasses(); | ||||
| 
 | ||||
|       const iconType = innerLoading.value ? 'loading' : icon; | ||||
|       const buttonProps = { | ||||
|         ...attrs, | ||||
|         title, | ||||
|         disabled, | ||||
|         class: classes, | ||||
|         class: [ | ||||
|           classes.value, | ||||
|           attrs.class, | ||||
|           { [`${prefixCls.value}-icon-only`]: children.length === 0 && !!iconType }, | ||||
|         ], | ||||
|         onClick: handleClick, | ||||
|       }; | ||||
|       const iconNode = sLoading.value ? <LoadingOutlined /> : iconCom.value; | ||||
| 
 | ||||
|       const kids = children.value.map((child) => | ||||
|         insertSpace(child, isNeedInserted() && autoInsertSpace.value), | ||||
|       const iconNode = innerLoading.value ? ( | ||||
|         <span class={`${prefixCls.value}-loading-icon`}> | ||||
|           <LoadingOutlined /> | ||||
|         </span> | ||||
|       ) : ( | ||||
|         icon | ||||
|       ); | ||||
| 
 | ||||
|       const kids = children.map((child) => | ||||
|         insertSpace(child, isNeedInserted && autoInsertSpace.value), | ||||
|       ); | ||||
| 
 | ||||
|       if (href !== undefined) { | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ import type { SizeType } from '../config-provider'; | |||
| 
 | ||||
| const ButtonTypes = tuple('default', 'primary', 'ghost', 'dashed', 'link', 'text'); | ||||
| export type ButtonType = typeof ButtonTypes[number]; | ||||
| const ButtonShapes = tuple('circle', 'circle-outline', 'round'); | ||||
| const ButtonShapes = tuple('circle', 'round'); | ||||
| export type ButtonShape = typeof ButtonShapes[number]; | ||||
| 
 | ||||
| const ButtonHTMLTypes = tuple('submit', 'button', 'reset'); | ||||
|  |  | |||
|  | @ -17,6 +17,8 @@ Button.install = function (app: App) { | |||
|   return app; | ||||
| }; | ||||
| 
 | ||||
| export { ButtonGroup }; | ||||
| 
 | ||||
| export default Button as typeof Button & | ||||
|   Plugin & { | ||||
|     readonly Group: typeof ButtonGroup; | ||||
|  |  | |||
|  | @ -155,39 +155,25 @@ | |||
|     } | ||||
|   } | ||||
| 
 | ||||
|   &&-loading:not(&-circle):not(&-circle-outline):not(&-icon-only) { | ||||
|     padding-left: 29px; | ||||
|     .@{iconfont-css-prefix}:not(:last-child) { | ||||
|       margin-left: -14px; | ||||
|     } | ||||
|   } | ||||
|   & > &-loading-icon { | ||||
|     transition: all 0.3s @ease-in-out; | ||||
| 
 | ||||
|   &-sm&-loading:not(&-circle):not(&-circle-outline):not(&-icon-only) { | ||||
|     padding-left: 24px; | ||||
|     .@{iconfont-css-prefix} { | ||||
|       margin-left: -17px; | ||||
|       padding-right: @padding-xs; | ||||
|       animation: none; | ||||
|       // for smooth button padding transition | ||||
|       svg { | ||||
|         animation: loadingCircle 1s infinite linear; | ||||
|       } | ||||
|     } | ||||
| 
 | ||||
|     &:only-child { | ||||
|       .@{iconfont-css-prefix} { | ||||
|         padding-right: 0; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| 
 | ||||
|   // & > &-loading-icon { | ||||
|   //   transition: all 0.3s @ease-in-out; | ||||
| 
 | ||||
|   //   .@{iconfont-css-prefix} { | ||||
|   //     padding-right: @padding-xs; | ||||
|   //     animation: none; | ||||
|   //     // for smooth button padding transition | ||||
|   //     svg { | ||||
|   //       animation: loadingCircle 1s infinite linear; | ||||
|   //     } | ||||
|   //   } | ||||
| 
 | ||||
|   //   &:only-child { | ||||
|   //     .@{iconfont-css-prefix} { | ||||
|   //       padding-right: 0; | ||||
|   //     } | ||||
|   //   } | ||||
|   // } | ||||
| 
 | ||||
|   &-group { | ||||
|     .btn-group(@btn-prefix-cls); | ||||
|   } | ||||
|  |  | |||
|  | @ -136,7 +136,9 @@ export interface ModalFuncProps { | |||
| 
 | ||||
| type getContainerFunc = () => HTMLElement; | ||||
| 
 | ||||
| export type ModalFunc = (props: ModalFuncProps) => { | ||||
| export type ModalFunc = ( | ||||
|   props: ModalFuncProps, | ||||
| ) => { | ||||
|   destroy: () => void; | ||||
|   update: (newConfig: ModalFuncProps) => void; | ||||
| }; | ||||
|  |  | |||
|  | @ -139,7 +139,7 @@ const Popconfirm = defineComponent({ | |||
|       <LocaleReceiver | ||||
|         componentName="Popconfirm" | ||||
|         defaultLocale={defaultLocale.Popconfirm} | ||||
|         children={(popconfirmLocale) => this.renderOverlay(prefixCls, popconfirmLocale)} | ||||
|         children={popconfirmLocale => this.renderOverlay(prefixCls, popconfirmLocale)} | ||||
|       /> | ||||
|     ); | ||||
|     const tooltipProps = { | ||||
|  |  | |||
							
								
								
									
										2
									
								
								v2-doc
								
								
								
								
							
							
								
								
								
								
								
								
							
						
						
									
										2
									
								
								v2-doc
								
								
								
								
							|  | @ -1 +1 @@ | |||
| Subproject commit 4c298275518d5790a58d26f2ed9b83ee5ba1dba4 | ||||
| Subproject commit b6ab0fec2cfa378bab8dfe6c8ef6b6a8664b970e | ||||
		Loading…
	
		Reference in New Issue
	
	 tangjinzhou
						tangjinzhou