44 onBeforeUnmount ,
55 onMounted ,
66 onUpdated ,
7+ Ref ,
78 ref ,
89 Text ,
910 watch ,
@@ -19,6 +20,8 @@ import devWarning from '../vc-util/devWarning';
1920import type { ButtonType } from './buttonTypes' ;
2021import type { VNode } from 'vue' ;
2122
23+ type Loading = boolean | number ;
24+
2225const rxTwoCNChar = / ^ [ \u4e00 - \u9fa5 ] { 2 } $ / ;
2326const isTwoCNChar = rxTwoCNChar . test . bind ( rxTwoCNChar ) ;
2427const props = buttonTypes ( ) ;
@@ -38,18 +41,41 @@ export default defineComponent({
3841 const { prefixCls, autoInsertSpaceInButton, direction } = useConfigInject ( 'btn' , props ) ;
3942
4043 const buttonNodeRef = ref < HTMLElement > ( null ) ;
41- const delayTimeout = ref ( undefined ) ;
42- const iconCom = ref < VNode > ( null ) ;
43- const children = ref < VNode [ ] > ( [ ] ) ;
44+ const delayTimeoutRef = ref ( undefined ) ;
45+ let isNeedInserted = false ;
4446
45- const sLoading = ref ( props . loading ) ;
47+ const innerLoading : Ref < Loading > = ref ( false ) ;
4648 const hasTwoCNChar = ref ( false ) ;
4749
4850 const autoInsertSpace = computed ( ( ) => autoInsertSpaceInButton . value !== false ) ;
4951
50- const getClasses = ( ) => {
51- const { type, shape, size, ghost, block, danger } = props ;
52+ // =============== Update Loading ===============
53+ const loadingOrDelay = computed ( ( ) =>
54+ typeof props . loading === 'object' && props . loading . delay
55+ ? props . loading . delay || true
56+ : ! ! props . loading ,
57+ ) ;
5258
59+ watch (
60+ loadingOrDelay ,
61+ ( val ) => {
62+ clearTimeout ( delayTimeoutRef . value ) ;
63+ if ( typeof loadingOrDelay . value === 'number' ) {
64+ delayTimeoutRef . value = window . setTimeout ( ( ) => {
65+ innerLoading . value = val ;
66+ } , loadingOrDelay . value ) ;
67+ } else {
68+ innerLoading . value = val ;
69+ }
70+ } ,
71+ {
72+ immediate : true ,
73+ } ,
74+ ) ;
75+
76+ const classes = computed ( ( ) => {
77+ const { type, shape, size, ghost, block, danger } = props ;
78+ const pre = prefixCls . value ;
5379 // large => lg
5480 // small => sm
5581 let sizeCls = '' ;
@@ -63,22 +89,20 @@ export default defineComponent({
6389 default :
6490 break ;
6591 }
66- const iconType = sLoading . value ? 'loading' : iconCom . value ;
6792 return {
6893 [ attrs . class as string ] : attrs . class ,
69- [ `${ prefixCls . value } ` ] : true ,
70- [ `${ prefixCls . value } -${ type } ` ] : type ,
71- [ `${ prefixCls . value } -${ shape } ` ] : shape ,
72- [ `${ prefixCls . value } -${ sizeCls } ` ] : sizeCls ,
73- [ `${ prefixCls . value } -icon-only` ] : children . value . length === 0 && ! ! iconType ,
74- [ `${ prefixCls . value } -loading` ] : sLoading . value ,
75- [ `${ prefixCls . value } -background-ghost` ] : ghost && ! isUnborderedButtonType ( type ) ,
76- [ `${ prefixCls . value } -two-chinese-chars` ] : hasTwoCNChar . value && autoInsertSpace . value ,
77- [ `${ prefixCls . value } -block` ] : block ,
78- [ `${ prefixCls . value } -dangerous` ] : ! ! danger ,
79- [ `${ prefixCls . value } -rtl` ] : direction . value === 'rtl' ,
94+ [ `${ pre } ` ] : true ,
95+ [ `${ pre } -${ type } ` ] : type ,
96+ [ `${ pre } -${ shape } ` ] : shape ,
97+ [ `${ pre } -${ sizeCls } ` ] : sizeCls ,
98+ [ `${ pre } -loading` ] : innerLoading . value ,
99+ [ `${ pre } -background-ghost` ] : ghost && ! isUnborderedButtonType ( type ) ,
100+ [ `${ pre } -two-chinese-chars` ] : hasTwoCNChar . value && autoInsertSpace . value ,
101+ [ `${ pre } -block` ] : block ,
102+ [ `${ pre } -dangerous` ] : ! ! danger ,
103+ [ `${ pre } -rtl` ] : direction . value === 'rtl' ,
80104 } ;
81- } ;
105+ } ) ;
82106
83107 const fixTwoCNChar = ( ) => {
84108 // Fix for HOC usage like <FormatMessage />
@@ -88,7 +112,7 @@ export default defineComponent({
88112 }
89113 const buttonText = node . textContent ;
90114
91- if ( isNeedInserted ( ) && isTwoCNChar ( buttonText ) ) {
115+ if ( isNeedInserted && isTwoCNChar ( buttonText ) ) {
92116 if ( ! hasTwoCNChar . value ) {
93117 hasTwoCNChar . value = true ;
94118 }
@@ -98,7 +122,7 @@ export default defineComponent({
98122 } ;
99123 const handleClick = ( event : Event ) => {
100124 // https://github.com/ant-design/ant-design/issues/30207
101- if ( sLoading . value || props . disabled ) {
125+ if ( innerLoading . value || props . disabled ) {
102126 event . preventDefault ( ) ;
103127 return ;
104128 }
@@ -117,9 +141,6 @@ export default defineComponent({
117141 return child ;
118142 } ;
119143
120- const isNeedInserted = ( ) =>
121- children . value . length === 1 && ! iconCom . value && ! isUnborderedButtonType ( props . type ) ;
122-
123144 watchEffect ( ( ) => {
124145 devWarning (
125146 ! ( props . ghost && isUnborderedButtonType ( props . type ) ) ,
@@ -128,50 +149,45 @@ export default defineComponent({
128149 ) ;
129150 } ) ;
130151
131- watch (
132- ( ) => props . loading ,
133- ( val , preVal ) => {
134- if ( preVal && typeof preVal !== 'boolean' ) {
135- clearTimeout ( delayTimeout . value ) ;
136- }
137- if ( val && typeof val !== 'boolean' && val . delay ) {
138- delayTimeout . value = setTimeout ( ( ) => {
139- sLoading . value = ! ! val ;
140- } , val . delay ) ;
141- } else {
142- sLoading . value = ! ! val ;
143- }
144- } ,
145- {
146- immediate : true ,
147- } ,
148- ) ;
149-
150152 onMounted ( fixTwoCNChar ) ;
151153 onUpdated ( fixTwoCNChar ) ;
152154
153155 onBeforeUnmount ( ( ) => {
154- delayTimeout . value && clearTimeout ( delayTimeout . value ) ;
156+ delayTimeoutRef . value && clearTimeout ( delayTimeoutRef . value ) ;
155157 } ) ;
156158
157159 return ( ) => {
158- iconCom . value = getPropsSlot ( slots , props , 'icon' ) ;
159- children . value = flattenChildren ( getPropsSlot ( slots , props ) ) ;
160+ const children = flattenChildren ( getPropsSlot ( slots , props ) ) ;
161+
162+ const icon = getPropsSlot ( slots , props , 'icon' ) ;
163+
164+ isNeedInserted = children . length === 1 && ! icon && ! isUnborderedButtonType ( props . type ) ;
160165
161166 const { type, htmlType, disabled, href, title, target } = props ;
162- const classes = getClasses ( ) ;
163167
168+ const iconType = innerLoading . value ? 'loading' : icon ;
164169 const buttonProps = {
165170 ...attrs ,
166171 title,
167172 disabled,
168- class : classes ,
173+ class : [
174+ classes . value ,
175+ attrs . class ,
176+ { [ `${ prefixCls . value } -icon-only` ] : children . length === 0 && ! ! iconType } ,
177+ ] ,
169178 onClick : handleClick ,
170179 } ;
171- const iconNode = sLoading . value ? < LoadingOutlined /> : iconCom . value ;
172180
173- const kids = children . value . map ( ( child ) =>
174- insertSpace ( child , isNeedInserted ( ) && autoInsertSpace . value ) ,
181+ const iconNode = innerLoading . value ? (
182+ < span class = { `${ prefixCls . value } -loading-icon` } >
183+ < LoadingOutlined />
184+ </ span >
185+ ) : (
186+ icon
187+ ) ;
188+
189+ const kids = children . map ( ( child ) =>
190+ insertSpace ( child , isNeedInserted && autoInsertSpace . value ) ,
175191 ) ;
176192
177193 if ( href !== undefined ) {
0 commit comments