1
1
import type { ExtractPropTypes , CSSProperties } from 'vue' ;
2
- import { defineComponent , inject } from 'vue' ;
2
+ import { computed , watch } from 'vue' ;
3
+ import { defineComponent , onMounted , ref } from 'vue' ;
3
4
import VcTooltip from '../vc-tooltip' ;
4
5
import classNames from '../_util/classNames' ;
5
- import getPlacements from './placements' ;
6
6
import PropTypes from '../_util/vue-types' ;
7
7
import { PresetColorTypes } from '../_util/colors' ;
8
- import {
9
- hasProp ,
10
- getComponent ,
11
- getStyle ,
12
- filterEmpty ,
13
- getSlot ,
14
- isValidElement ,
15
- } from '../_util/props-util' ;
8
+ import warning from '../_util/warning' ;
9
+ import { getPropsSlot , getStyle , filterEmpty , isValidElement } from '../_util/props-util' ;
16
10
import { cloneElement } from '../_util/vnode' ;
17
- import { defaultConfigProvider } from '../config-provider ' ;
11
+ import type { triggerTypes , placementTypes } from './abstractTooltipProps ' ;
18
12
import abstractTooltipProps from './abstractTooltipProps' ;
13
+ import useConfigInject from '../_util/hooks/useConfigInject' ;
14
+ import getPlacements , { AdjustOverflow , PlacementsConfig } from './placements' ;
15
+
16
+ export { AdjustOverflow , PlacementsConfig } ;
17
+
18
+ export type TooltipPlacement = typeof placementTypes ;
19
+
20
+ // https://github.com/react-component/tooltip
21
+ // https://github.com/yiminghe/dom-align
22
+ export interface TooltipAlignConfig {
23
+ points ?: [ string , string ] ;
24
+ offset ?: [ number | string , number | string ] ;
25
+ targetOffset ?: [ number | string , number | string ] ;
26
+ overflow ?: { adjustX : boolean ; adjustY : boolean } ;
27
+ useCssRight ?: boolean ;
28
+ useCssBottom ?: boolean ;
29
+ useCssTransform ?: boolean ;
30
+ }
19
31
20
32
const splitObject = ( obj : any , keys : string [ ] ) => {
21
33
const picked = { } ;
@@ -37,59 +49,70 @@ const tooltipProps = {
37
49
title : PropTypes . VNodeChild ,
38
50
} ;
39
51
52
+ export type TriggerTypes = typeof triggerTypes [ number ] ;
53
+
54
+ export type PlacementTypes = typeof placementTypes [ number ] ;
55
+
40
56
export type TooltipProps = Partial < ExtractPropTypes < typeof tooltipProps > > ;
41
57
42
58
export default defineComponent ( {
43
59
name : 'ATooltip' ,
44
60
inheritAttrs : false ,
45
61
props : tooltipProps ,
46
62
emits : [ 'update:visible' , 'visibleChange' ] ,
47
- setup ( ) {
48
- return {
49
- configProvider : inject ( 'configProvider' , defaultConfigProvider ) ,
50
- } ;
51
- } ,
52
- data ( ) {
53
- return {
54
- sVisible : ! ! this . $props . visible || ! ! this . $props . defaultVisible ,
63
+ setup ( props , { slots, emit, attrs, expose } ) {
64
+ const { prefixCls, getTargetContainer } = useConfigInject ( 'tooltip' , props ) ;
65
+
66
+ const visible = ref ( false ) ;
67
+
68
+ const tooltip = ref ( ) ;
69
+
70
+ onMounted ( ( ) => {
71
+ warning (
72
+ ! ( 'default-visible' in attrs ) || ! ( 'defaultVisible' in attrs ) ,
73
+ 'Tooltip' ,
74
+ `'defaultVisible' is deprecated, please use 'v-model:visible'` ,
75
+ ) ;
76
+ } ) ;
77
+ watch (
78
+ ( ) => props . visible ,
79
+ val => {
80
+ visible . value = ! ! val ;
81
+ } ,
82
+ { immediate : true } ,
83
+ ) ;
84
+
85
+ const isNoTitle = ( ) => {
86
+ const title = getPropsSlot ( slots , props , 'title' ) ;
87
+ return ! title && title !== 0 ;
55
88
} ;
56
- } ,
57
- watch : {
58
- visible ( val ) {
59
- this . sVisible = val ;
60
- } ,
61
- } ,
62
- methods : {
63
- handleVisibleChange ( visible : boolean ) {
64
- if ( ! hasProp ( this , 'visible' ) ) {
65
- this . sVisible = this . isNoTitle ( ) ? false : visible ;
66
- }
67
- if ( ! this . isNoTitle ( ) ) {
68
- this . $emit ( 'update:visible' , visible ) ;
69
- this . $emit ( 'visibleChange' , visible ) ;
89
+
90
+ const handleVisibleChange = ( val : boolean ) => {
91
+ visible . value = isNoTitle ( ) ? false : val ;
92
+ if ( ! isNoTitle ( ) ) {
93
+ emit ( 'update:visible' , val ) ;
94
+ emit ( 'visibleChange' , val ) ;
70
95
}
71
- } ,
96
+ } ;
72
97
73
- getPopupDomNode ( ) {
74
- return ( this . $refs . tooltip as any ) . getPopupDomNode ( ) ;
75
- } ,
98
+ const getPopupDomNode = ( ) => {
99
+ return tooltip . value . getPopupDomNode ( ) ;
100
+ } ;
76
101
77
- getPlacements ( ) {
78
- const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = this . $props ;
102
+ expose ( { getPopupDomNode, visible } ) ;
103
+
104
+ const tooltipPlacements = computed ( ( ) => {
105
+ const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = props ;
79
106
return (
80
107
builtinPlacements ||
81
108
getPlacements ( {
82
109
arrowPointAtCenter,
83
- verticalArrowShift : 8 ,
84
110
autoAdjustOverflow,
85
111
} )
86
112
) ;
87
- } ,
113
+ } ) ;
88
114
89
- // Fix Tooltip won't hide at disabled button
90
- // mouse events don't trigger at disabled button in Chrome
91
- // https://github.com/react-component/tooltip/issues/18
92
- getDisabledCompatibleChildren ( ele : any ) {
115
+ const getDisabledCompatibleChildren = ( ele : any ) => {
93
116
if (
94
117
( ( typeof ele . type === 'object' &&
95
118
( ele . type . __ANT_BUTTON === true ||
@@ -128,27 +151,22 @@ export default defineComponent({
128
151
} ,
129
152
true ,
130
153
) ;
131
- return < span style = { spanStyle } > { child } </ span > ;
154
+ return (
155
+ < span style = { spanStyle } class = { `${ prefixCls } -disabled-compatible-wrapper` } >
156
+ { child }
157
+ </ span >
158
+ ) ;
132
159
}
133
160
return ele ;
134
- } ,
135
-
136
- isNoTitle ( ) {
137
- const title = getComponent ( this , 'title' ) ;
138
- return ! title && title !== 0 ;
139
- } ,
161
+ } ;
140
162
141
- getOverlay ( ) {
142
- const title = getComponent ( this , 'title' ) ;
143
- if ( title === 0 ) {
144
- return title ;
145
- }
146
- return title || '' ;
147
- } ,
163
+ const getOverlay = ( ) => {
164
+ const title = getPropsSlot ( slots , props , 'title' ) ;
165
+ return title ?? '' ;
166
+ } ;
148
167
149
- // 动态设置动画点
150
- onPopupAlign ( domNode : HTMLElement , align : any ) {
151
- const placements = this . getPlacements ( ) ;
168
+ const onPopupAlign = ( domNode : HTMLElement , align : any ) => {
169
+ const placements = tooltipPlacements . value ;
152
170
// 当前返回的位置
153
171
const placement = Object . keys ( placements ) . filter (
154
172
key =>
@@ -175,67 +193,64 @@ export default defineComponent({
175
193
transformOrigin . left = `${ - align . offset [ 0 ] } px` ;
176
194
}
177
195
domNode . style . transformOrigin = `${ transformOrigin . left } ${ transformOrigin . top } ` ;
178
- } ,
179
- } ,
196
+ } ;
180
197
181
- render ( ) {
182
- const { $props, $data, $attrs } = this ;
183
- const {
184
- prefixCls : customizePrefixCls ,
185
- openClassName,
186
- getPopupContainer,
187
- color,
188
- overlayClassName,
189
- } = $props ;
190
- const { getPopupContainer : getContextPopupContainer } = this . configProvider ;
191
- const getPrefixCls = this . configProvider . getPrefixCls ;
192
- const prefixCls = getPrefixCls ( 'tooltip' , customizePrefixCls ) ;
193
- let children = this . children || filterEmpty ( getSlot ( this ) ) ;
194
- children = children . length === 1 ? children [ 0 ] : children ;
195
- let sVisible = $data . sVisible ;
196
- // Hide tooltip when there is no title
197
- if ( ! hasProp ( this , 'visible' ) && this . isNoTitle ( ) ) {
198
- sVisible = false ;
199
- }
200
- if ( ! children ) {
201
- return null ;
202
- }
203
- const child = this . getDisabledCompatibleChildren (
204
- isValidElement ( children ) ? children : < span > { children } </ span > ,
205
- ) ;
206
- const childCls = classNames ( {
207
- [ openClassName || `${ prefixCls } -open` ] : sVisible ,
208
- [ child . props && child . props . class ] : child . props && child . props . class ,
209
- } ) ;
210
- const customOverlayClassName = classNames ( overlayClassName , {
211
- [ `${ prefixCls } -${ color } ` ] : color && PresetColorRegex . test ( color ) ,
212
- } ) ;
213
- let formattedOverlayInnerStyle : CSSProperties ;
214
- let arrowContentStyle : CSSProperties ;
215
- if ( color && ! PresetColorRegex . test ( color ) ) {
216
- formattedOverlayInnerStyle = { backgroundColor : color } ;
217
- arrowContentStyle = { backgroundColor : color } ;
218
- }
198
+ return ( ) => {
199
+ const { openClassName, getPopupContainer, color, overlayClassName } = props ;
200
+ let children = filterEmpty ( slots . default ?.( ) ) ?? null ;
201
+ children = children . length === 1 ? children [ 0 ] : children ;
219
202
220
- const vcTooltipProps = {
221
- ...$attrs ,
222
- ...$props ,
223
- prefixCls,
224
- getTooltipContainer : getPopupContainer || getContextPopupContainer ,
225
- builtinPlacements : this . getPlacements ( ) ,
226
- overlay : this . getOverlay ( ) ,
227
- visible : sVisible ,
228
- ref : 'tooltip' ,
229
- overlayClassName : customOverlayClassName ,
230
- overlayInnerStyle : formattedOverlayInnerStyle ,
231
- arrowContent : < span class = { `${ prefixCls } -arrow-content` } style = { arrowContentStyle } > </ span > ,
232
- onVisibleChange : this . handleVisibleChange ,
233
- onPopupAlign : this . onPopupAlign ,
203
+ let tempVisible = visible . value ;
204
+ // Hide tooltip when there is no title
205
+ if ( props . visible === undefined && isNoTitle ( ) ) {
206
+ tempVisible = false ;
207
+ }
208
+ if ( ! children ) {
209
+ return null ;
210
+ }
211
+ const child = getDisabledCompatibleChildren (
212
+ isValidElement ( children ) ? children : < span > { children } </ span > ,
213
+ ) ;
214
+ const childCls = classNames ( {
215
+ [ openClassName || `${ prefixCls . value } -open` ] : true ,
216
+ [ child . props && child . props . class ] : child . props && child . props . class ,
217
+ } ) ;
218
+ const customOverlayClassName = classNames ( overlayClassName , {
219
+ [ `${ prefixCls . value } -${ color } ` ] : color && PresetColorRegex . test ( color ) ,
220
+ } ) ;
221
+ let formattedOverlayInnerStyle : CSSProperties ;
222
+ let arrowContentStyle : CSSProperties ;
223
+ if ( color && ! PresetColorRegex . test ( color ) ) {
224
+ formattedOverlayInnerStyle = { backgroundColor : color } ;
225
+ arrowContentStyle = { backgroundColor : color } ;
226
+ }
227
+
228
+ const vcTooltipProps = {
229
+ ...attrs ,
230
+ ...props ,
231
+ prefixCls : prefixCls . value ,
232
+ getTooltipContainer : getPopupContainer || getTargetContainer . value ,
233
+ builtinPlacements : tooltipPlacements . value ,
234
+ overlay : getOverlay ( ) ,
235
+ visible : tempVisible ,
236
+ ref : tooltip ,
237
+ overlayClassName : customOverlayClassName ,
238
+ overlayInnerStyle : formattedOverlayInnerStyle ,
239
+ onVisibleChange : handleVisibleChange ,
240
+ onPopupAlign,
241
+ } ;
242
+ return (
243
+ < VcTooltip
244
+ { ...vcTooltipProps }
245
+ v-slots = { {
246
+ arrowContent : ( ) => (
247
+ < span class = { `${ prefixCls . value } -arrow-content` } style = { arrowContentStyle } > </ span >
248
+ ) ,
249
+ } }
250
+ >
251
+ { visible . value ? cloneElement ( child , { class : childCls } ) : child }
252
+ </ VcTooltip >
253
+ ) ;
234
254
} ;
235
- return (
236
- < VcTooltip { ...vcTooltipProps } >
237
- { sVisible ? cloneElement ( child , { class : childCls } ) : child }
238
- </ VcTooltip >
239
- ) ;
240
255
} ,
241
256
} ) ;
0 commit comments