1
- <template >
2
- <li :class =" computedDropdownClasses" >
3
- <a href =" #"
4
- aria-haspopup =" true"
5
- :aria-expanded =" visible"
6
- :class =" computedToggleClasses"
7
- @click =" click($event)"
8
- ref =" toggle"
9
- >
10
- <slot name =" button" >
11
- <button class =" btn btn-outline-primary dropdown-toggle" >{{text}}</button >
12
- </slot >
13
- </a >
14
- <div :class =" computedMenuClasses" ref =" menu" v-on-clickaway =" hide" >
15
- <slot ></slot >
16
- </div >
17
- </li >
18
- </template >
19
1
<script >
2
+ import CLink from ' ../Link/CLink'
20
3
import Popper from ' popper.js'
21
4
import { mixin as clickaway } from ' vue-clickaway'
5
+ import { deepObjectsMerge } from ' @coreui/coreui/dist/js/coreui-utilities'
22
6
23
7
export default {
24
8
name: ' CDropdown' ,
@@ -33,20 +17,34 @@ export default {
33
17
this .createPopper
34
18
},
35
19
props: {
36
- text : {
20
+ buttonContent : {
37
21
type: String ,
38
22
default: ' Dropdown'
39
23
},
40
24
show: Boolean ,
41
25
dropup: Boolean ,
42
26
disabled: Boolean ,
43
- right: Boolean ,
44
- menuClasses: String ,
45
- toggleClasses: String ,
46
- popperConfig: Object
27
+ addMenuClasses: String ,
28
+ addButtonClasses: String ,
29
+ nav: Boolean ,
30
+ noCaret: Boolean ,
31
+ variant: {
32
+ type: String ,
33
+ default: ' secondary'
34
+ },
35
+ size: {
36
+ type: String ,
37
+ validator : val => [' sm' , ' lg' ].includes (val)
38
+ },
39
+ split: Boolean ,
40
+ offset: Number ,
41
+ placement: String ,
42
+ noFlip: Boolean ,
43
+ popperConfig: Object ,
44
+ noPopper: Boolean ,
47
45
},
48
46
mounted () {
49
- this .checkForPopper ()
47
+ this .menagePopper ()
50
48
},
51
49
methods: {
52
50
hide () {
@@ -57,14 +55,16 @@ export default {
57
55
e .preventDefault ()
58
56
this .toggle (! this .visible )
59
57
},
60
- toggle (visible ) {
58
+ toggle (value ) {
61
59
if (this .disabled )
62
60
return
63
- this .visible = visible
64
- this .checkForPopper ()
61
+ setTimeout (() => {
62
+ this .visible = value
63
+ this .menagePopper ()
64
+ }, 0 )
65
65
},
66
- checkForPopper () {
67
- if (this .popperConfig )
66
+ menagePopper () {
67
+ if (! this .noPopper )
68
68
setTimeout (() => this .visible ? this .createPopper () : this .removePopper (), 0 )
69
69
},
70
70
removePopper () {
@@ -73,37 +73,102 @@ export default {
73
73
}
74
74
this ._popper = null
75
75
},
76
- createPopper (element ) {
76
+ createPopper () {
77
77
this .removePopper ()
78
- this ._popper = new Popper (this .$refs .toggle , this .$refs .menu , this .popperConfig )
78
+ this ._popper = new Popper (this .$refs .toggle , this .$refs .menu , this .computedPopperConfig )
79
79
}
80
80
},
81
81
computed: {
82
+ generatedPopperConfig () {
83
+ return {
84
+ placement: this .placement ? this .placement : this .dropup ? ' top-start' : ' bottom-start' ,
85
+ modifiers: {
86
+ offset: { offset: this .offset || 0 },
87
+ flip: { enabled: ! this .noFlip }
88
+ }
89
+ }
90
+ },
91
+ computedPopperConfig () {
92
+ return deepObjectsMerge (this .generatedPopperConfig , this .popperConfig || {})
93
+ },
82
94
computedDropdownClasses () {
83
95
return [
84
- ' dropdown' ,
96
+ ! this . dropup ? ' dropdown' : ' dropup ' ,
85
97
{
86
- ' dropup' : this .dropup ,
87
- ' show' : this .visible
98
+ ' show' : this .visible ,
99
+ ' nav-item' : this .nav ,
100
+ ' btn-group' : this .haveButtonClasses
88
101
}
89
102
]
90
103
},
91
- computedToggleClasses () {
104
+ buttonTag () {
105
+ return this .nav ? CLink : ' button'
106
+ },
107
+ haveButtonClasses () {
108
+ return this .nav && ! this .split ? Boolean (this .$options .propsData .variant ) : true
109
+ },
110
+ computedButtonClasses () {
92
111
return [
93
- this .toggleClasses ,
112
+ this .addButtonClasses ,
113
+ this .haveButtonClasses ? ` btn btn-${ this .variant } ` : ' nav-link' ,
94
114
{
95
- ' disabled' : this .disabled
115
+ ' dropdown-toggle' : ! this .noCaret && ! this .split ,
116
+ [` btn-${ this .size } ` ]: this .size ,
117
+ ' disabled' : this .disabled ,
96
118
}
97
119
]
98
120
},
99
121
computedMenuClasses () {
100
122
return [
101
- this .menuClasses ,
123
+ this .addMenuClasses ,
102
124
' dropdown-menu' ,
103
- this .right ? ' dropdown-menu-right' : ' dropdown-menu-left' ,
104
125
{ ' show' : this .visible }
105
126
]
106
- }
127
+ },
107
128
},
129
+ render (h ) {
130
+ const toggle = this .$slots .button || h (
131
+ this .buttonTag ,
132
+ {
133
+ style: { cursor: ' pointer' },
134
+ attrs: {
135
+ ' aria-haspopup' : true ,
136
+ ' aria-expanded' : this .visible ,
137
+ },
138
+ on: {
139
+ click: this .split ? ' ' : this .click
140
+ },
141
+ ref: ' toggle' ,
142
+ class: this .computedButtonClasses ,
143
+ domProps: ! this .$slots .buttonContent ?
144
+ { innerHTML: this .buttonContent } :
145
+ null
146
+ }, this .$slots .buttonContent )
147
+ let splitButton = h (false )
148
+ if (this .split ) {
149
+ splitButton = h (
150
+ this .buttonTag ,
151
+ {
152
+ class: [ this .computedButtonClasses , ' dropdown-toggle dropdown-toggle-split' ],
153
+ on: { click: this .click }
154
+ })
155
+ }
156
+
157
+
158
+ const content = h (
159
+ ' div' ,
160
+ {
161
+ class: this .computedMenuClasses ,
162
+ ref: ' menu' ,
163
+ directives: [{ name: ' on-clickaway' , value: this .hide }],
164
+ },
165
+ this .$slots .default
166
+ )
167
+ return h (
168
+ this .nav ? ' li' : ' div' ,
169
+ { class: this .computedDropdownClasses },
170
+ [ toggle, splitButton, content ]
171
+ )
172
+ }
108
173
}
109
174
</script >
0 commit comments