Skip to content

Commit f00b953

Browse files
committed
feat: dropdown add arrow
1 parent a1ac224 commit f00b953

File tree

7 files changed

+142
-28
lines changed

7 files changed

+142
-28
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<docs>
2+
---
3+
order: 3
4+
title:
5+
zh-CN: 箭头指向
6+
en-US: Arrow pointing at the center
7+
---
8+
9+
## zh-CN
10+
11+
设置 `arrow` 为 `{ pointAtCenter: true }` 后,箭头将指向目标元素的中心。
12+
13+
## en-US
14+
15+
By specifying `arrow` prop with `{ pointAtCenter: true }`, the arrow will point to the center of the target element.
16+
17+
</docs>
18+
19+
<template>
20+
<a-space style="display: flex; flex-wrap: wrap">
21+
<template v-for="placement in placements" :key="placement">
22+
<a-dropdown :placement="placement" :arrow="{ pointAtCenter: true }">
23+
<a-button>{{ placement }}</a-button>
24+
<template #overlay>
25+
<a-menu>
26+
<a-menu-item>
27+
<a href="javascript:;">1st menu item</a>
28+
</a-menu-item>
29+
<a-menu-item>
30+
<a href="javascript:;">2nd menu item</a>
31+
</a-menu-item>
32+
<a-menu-item>
33+
<a href="javascript:;">3rd menu item</a>
34+
</a-menu-item>
35+
</a-menu>
36+
</template>
37+
</a-dropdown>
38+
</template>
39+
</a-space>
40+
</template>
41+
<script lang="ts">
42+
import { defineComponent } from 'vue';
43+
44+
export default defineComponent({
45+
components: {},
46+
setup() {
47+
return {
48+
placements: ['topLeft', 'top', 'topRight', 'bottomLeft', 'bottom', 'bottomRight'] as const,
49+
};
50+
},
51+
});
52+
</script>

components/dropdown/demo/arrow.vue

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<docs>
2+
---
3+
order: 2
4+
title:
5+
zh-CN: 箭头
6+
en-US: Arrow
7+
---
8+
9+
## zh-CN
10+
11+
可以展示一个箭头。
12+
13+
## en-US
14+
15+
You could display an arrow.
16+
17+
</docs>
18+
19+
<template>
20+
<a-space style="display: flex; flex-wrap: wrap">
21+
<template v-for="placement in placements" :key="placement">
22+
<a-dropdown :placement="placement" arrow>
23+
<a-button>{{ placement }}</a-button>
24+
<template #overlay>
25+
<a-menu>
26+
<a-menu-item>
27+
<a href="javascript:;">1st menu item</a>
28+
</a-menu-item>
29+
<a-menu-item>
30+
<a href="javascript:;">2nd menu item</a>
31+
</a-menu-item>
32+
<a-menu-item>
33+
<a href="javascript:;">3rd menu item</a>
34+
</a-menu-item>
35+
</a-menu>
36+
</template>
37+
</a-dropdown>
38+
</template>
39+
</a-space>
40+
</template>
41+
<script lang="ts">
42+
import { defineComponent } from 'vue';
43+
44+
export default defineComponent({
45+
components: {},
46+
setup() {
47+
return {
48+
placements: ['topLeft', 'top', 'topRight', 'bottomLeft', 'bottom', 'bottomRight'] as const,
49+
};
50+
},
51+
});
52+
</script>

