1
- import type { ExtractPropTypes } from 'vue' ;
2
- import { computed , watch , defineComponent , onMounted , ref } from 'vue' ;
1
+ import type { CSSProperties , ExtractPropTypes } from 'vue' ;
2
+ import { computed , watch , defineComponent , ref } from 'vue' ;
3
3
import VcTooltip from '../vc-tooltip' ;
4
4
import classNames from '../_util/classNames' ;
5
5
import PropTypes from '../_util/vue-types' ;
6
6
import warning from '../_util/warning' ;
7
- import { getStyle , filterEmpty , isValidElement , initDefaultProps } from '../_util/props-util' ;
7
+ import {
8
+ getStyle ,
9
+ filterEmpty ,
10
+ isValidElement ,
11
+ initDefaultProps ,
12
+ isFragment ,
13
+ } from '../_util/props-util' ;
8
14
import { cloneElement } from '../_util/vnode' ;
9
15
export type { TriggerType , TooltipPlacement } from './abstractTooltipProps' ;
10
16
import abstractTooltipProps from './abstractTooltipProps' ;
11
17
import useConfigInject from '../config-provider/hooks/useConfigInject' ;
12
- import getPlacements from './placements' ;
18
+ import getPlacements from '../_util /placements' ;
13
19
import firstNotUndefined from '../_util/firstNotUndefined' ;
14
20
import raf from '../_util/raf' ;
15
21
import { parseColor } from './util' ;
16
- export type { AdjustOverflow , PlacementsConfig } from './placements' ;
22
+ export type { AdjustOverflow , PlacementsConfig } from '../_util/placements' ;
23
+ import useStyle from './style' ;
17
24
18
25
// https://github.com/react-component/tooltip
19
26
// https://github.com/yiminghe/dom-align
@@ -26,10 +33,12 @@ export interface TooltipAlignConfig {
26
33
useCssBottom ?: boolean ;
27
34
useCssTransform ?: boolean ;
28
35
}
29
-
30
- const splitObject = ( obj : any , keys : string [ ] ) => {
31
- const picked = { } ;
32
- const omitted = { ...obj } ;
36
+ const splitObject = < T extends CSSProperties > (
37
+ obj : T ,
38
+ keys : ( keyof T ) [ ] ,
39
+ ) : Record < 'picked' | 'omitted' , T > => {
40
+ const picked : T = { } as T ;
41
+ const omitted : T = { ...obj } ;
33
42
keys . forEach ( key => {
34
43
if ( obj && key in obj ) {
35
44
picked [ key ] = obj [ key ] ;
@@ -74,50 +83,55 @@ export default defineComponent({
74
83
slots : [ 'title' ] ,
75
84
// emits: ['update:visible', 'visibleChange'],
76
85
setup ( props , { slots, emit, attrs, expose } ) {
77
- const { prefixCls, getPopupContainer, direction } = useConfigInject ( 'tooltip' , props ) ;
86
+ if ( process . env . NODE_ENV !== 'production' ) {
87
+ [
88
+ [ 'visible' , 'open' ] ,
89
+ [ 'onVisibleChange' , 'onOpenChange' ] ,
90
+ ] . forEach ( ( [ deprecatedName , newName ] ) => {
91
+ warning (
92
+ props [ deprecatedName ] === undefined ,
93
+ 'Tooltip' ,
94
+ `\`${ deprecatedName } \` is deprecated, please use \`${ newName } \` instead.` ,
95
+ ) ;
96
+ } ) ;
97
+ }
78
98
79
- const visible = ref ( firstNotUndefined ( [ props . visible , props . defaultVisible ] ) ) ;
99
+ const { prefixCls, getPopupContainer, direction } = useConfigInject ( 'tooltip' , props ) ;
100
+ const mergedOpen = computed ( ( ) => props . open ?? props . visible ) ;
101
+ const innerOpen = ref ( firstNotUndefined ( [ props . open , props . visible ] ) ) ;
80
102
81
103
const tooltip = ref ( ) ;
82
104
83
- onMounted ( ( ) => {
84
- warning (
85
- props . defaultVisible === undefined ,
86
- 'Tooltip' ,
87
- `'defaultVisible' is deprecated, please use 'v-model:visible'` ,
88
- ) ;
89
- } ) ;
90
105
let rafId : any ;
91
- watch (
92
- ( ) => props . visible ,
93
- val => {
94
- raf . cancel ( rafId ) ;
95
- rafId = raf ( ( ) => {
96
- visible . value = ! ! val ;
97
- } ) ;
98
- } ,
99
- ) ;
106
+ watch ( mergedOpen , val => {
107
+ raf . cancel ( rafId ) ;
108
+ rafId = raf ( ( ) => {
109
+ innerOpen . value = ! ! val ;
110
+ } ) ;
111
+ } ) ;
100
112
const isNoTitle = ( ) => {
101
113
const title = props . title ?? slots . title ;
102
114
return ! title && title !== 0 ;
103
115
} ;
104
116
105
117
const handleVisibleChange = ( val : boolean ) => {
106
118
const noTitle = isNoTitle ( ) ;
107
- if ( props . visible === undefined ) {
108
- visible . value = noTitle ? false : val ;
119
+ if ( mergedOpen . value === undefined ) {
120
+ innerOpen . value = noTitle ? false : val ;
109
121
}
110
122
if ( ! noTitle ) {
111
123
emit ( 'update:visible' , val ) ;
112
124
emit ( 'visibleChange' , val ) ;
125
+ emit ( 'update:open' , val ) ;
126
+ emit ( 'openChange' , val ) ;
113
127
}
114
128
} ;
115
129
116
130
const getPopupDomNode = ( ) => {
117
131
return tooltip . value . getPopupDomNode ( ) ;
118
132
} ;
119
133
120
- expose ( { getPopupDomNode, visible , forcePopupAlign : ( ) => tooltip . value ?. forcePopupAlign ( ) } ) ;
134
+ expose ( { getPopupDomNode, open , forcePopupAlign : ( ) => tooltip . value ?. forcePopupAlign ( ) } ) ;
121
135
122
136
const tooltipPlacements = computed ( ( ) => {
123
137
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = props ;
@@ -139,7 +153,8 @@ export default defineComponent({
139
153
( ( elementType . __ANT_BUTTON === true || elementType === 'button' ) &&
140
154
isTrueProps ( ele . props . disabled ) ) ||
141
155
( elementType . __ANT_SWITCH === true &&
142
- ( isTrueProps ( ele . props . disabled ) || isTrueProps ( ele . props . loading ) ) )
156
+ ( isTrueProps ( ele . props . disabled ) || isTrueProps ( ele . props . loading ) ) ) ||
157
+ ( elementType . __ANT_RADIO === true && isTrueProps ( ele . props . disabled ) )
143
158
) {
144
159
// Pick some layout related style properties up to span
145
160
// Prevent layout bugs like https://github.com/ant-design/ant-design/issues/5254
@@ -153,14 +168,14 @@ export default defineComponent({
153
168
'display' ,
154
169
'zIndex' ,
155
170
] ) ;
156
- const spanStyle = {
171
+ const spanStyle : CSSProperties = {
157
172
display : 'inline-block' , // default inline-block is important
158
173
...picked ,
159
174
cursor : 'not-allowed' ,
160
175
lineHeight : 1 , // use the true height of child nodes
161
- width : ele . props && ele . props . block ? '100%' : null ,
176
+ width : ele . props && ele . props . block ? '100%' : undefined ,
162
177
} ;
163
- const buttonStyle = {
178
+ const buttonStyle : CSSProperties = {
164
179
...omitted ,
165
180
pointerEvents : 'none' ,
166
181
} ;
@@ -190,46 +205,50 @@ export default defineComponent({
190
205
// 当前返回的位置
191
206
const placement = Object . keys ( placements ) . find (
192
207
key =>
193
- placements [ key ] . points [ 0 ] === align . points [ 0 ] &&
194
- placements [ key ] . points [ 1 ] === align . points [ 1 ] ,
208
+ placements [ key ] . points [ 0 ] === align . points ?. [ 0 ] &&
209
+ placements [ key ] . points [ 1 ] === align . points ?. [ 1 ] ,
195
210
) ;
196
- if ( ! placement ) {
197
- return ;
198
- }
199
- // 根据当前坐标设置动画点
200
- const rect = domNode . getBoundingClientRect ( ) ;
201
- const transformOrigin = {
202
- top : '50%' ,
203
- left : '50%' ,
204
- } ;
205
- if ( placement . indexOf ( 'top ' ) >= 0 || placement . indexOf ( 'Bottom ' ) >= 0 ) {
206
- transformOrigin . top = `${ rect . height - align . offset [ 1 ] } px` ;
207
- } else if ( placement . indexOf ( 'Top' ) >= 0 || placement . indexOf ( 'bottom' ) >= 0 ) {
208
- transformOrigin . top = ` ${ - align . offset [ 1 ] } px` ;
209
- }
210
- if ( placement . indexOf ( 'left ' ) >= 0 || placement . indexOf ( 'Right ' ) >= 0 ) {
211
- transformOrigin . left = `${ rect . width - align . offset [ 0 ] } px` ;
212
- } else if ( placement . indexOf ( 'right' ) >= 0 || placement . indexOf ( 'Left' ) >= 0 ) {
213
- transformOrigin . left = `${ - align . offset [ 0 ] } px ` ;
211
+ if ( placement ) {
212
+ // 根据当前坐标设置动画点
213
+ const rect = domNode . getBoundingClientRect ( ) ;
214
+ const transformOrigin = {
215
+ top : '50%' ,
216
+ left : '50%' ,
217
+ } ;
218
+ if ( placement . indexOf ( 'top' ) >= 0 || placement . indexOf ( 'Bottom' ) >= 0 ) {
219
+ transformOrigin . top = ` ${ rect . height - align . offset [ 1 ] } px` ;
220
+ } else if ( placement . indexOf ( 'Top ' ) >= 0 || placement . indexOf ( 'bottom ' ) >= 0 ) {
221
+ transformOrigin . top = `${ - align . offset [ 1 ] } px` ;
222
+ }
223
+ if ( placement . indexOf ( 'left' ) >= 0 || placement . indexOf ( 'Right' ) >= 0 ) {
224
+ transformOrigin . left = ` ${ rect . width - align . offset [ 0 ] } px` ;
225
+ } else if ( placement . indexOf ( 'right ' ) >= 0 || placement . indexOf ( 'Left ' ) >= 0 ) {
226
+ transformOrigin . left = `${ - align . offset [ 0 ] } px` ;
227
+ }
228
+ domNode . style . transformOrigin = `${ transformOrigin . left } ${ transformOrigin . top } ` ;
214
229
}
215
- domNode . style . transformOrigin = `${ transformOrigin . left } ${ transformOrigin . top } ` ;
216
230
} ;
217
231
const colorInfo = computed ( ( ) => parseColor ( prefixCls . value , props . color ) ) ;
232
+ const injectFromPopover = computed ( ( ) => ( attrs as any ) [ 'data-popover-inject' ] ) ;
233
+ const [ wrapSSR , hashId ] = useStyle (
234
+ prefixCls ,
235
+ computed ( ( ) => ! injectFromPopover . value ) ,
236
+ ) ;
218
237
return ( ) => {
219
238
const { openClassName, overlayClassName } = props ;
220
239
let children = filterEmpty ( slots . default ?.( ) ) ?? null ;
221
240
children = children . length === 1 ? children [ 0 ] : children ;
222
241
223
- let tempVisible = visible . value ;
242
+ let tempVisible = innerOpen . value ;
224
243
// Hide tooltip when there is no title
225
- if ( props . visible === undefined && isNoTitle ( ) ) {
244
+ if ( mergedOpen . value === undefined && isNoTitle ( ) ) {
226
245
tempVisible = false ;
227
246
}
228
247
if ( ! children ) {
229
248
return null ;
230
249
}
231
250
const child = getDisabledCompatibleChildren (
232
- isValidElement ( children ) ? children : < span > { children } </ span > ,
251
+ isValidElement ( children ) && ! isFragment ( children ) ? children : < span > { children } </ span > ,
233
252
) ;
234
253
const childCls = classNames ( {
235
254
[ openClassName || `${ prefixCls . value } -open` ] : true ,
@@ -242,6 +261,7 @@ export default defineComponent({
242
261
} ,
243
262
244
263
colorInfo . value . className ,
264
+ hashId . value ,
245
265
) ;
246
266
const formattedOverlayInnerStyle = {
247
267
...props . overlayInnerStyle ,
@@ -261,7 +281,7 @@ export default defineComponent({
261
281
onVisibleChange : handleVisibleChange ,
262
282
onPopupAlign,
263
283
} ;
264
- return (
284
+ return wrapSSR (
265
285
< VcTooltip
266
286
{ ...vcTooltipProps }
267
287
v-slots = { {
@@ -271,8 +291,8 @@ export default defineComponent({
271
291
overlay : getOverlay ,
272
292
} }
273
293
>
274
- { visible . value ? cloneElement ( child , { class : childCls } ) : child }
275
- </ VcTooltip >
294
+ { innerOpen . value ? cloneElement ( child , { class : childCls } ) : child }
295
+ </ VcTooltip > ,
276
296
) ;
277
297
} ;
278
298
} ,
0 commit comments