Skip to content

Commit 85c48c0

Browse files
authored
feat[tooltip]: add arrow attribute (#7459)
* docs: updating the `dropdownRender` description and jumps in the FAQ for Select * wip: add popover-arrow * wip: trigger add arrow attr * fix: remove popupContextKey * optimize * perf: optimize * docs: optimize docs * docs: add `arrow` attribute in tooltip en-US docs * fix: fix bug * perf[demo]: `radio-group` replace with `segmented`
1 parent 966bc10 commit 85c48c0

File tree

13 files changed

+195
-10
lines changed

13 files changed

+195
-10
lines changed

components/style/placementArrow.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -209,23 +209,29 @@ export default function getArrowStyle<Token extends TokenWithCommonCls<AliasToke
209209
// Offset the popover to account for the dropdown arrow
210210
// >>>>> Top
211211
[connectArrowCls(
212-
[`&-placement-topLeft`, `&-placement-top`, `&-placement-topRight`],
212+
[`&-placement-topLeft`, `&-placement-top`, `&-placement-topRight`].map(
213+
cls => (cls += ':not(&-arrow-hidden)'),
214+
),
213215
showArrowCls,
214216
)]: {
215217
paddingBottom: dropdownArrowDistance,
216218
},
217219

218220
// >>>>> Bottom
219221
[connectArrowCls(
220-
[`&-placement-bottomLeft`, `&-placement-bottom`, `&-placement-bottomRight`],
222+
[`&-placement-bottomLeft`, `&-placement-bottom`, `&-placement-bottomRight`].map(
223+
cls => (cls += ':not(&-arrow-hidden)'),
224+
),
221225
showArrowCls,
222226
)]: {
223227
paddingTop: dropdownArrowDistance,
224228
},
225229

226230
// >>>>> Left
227231
[connectArrowCls(
228-
[`&-placement-leftTop`, `&-placement-left`, `&-placement-leftBottom`],
232+
[`&-placement-leftTop`, `&-placement-left`, `&-placement-leftBottom`].map(
233+
cls => (cls += ':not(&-arrow-hidden)'),
234+
),
229235
showArrowCls,
230236
)]: {
231237
paddingRight: {
@@ -236,7 +242,9 @@ export default function getArrowStyle<Token extends TokenWithCommonCls<AliasToke
236242

237243
// >>>>> Right
238244
[connectArrowCls(
239-
[`&-placement-rightTop`, `&-placement-right`, `&-placement-rightBottom`],
245+
[`&-placement-rightTop`, `&-placement-right`, `&-placement-rightBottom`].map(
246+
cls => (cls += ':not(&-arrow-hidden)'),
247+
),
240248
showArrowCls,
241249
)]: {
242250
paddingLeft: {

components/tooltip/Tooltip.tsx

+8-2
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,16 @@ export default defineComponent({
145145
});
146146

147147
const tooltipPlacements = computed(() => {
148-
const { builtinPlacements, arrowPointAtCenter, autoAdjustOverflow } = props;
148+
const { builtinPlacements, autoAdjustOverflow, arrow, arrowPointAtCenter } = props;
149+
let mergedArrowPointAtCenter = arrowPointAtCenter;
150+
151+
if (typeof arrow === 'object') {
152+
mergedArrowPointAtCenter = arrow.pointAtCenter ?? arrowPointAtCenter;
153+
}
149154
return (
150155
builtinPlacements ||
151156
getPlacements({
152-
arrowPointAtCenter,
157+
arrowPointAtCenter: mergedArrowPointAtCenter,
153158
autoAdjustOverflow,
154159
})
155160
);
@@ -283,6 +288,7 @@ export default defineComponent({
283288
...attrs,
284289
...(props as TooltipProps),
285290
prefixCls: prefixCls.value,
291+
arrow: !!props.arrow,
286292
getPopupContainer: getPopupContainer?.value,
287293
builtinPlacements: tooltipPlacements.value,
288294
visible: tempVisible,

components/tooltip/abstractTooltipProps.ts

+5
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,12 @@ export default () => ({
3535
mouseEnterDelay: Number,
3636
mouseLeaveDelay: Number,
3737
getPopupContainer: Function as PropType<(triggerNode: HTMLElement) => HTMLElement>,
38+
/**@deprecated Please use `arrow={{ pointAtCenter: true }}` instead. */
3839
arrowPointAtCenter: { type: Boolean, default: undefined },
40+
arrow: {
41+
type: [Boolean, Object] as PropType<boolean | { pointAtCenter?: boolean }>,
42+
default: true as boolean | { pointAtCenter?: boolean },
43+
},
3944
autoAdjustOverflow: {
4045
type: [Boolean, Object] as PropType<boolean | AdjustOverflow>,
4146
default: undefined as boolean | AdjustOverflow,

components/tooltip/demo/arrow.vue

+143
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
<docs>
2+
---
3+
order: 6
4+
title:
5+
zh-CN: 箭头展示
6+
en-US: Arrow show
7+
---
8+
9+
## zh-CN
10+
支持显示、隐藏以及将箭头保持居中定位。
11+
12+
## en-US
13+
14+
Support show, hide or keep arrow in the center.
15+
</docs>
16+
17+
<template>
18+
<div id="components-a-tooltip-demo-arrow">
19+
<div style="margin-bottom: 24px">
20+
<a-segmented v-model:value="arrow" :options="options" />
21+
</div>
22+
<div :style="{ marginLeft: `${buttonWidth}px`, whiteSpace: 'nowrap' }">
23+
<a-tooltip placement="topLeft" :arrow="mergedArrow">
24+
<template #title>
25+
<span>prompt text</span>
26+
</template>
27+
<a-button>TL</a-button>
28+
</a-tooltip>
29+
<a-tooltip placement="top" :arrow="mergedArrow">
30+
<template #title>
31+
<span>prompt text</span>
32+
</template>
33+
<a-button>Top</a-button>
34+
</a-tooltip>
35+
<a-tooltip placement="topRight" :arrow="mergedArrow">
36+
<template #title>
37+
<span>prompt text</span>
38+
</template>
39+
<a-button>TR</a-button>
40+
</a-tooltip>
41+
</div>
42+
<div :style="{ width: `${buttonWidth}px`, float: 'left' }">
43+
<a-tooltip placement="leftTop" :arrow="mergedArrow">
44+
<template #title>
45+
<span>prompt text</span>
46+
</template>
47+
<a-button>LT</a-button>
48+
</a-tooltip>
49+
<a-tooltip placement="left" :arrow="mergedArrow">
50+
<template #title>
51+
<span>prompt text</span>
52+
</template>
53+
<a-button>Left</a-button>
54+
</a-tooltip>
55+
<a-tooltip placement="leftBottom" :arrow="mergedArrow">
56+
<template #title>
57+
<span>prompt text</span>
58+
</template>
59+
<a-button>LB</a-button>
60+
</a-tooltip>
61+
</div>
62+
<div :style="{ width: `${buttonWidth}px`, marginLeft: `${buttonWidth * 4 + 24}px` }">
63+
<a-tooltip placement="rightTop" :arrow="mergedArrow">
64+
<template #title>
65+
<span>prompt text</span>
66+
</template>
67+
<a-button>RT</a-button>
68+
</a-tooltip>
69+
<a-tooltip placement="right" :arrow="mergedArrow">
70+
<template #title>
71+
<span>prompt text</span>
72+
</template>
73+
<a-button>Right</a-button>
74+
</a-tooltip>
75+
<a-tooltip placement="rightBottom" :arrow="mergedArrow">
76+
<template #title>
77+
<span>prompt text</span>
78+
</template>
79+
<a-button>RB</a-button>
80+
</a-tooltip>
81+
</div>
82+
<div :style="{ marginLeft: `${buttonWidth}px`, clear: 'both', whiteSpace: 'nowrap' }">
83+
<a-tooltip placement="bottomLeft" :arrow="mergedArrow">
84+
<template #title>
85+
<span>prompt text</span>
86+
</template>
87+
<a-button>BL</a-button>
88+
</a-tooltip>
89+
<a-tooltip placement="bottom" :arrow="mergedArrow">
90+
<template #title>
91+
<span>prompt text</span>
92+
</template>
93+
<a-button>Bottom</a-button>
94+
</a-tooltip>
95+
<a-tooltip placement="bottomRight" :arrow="mergedArrow">
96+
<template #title>
97+
<span>prompt text</span>
98+
</template>
99+
<a-button>BR</a-button>
100+
</a-tooltip>
101+
</div>
102+
</div>
103+
</template>
104+
<script lang="ts" setup>
105+
import { ref, computed } from 'vue';
106+
const buttonWidth = 70;
107+
108+
const arrow = ref<string>('show');
109+
110+
const options = [
111+
{
112+
label: 'Show',
113+
value: 'show',
114+
},
115+
{
116+
label: 'Hide',
117+
value: 'hide',
118+
},
119+
{
120+
label: 'Center',
121+
value: 'center',
122+
},
123+
];
124+
const mergedArrow = computed(() => {
125+
switch (arrow.value) {
126+
case 'show':
127+
return true;
128+
case 'hide':
129+
return false;
130+
case 'center':
131+
return { pointAtCenter: true };
132+
}
133+
});
134+
</script>
135+
<style scoped>
136+
:deep(#components-a-tooltip-demo-arrow) .ant-btn {
137+
width: 70px;
138+
text-align: center;
139+
padding: 0;
140+
margin-right: 8px;
141+
margin-bottom: 8px;
142+
}
143+
</style>

components/tooltip/demo/index.vue

+3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
<arrow-point-at-center />
66
<auto-adjust-overflow />
77
<color />
8+
<Arrow />
89
</demo-sort>
910
</template>
1011
<script lang="ts">
@@ -13,6 +14,7 @@ import Placement from './placement.vue';
1314
import arrowPointAtCenter from './arrow-point-at-center.vue';
1415
import AutoAdjustOverflow from './auto-adjust-overflow.vue';
1516
import Color from './color.vue';
17+
import Arrow from './arrow.vue';
1618
import CN from '../index.zh-CN.md';
1719
import US from '../index.en-US.md';
1820
import { defineComponent } from 'vue';
@@ -25,6 +27,7 @@ export default defineComponent({
2527
arrowPointAtCenter,
2628
AutoAdjustOverflow,
2729
Color,
30+
Arrow,
2831
},
2932
setup() {
3033
return {};

components/tooltip/index.en-US.md

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ The following APIs are shared by Tooltip, Popconfirm, Popover.
2727
| --- | --- | --- | --- | --- |
2828
| align | this value will be merged into placement's config, please refer to the settings [dom-align](https://github.com/yiminghe/dom-align) | Object | - | |
2929
| arrowPointAtCenter | Whether the arrow is pointed at the center of target | boolean | `false` | |
30+
| arrow | Change arrow's visible state and change whether the arrow is pointed at the center of target. | boolean \| { pointAtCenter: boolean} | `true` | |
3031
| autoAdjustOverflow | Whether to adjust popup placement automatically when popup is off screen | boolean | `true` | |
3132
| color | The background color | string | - | |
3233
| destroyTooltipOnHide | Whether to destroy tooltip on hide | boolean | false | |

components/tooltip/index.zh-CN.md

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*gwrhTozoTC4AAA
2828
| --- | --- | --- | --- | --- |
2929
| align | 该值将合并到 placement 的配置中,设置参考 [dom-align](https://github.com/yiminghe/dom-align) | Object || |
3030
| arrowPointAtCenter | 箭头是否指向目标元素中心 | boolean | `false` | |
31+
| arrow | 修改箭头的显示状态以及修改箭头是否指向目标元素中心 | boolean \| { pointAtCenter: boolean} | `true` | |
3132
| autoAdjustOverflow | 气泡被遮挡时自动调整位置 | boolean | `true` | |
3233
| color | 背景颜色 | string || |
3334
| destroyTooltipOnHide | 隐藏后是否销毁 tooltip | boolean | false | |

components/vc-tooltip/src/Tooltip.tsx

+9-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Content from './Content';
55
import { getPropsSlot } from '../../_util/props-util';
66
import type { CSSProperties, PropType } from 'vue';
77
import { defineComponent, shallowRef, watchEffect } from 'vue';
8+
89
function noop() {}
910
export default defineComponent({
1011
compatConfig: { MODE: 3 },
@@ -36,16 +37,20 @@ export default defineComponent({
3637
popupVisible: { type: Boolean, default: undefined },
3738
onVisibleChange: Function,
3839
onPopupAlign: Function,
40+
arrow: { type: Boolean, default: true },
3941
},
4042
setup(props, { slots, attrs, expose }) {
4143
const triggerDOM = shallowRef();
4244

4345
const getPopupElement = () => {
4446
const { prefixCls, tipId, overlayInnerStyle } = props;
47+
4548
return [
46-
<div class={`${prefixCls}-arrow`} key="arrow">
47-
{getPropsSlot(slots, props, 'arrowContent')}
48-
</div>,
49+
!!props.arrow ? (
50+
<div class={`${prefixCls}-arrow`} key="arrow">
51+
{getPropsSlot(slots, props, 'arrowContent')}
52+
</div>
53+
) : null,
4954
<Content
5055
key="content"
5156
prefixCls={prefixCls}
@@ -122,6 +127,7 @@ export default defineComponent({
122127
onPopupVisibleChange: props.onVisibleChange || (noop as any),
123128
onPopupAlign: props.onPopupAlign || noop,
124129
ref: triggerDOM,
130+
arrow: !!props.arrow,
125131
popup: getPopupElement(),
126132
};
127133
return <Trigger {...triggerProps} v-slots={{ default: slots.default }}></Trigger>;

components/vc-tour/Tour.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ const Tour = defineComponent({
210210
/>
211211
<Trigger
212212
{...restProps}
213+
arrow={!!restProps.arrow}
213214
builtinPlacements={
214215
!curStep.value.target
215216
? undefined

components/vc-trigger/Popup/PopupInner.tsx

+7-1
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,13 @@ export default defineComponent({
171171
if (childNode.length > 1) {
172172
childNode = <div class={`${prefixCls}-content`}>{childNode}</div>;
173173
}
174-
const mergedClassName = classNames(prefixCls, attrs.class, alignedClassName.value);
174+
175+
const mergedClassName = classNames(
176+
prefixCls,
177+
attrs.class,
178+
alignedClassName.value,
179+
!props.arrow && `${prefixCls}-arrow-hidden`,
180+
);
175181
const hasAnimate = visible.value || !props.visible;
176182
const transitionProps = hasAnimate ? getTransitionProps(motion.value.name, motion.value) : {};
177183

components/vc-trigger/Popup/interface.ts

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ export const innerProps = {
1010
destroyPopupOnHide: Boolean,
1111
forceRender: Boolean,
1212

13+
arrow: { type: Boolean, default: true },
14+
1315
// Legacy Motion
1416
animation: [String, Object],
1517
transitionName: String,

components/vc-trigger/Trigger.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -414,11 +414,13 @@ export default defineComponent({
414414
stretch,
415415
alignPoint,
416416
mobile,
417+
arrow,
417418
forceRender,
418419
} = this.$props;
419420
const { sPopupVisible, point } = this.$data;
420421
const popupProps = {
421422
prefixCls,
423+
arrow,
422424
destroyPopupOnHide,
423425
visible: sPopupVisible,
424426
point: alignPoint ? point : null,

components/vc-trigger/interface.ts

+1
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export const triggerProps = () => ({
111111
onPopupVisibleChange: Function as PropType<(open: boolean) => void>,
112112
afterPopupVisibleChange: PropTypes.func.def(noop),
113113
popup: PropTypes.any,
114+
arrow: PropTypes.bool.def(true),
114115
popupStyle: { type: Object as PropType<CSSProperties>, default: undefined as CSSProperties },
115116
prefixCls: PropTypes.string.def('rc-trigger-popup'),
116117
popupClassName: PropTypes.string.def(''),

0 commit comments

Comments
 (0)