components/dropdown/demo/index.vue

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<item />
88
<overlay-visible />
99
<placement />
10+
<arrow-vue />
11+
<arrow-center-vue></arrow-center-vue>
1012
<sub-menu />
1113
<trigger />
1214
<loadingVue />
@@ -27,11 +29,14 @@ import Placement from './placement.vue';
2729
import SubMenu from './sub-menu.vue';
2830
import Trigger from './trigger.vue';
2931
import loadingVue from './loading.vue';
30-
32+
import arrowVue from './arrow.vue';
33+
import arrowCenterVue from './arrow-center.vue';
3134
export default defineComponent({
3235
CN,
3336
US,
3437
components: {
38+
arrowCenterVue,
39+
arrowVue,
3540
loadingVue,
3641
Basic,
3742
ContextMenu,

components/dropdown/dropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ const Dropdown = defineComponent({
144144
...attrs,
145145
builtinPlacements,
146146
overlayClassName: overlayClassNameCustomized,
147-
arrow,
147+
arrow: !!arrow,
148148
alignPoint,
149149
prefixCls: prefixCls.value,
150150
getPopupContainer: getPopupContainer.value,

components/dropdown/index.en-US.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ When there are more than a few options to choose from, you can wrap them in a `D
1717

1818
| Property | Description | Type | Default | |
1919
| --- | --- | --- | --- | --- |
20+
| arrow | Whether the dropdown arrow should be visible | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
2021
| destroyPopupOnHide | Whether destroy dropdown when hidden | boolean | false | |
2122
| disabled | whether the dropdown menu is disabled | boolean | - | |
2223
| getPopupContainer | to set the container of the dropdown menu. The default is to create a `div` element in `body`, you can reset it to the scrolling area and make a relative reposition. [example](https://codepen.io/afc163/pen/zEjNOy?editors=0010) | Function(triggerNode) | `() => document.body` | |

components/dropdown/index.zh-CN.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ cover: https://gw.alipayobjects.com/zos/alicdn/eedWN59yJ/Dropdown.svg
2121

2222
| 参数 | 说明 | 类型 | 默认值 | |
2323
| --- | --- | --- | --- | --- |
24+
| arrow | 下拉框箭头是否显示 | boolean \| { pointAtCenter: boolean } | false | 3.3.0 |
2425
| destroyPopupOnHide | 关闭后是否销毁 Dropdown | boolean | false | 3.0 |
2526
| disabled | 菜单是否禁用 | boolean | - | |
2627
| getPopupContainer | 菜单渲染父节点。默认渲染到 body 上,如果你遇到菜单滚动定位问题,试试修改为滚动的区域,并相对其定位。 | Function(triggerNode) | `() => document.body` | |

components/dropdown/style/index.less

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,14 @@
4949
}
5050

5151
// Offset the popover to account for the dropdown arrow
52-
&-show-arrow&-placement-topCenter,
5352
&-show-arrow&-placement-topLeft,
53+
&-show-arrow&-placement-top,
5454
&-show-arrow&-placement-topRight {
5555
padding-bottom: @popover-distance;
5656
}
5757

58-
&-show-arrow&-placement-bottomCenter,
5958
&-show-arrow&-placement-bottomLeft,
59+
&-show-arrow&-placement-bottom,
6060
&-show-arrow&-placement-bottomRight {
6161
padding-top: @popover-distance;
6262
}
@@ -68,23 +68,25 @@
6868
position: absolute;
6969
z-index: 1; // lift it up so the menu wouldn't cask shadow on it
7070
display: block;
71-
width: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
72-
height: sqrt(@popover-arrow-width * @popover-arrow-width * 2);
73-
background: transparent;
74-
border-style: solid;
75-
border-width: (sqrt(@popover-arrow-width * @popover-arrow-width * 2) / 2);
76-
transform: rotate(45deg);
71+
width: @popover-arrow-width;
72+
height: @popover-arrow-width;
73+
background: linear-gradient(
74+
135deg,
75+
transparent 40%,
76+
@popover-bg 40%
77+
); // Use linear-gradient to prevent arrow from covering text
78+
.roundedArrow(@popover-arrow-width, 5px, @popover-bg);
7779
}
7880

79-
&-placement-topCenter > &-arrow,
81+
&-placement-top > &-arrow,
8082
&-placement-topLeft > &-arrow,
8183
&-placement-topRight > &-arrow {
82-
bottom: @popover-distance - @popover-arrow-width + 2.2px;
83-
border-color: transparent @popover-bg @popover-bg transparent;
84-
box-shadow: 3px 3px 7px fade(@black, 7%);
84+
bottom: @popover-arrow-width * sqrt((1 / 2)) + 2px;
85+
box-shadow: 3px 3px 7px -3px fade(@black, 10%);
86+
transform: rotate(45deg);
8587
}
8688

87-
&-placement-topCenter > &-arrow {
89+
&-placement-top > &-arrow {
8890
left: 50%;
8991
transform: translateX(-50%) rotate(45deg);
9092
}
@@ -97,17 +99,17 @@
9799
right: 16px;
98100
}
99101

100-
&-placement-bottomCenter > &-arrow,
102+
&-placement-bottom > &-arrow,
101103
&-placement-bottomLeft > &-arrow,
102104
&-placement-bottomRight > &-arrow {
103-
top: @popover-distance - @popover-arrow-width + 2px;
104-
border-color: @popover-bg transparent transparent @popover-bg;
105-
box-shadow: -2px -2px 5px fade(@black, 6%);
105+
top: (@popover-arrow-width + 2px) * sqrt((1 / 2));
106+
box-shadow: 2px 2px 5px -2px fade(@black, 10%);
107+
transform: rotate(-135deg) translateY(-0.5px);
106108
}
107109

108-
&-placement-bottomCenter > &-arrow {
110+
&-placement-bottom > &-arrow {
109111
left: 50%;
110-
transform: translateX(-50%) rotate(45deg);
112+
transform: translateX(-50%) rotate(-135deg) translateY(-0.5px);
111113
}
112114

113115
&-placement-bottomLeft > &-arrow {
@@ -219,7 +221,8 @@
219221
background-color: @dropdown-selected-bg;
220222
}
221223

222-
&:hover {
224+
&:hover,
225+
&&-active {
223226
background-color: @item-hover-bg;
224227
}
225228

@@ -299,30 +302,30 @@
299302

300303
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomLeft,
301304
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomLeft,
302-
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomCenter,
303-
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomCenter,
305+
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottom,
306+
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottom,
304307
&.@{ant-prefix}-slide-down-enter.@{ant-prefix}-slide-down-enter-active&-placement-bottomRight,
305308
&.@{ant-prefix}-slide-down-appear.@{ant-prefix}-slide-down-appear-active&-placement-bottomRight {
306309
animation-name: antSlideUpIn;
307310
}
308311

309312
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topLeft,
310313
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topLeft,
311-
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topCenter,
312-
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topCenter,
314+
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-top,
315+
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-top,
313316
&.@{ant-prefix}-slide-up-enter.@{ant-prefix}-slide-up-enter-active&-placement-topRight,
314317
&.@{ant-prefix}-slide-up-appear.@{ant-prefix}-slide-up-appear-active&-placement-topRight {
315318
animation-name: antSlideDownIn;
316319
}
317320

318321
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomLeft,
319-
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomCenter,
322+
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottom,
320323
&.@{ant-prefix}-slide-down-leave.@{ant-prefix}-slide-down-leave-active&-placement-bottomRight {
321324
animation-name: antSlideUpOut;
322325
}
323326

324327
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topLeft,
325-
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topCenter,
328+
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-top,
326329
&.@{ant-prefix}-slide-up-leave.@{ant-prefix}-slide-up-leave-active&-placement-topRight {
327330
animation-name: antSlideDownOut;
328331
}

0 commit comments

Comments
 (0)