@carbon/vue 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +1 -1
- package/dist/carbon-data-viz-vue.common.js +3 -3
- package/dist/carbon-data-viz-vue.common.js.map +1 -1
- package/dist/carbon-data-viz-vue.umd.js +3 -3
- package/dist/carbon-data-viz-vue.umd.js.map +1 -1
- package/dist/carbon-data-viz-vue.umd.min.js.map +1 -1
- package/dist/carbon-vue.common.js +1236 -186
- package/dist/carbon-vue.common.js.map +1 -1
- package/dist/carbon-vue.umd.js +1236 -186
- package/dist/carbon-vue.umd.js.map +1 -1
- package/dist/carbon-vue.umd.min.js +4 -4
- package/dist/carbon-vue.umd.min.js.map +1 -1
- package/package.json +2 -2
- package/src/components/cv-content-switcher/cv-content-switcher.vue +1 -1
- package/src/components/cv-dropdown/_cv-dropdown-inner-c10.vue +201 -0
- package/src/components/cv-dropdown/_cv-dropdown-inner-form-item.vue +22 -0
- package/src/components/cv-dropdown/_cv-dropdown-inner.vue +213 -0
- package/src/components/cv-dropdown/cv-dropdown-item.vue +4 -0
- package/src/components/cv-dropdown/cv-dropdown.vue +20 -167
- package/src/components/cv-file-uploader/cv-file-uploader.vue +48 -8
- package/src/components/cv-inline-notification/cv-inline-notification.vue +25 -7
- package/src/components/cv-loading/cv-loading.vue +18 -1
- package/src/components/cv-modal/cv-modal.vue +15 -4
- package/src/components/cv-number-input/cv-number-input.vue +9 -2
- package/src/components/cv-tabs/cv-tabs.vue +22 -11
- package/src/components/cv-toast-notification/cv-toast-notification.vue +35 -0
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@carbon/vue",
|
|
3
3
|
"description": "A collection of components for the Carbon Design System built using Vue.js",
|
|
4
|
-
"version": "1.1.
|
|
4
|
+
"version": "1.1.1",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": "10.x"
|
|
7
|
+
"node": ">=10.x"
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
@@ -24,7 +24,7 @@ const toggleContent = (selector, on) => {
|
|
|
24
24
|
export default {
|
|
25
25
|
name: 'CvContentSwitcher',
|
|
26
26
|
created() {
|
|
27
|
-
// add these on created otherwise cv:mounted is too
|
|
27
|
+
// add these on created otherwise cv:mounted is too late.
|
|
28
28
|
this.$on('cv:open', srcComponent => this.onCvOpen(srcComponent));
|
|
29
29
|
this.$on('cv:mounted', srcComponent => this.onCvMount(srcComponent));
|
|
30
30
|
this.$on('cv:beforeDestroy', srcComponent =>
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Carbon Style Dropdown
|
|
3
|
+
|
|
4
|
+
Attributes:
|
|
5
|
+
placeholder: Placeholder text displayed before any selection is made.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
<cv-dropdown placeholder="Choose an option">
|
|
9
|
+
<cv-dropdown-item value="10">Option 1</cv-dropdown-item>
|
|
10
|
+
<cv-dropdown-item value="20">Option 2</cv-dropdown-item>
|
|
11
|
+
<cv-dropdown-item value="30">Option 3</cv-dropdown-item>
|
|
12
|
+
<cv-dropdown-item value="40">Option 4</cv-dropdown-item>
|
|
13
|
+
<cv-dropdown-item value="50">Option 5</cv-dropdown-item>
|
|
14
|
+
</cv-dropdown>
|
|
15
|
+
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<div>
|
|
20
|
+
<ul
|
|
21
|
+
data-dropdown
|
|
22
|
+
:data-value="internalValue"
|
|
23
|
+
class="bx--dropdown"
|
|
24
|
+
tabindex="0"
|
|
25
|
+
:class="{
|
|
26
|
+
'bx--dropdown--light': theme === 'light',
|
|
27
|
+
'bx--dropdown--up': up,
|
|
28
|
+
'bx--dropdown--open': open,
|
|
29
|
+
'bx--dropdown--invalid': isInvalid,
|
|
30
|
+
}"
|
|
31
|
+
v-bind="$attrs"
|
|
32
|
+
@keydown.down.prevent="onDown"
|
|
33
|
+
@keydown.up.prevent="onUp"
|
|
34
|
+
@keydown.enter.prevent="onClick"
|
|
35
|
+
@keydown.esc.prevent="onEsc"
|
|
36
|
+
@click="onClick"
|
|
37
|
+
>
|
|
38
|
+
<WarningFilled16 v-if="isInvalid" class="bx--dropdown__invalid" />
|
|
39
|
+
<li class="bx--dropdown-text" ref="valueContent">{{ placeholder }}</li>
|
|
40
|
+
<svg
|
|
41
|
+
class="bx--dropdown__arrow"
|
|
42
|
+
width="10"
|
|
43
|
+
height="5"
|
|
44
|
+
viewBox="0 0 10 5"
|
|
45
|
+
fill-rule="evenodd"
|
|
46
|
+
>
|
|
47
|
+
<path d="M10 0L5 5 0 0z"></path>
|
|
48
|
+
</svg>
|
|
49
|
+
<li>
|
|
50
|
+
<ul class="bx--dropdown-list">
|
|
51
|
+
<slot></slot>
|
|
52
|
+
</ul>
|
|
53
|
+
</li>
|
|
54
|
+
</ul>
|
|
55
|
+
<div v-if="isInvalid" class="bx--form-requirement">
|
|
56
|
+
{{ invalidMessage }}
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</template>
|
|
60
|
+
|
|
61
|
+
<script>
|
|
62
|
+
import themeMixin from '../../mixins/theme-mixin';
|
|
63
|
+
import WarningFilled16 from '@carbon/icons-vue/lib/warning--filled/16';
|
|
64
|
+
|
|
65
|
+
export default {
|
|
66
|
+
name: 'CvDropdownInner',
|
|
67
|
+
inheritAttrs: false,
|
|
68
|
+
mixins: [themeMixin],
|
|
69
|
+
components: { WarningFilled16 },
|
|
70
|
+
props: {
|
|
71
|
+
invalidMessage: String,
|
|
72
|
+
placeholder: {
|
|
73
|
+
type: String,
|
|
74
|
+
default: 'Choose an option',
|
|
75
|
+
},
|
|
76
|
+
up: Boolean,
|
|
77
|
+
value: String, // initial value of the dropdown,
|
|
78
|
+
},
|
|
79
|
+
data() {
|
|
80
|
+
return {
|
|
81
|
+
open: false,
|
|
82
|
+
dataValue: this.value,
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
mounted() {
|
|
86
|
+
this.$el.addEventListener('focusout', ev => {
|
|
87
|
+
if (ev.relatedTarget === null || !this.$el.contains(ev.relatedTarget)) {
|
|
88
|
+
this.open = false;
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
this.internalValue = this.internalValue; // forces update of value
|
|
92
|
+
},
|
|
93
|
+
model: {
|
|
94
|
+
prop: 'value',
|
|
95
|
+
event: 'change',
|
|
96
|
+
},
|
|
97
|
+
watch: {
|
|
98
|
+
value(val) {
|
|
99
|
+
this.internalValue = val;
|
|
100
|
+
},
|
|
101
|
+
},
|
|
102
|
+
computed: {
|
|
103
|
+
isInvalid() {
|
|
104
|
+
return this.invalidMessage && this.invalidMessage.length > 0;
|
|
105
|
+
},
|
|
106
|
+
internalValue: {
|
|
107
|
+
get() {
|
|
108
|
+
return this.dataValue;
|
|
109
|
+
},
|
|
110
|
+
set(val) {
|
|
111
|
+
const childItems = this.dropdownItems();
|
|
112
|
+
for (let index in childItems) {
|
|
113
|
+
let child = childItems[index];
|
|
114
|
+
let selected = child.value === val;
|
|
115
|
+
child.internalSelected = selected;
|
|
116
|
+
|
|
117
|
+
if (selected) {
|
|
118
|
+
this.$refs.valueContent.innerHTML = child.internalContent;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (this.dataValue !== val) {
|
|
122
|
+
// only raise event on change
|
|
123
|
+
this.dataValue = val;
|
|
124
|
+
this.$emit('change', this.dataValue);
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
methods: {
|
|
130
|
+
dropdownItems() {
|
|
131
|
+
return this.$children.filter(item => item.$_CvDropdownItem);
|
|
132
|
+
},
|
|
133
|
+
doMove(up) {
|
|
134
|
+
// requery could have changed
|
|
135
|
+
let currentFocusEl = this.$el.querySelector('.cv-dropdown-item :focus');
|
|
136
|
+
let currentFocusValue;
|
|
137
|
+
let childItems = this.dropdownItems();
|
|
138
|
+
let last = childItems.length - 1;
|
|
139
|
+
let currentFocusIndex = up ? 0 : last;
|
|
140
|
+
let nextFocusIndex;
|
|
141
|
+
|
|
142
|
+
if (currentFocusEl) {
|
|
143
|
+
currentFocusValue = currentFocusEl.parentNode.getAttribute(
|
|
144
|
+
'data-value'
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (currentFocusValue !== undefined) {
|
|
149
|
+
currentFocusIndex = childItems.findIndex(
|
|
150
|
+
child => child.value === currentFocusValue
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (up) {
|
|
155
|
+
nextFocusIndex = currentFocusIndex > 0 ? currentFocusIndex - 1 : last;
|
|
156
|
+
if (childItems[nextFocusIndex].internalSelected) {
|
|
157
|
+
nextFocusIndex = nextFocusIndex > 0 ? nextFocusIndex - 1 : last;
|
|
158
|
+
}
|
|
159
|
+
} else {
|
|
160
|
+
nextFocusIndex = currentFocusIndex < last ? currentFocusIndex + 1 : 0;
|
|
161
|
+
if (childItems[nextFocusIndex].internalSelected) {
|
|
162
|
+
nextFocusIndex = nextFocusIndex < last ? nextFocusIndex + 1 : 0;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
childItems[nextFocusIndex].setFocus();
|
|
167
|
+
},
|
|
168
|
+
onDown() {
|
|
169
|
+
if (!this.open) {
|
|
170
|
+
this.open = true;
|
|
171
|
+
} else {
|
|
172
|
+
this.doMove(false);
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
onUp() {
|
|
176
|
+
if (this.open) {
|
|
177
|
+
this.doMove(true);
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
onEsc() {
|
|
181
|
+
this.open = false;
|
|
182
|
+
this.$el.focus();
|
|
183
|
+
},
|
|
184
|
+
onClick(ev) {
|
|
185
|
+
this.open = !this.open;
|
|
186
|
+
if (!this.open) {
|
|
187
|
+
this.$el.focus();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (ev.target.classList.contains('bx--dropdown-link')) {
|
|
191
|
+
const targetItemEl = ev.target.parentNode;
|
|
192
|
+
const newValue = targetItemEl.getAttribute('data-value');
|
|
193
|
+
|
|
194
|
+
this.internalValue = newValue;
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
</script>
|
|
200
|
+
|
|
201
|
+
<style lang="scss"></style>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<div class="bx--form-item">
|
|
3
|
+
<cv-dropdown-inner v-bind="$attrs" v-on="$listeners" :value="value">
|
|
4
|
+
<slot></slot>
|
|
5
|
+
</cv-dropdown-inner>
|
|
6
|
+
</div>
|
|
7
|
+
</template>
|
|
8
|
+
|
|
9
|
+
<script>
|
|
10
|
+
import CvDropdownInner from './_cv-dropdown-inner-c10';
|
|
11
|
+
|
|
12
|
+
export default {
|
|
13
|
+
name: 'CvDropdownInnerFormItem',
|
|
14
|
+
components: { CvDropdownInner },
|
|
15
|
+
inheritAttrs: false,
|
|
16
|
+
props: {
|
|
17
|
+
value: String,
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<style lang="scss"></style>
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Carbon Style Dropdown
|
|
3
|
+
|
|
4
|
+
Attributes:
|
|
5
|
+
placeholder: Placeholder text displayed before any selection is made.
|
|
6
|
+
|
|
7
|
+
Usage:
|
|
8
|
+
<cv-dropdown placeholder="Choose an option">
|
|
9
|
+
<cv-dropdown-item value="10">Option 1</cv-dropdown-item>
|
|
10
|
+
<cv-dropdown-item value="20">Option 2</cv-dropdown-item>
|
|
11
|
+
<cv-dropdown-item value="30">Option 3</cv-dropdown-item>
|
|
12
|
+
<cv-dropdown-item value="40">Option 4</cv-dropdown-item>
|
|
13
|
+
<cv-dropdown-item value="50">Option 5</cv-dropdown-item>
|
|
14
|
+
</cv-dropdown>
|
|
15
|
+
|
|
16
|
+
-->
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<ul
|
|
20
|
+
data-dropdown
|
|
21
|
+
:data-value="internalValue"
|
|
22
|
+
class="bx--dropdown"
|
|
23
|
+
tabindex="0"
|
|
24
|
+
:class="{
|
|
25
|
+
'bx--dropdown--light': theme === 'light',
|
|
26
|
+
'bx--dropdown--up': up,
|
|
27
|
+
'bx--dropdown--open': open,
|
|
28
|
+
}"
|
|
29
|
+
v-bind="$attrs"
|
|
30
|
+
@keydown.down.prevent="onDown"
|
|
31
|
+
@keydown.up.prevent="onUp"
|
|
32
|
+
@keydown.enter.prevent="onClick"
|
|
33
|
+
@keydown.esc.prevent="onEsc"
|
|
34
|
+
@click="onClick"
|
|
35
|
+
>
|
|
36
|
+
<li class="bx--dropdown-text" ref="valueContent">{{ placeholder }}</li>
|
|
37
|
+
<svg
|
|
38
|
+
class="bx--dropdown__arrow"
|
|
39
|
+
width="10"
|
|
40
|
+
height="5"
|
|
41
|
+
viewBox="0 0 10 5"
|
|
42
|
+
fill-rule="evenodd"
|
|
43
|
+
>
|
|
44
|
+
<path d="M10 0L5 5 0 0z"></path>
|
|
45
|
+
</svg>
|
|
46
|
+
<li>
|
|
47
|
+
<ul class="bx--dropdown-list">
|
|
48
|
+
<slot></slot>
|
|
49
|
+
</ul>
|
|
50
|
+
</li>
|
|
51
|
+
</ul>
|
|
52
|
+
</template>
|
|
53
|
+
|
|
54
|
+
<script>
|
|
55
|
+
import themeMixin from '../../mixins/theme-mixin';
|
|
56
|
+
|
|
57
|
+
export default {
|
|
58
|
+
name: 'CvDropdownInner',
|
|
59
|
+
inheritAttrs: false,
|
|
60
|
+
mixins: [themeMixin],
|
|
61
|
+
props: {
|
|
62
|
+
placeholder: {
|
|
63
|
+
type: String,
|
|
64
|
+
default: 'Choose an option',
|
|
65
|
+
},
|
|
66
|
+
up: Boolean,
|
|
67
|
+
value: String, // initial value of the dropdown,
|
|
68
|
+
},
|
|
69
|
+
data() {
|
|
70
|
+
return {
|
|
71
|
+
open: false,
|
|
72
|
+
dataValue: null,
|
|
73
|
+
};
|
|
74
|
+
},
|
|
75
|
+
created() {
|
|
76
|
+
// add these on created otherwise cv:mounted is too late.
|
|
77
|
+
this.$on('cv:mounted', srcComponent => this.onCvMount(srcComponent));
|
|
78
|
+
this.$on('cv:beforeDestroy', srcComponent =>
|
|
79
|
+
this.onCvBeforeDestroy(srcComponent)
|
|
80
|
+
);
|
|
81
|
+
},
|
|
82
|
+
mounted() {
|
|
83
|
+
this.$el.addEventListener('focusout', ev => {
|
|
84
|
+
if (ev.relatedTarget === null || !this.$el.contains(ev.relatedTarget)) {
|
|
85
|
+
this.open = false;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
if (this.value) {
|
|
89
|
+
this.internalValue = this.value; // forces update of value
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
model: {
|
|
93
|
+
prop: 'value',
|
|
94
|
+
event: 'change',
|
|
95
|
+
},
|
|
96
|
+
watch: {
|
|
97
|
+
value(val) {
|
|
98
|
+
this.internalValue = val;
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
computed: {
|
|
102
|
+
internalValue: {
|
|
103
|
+
get() {
|
|
104
|
+
return this.dataValue;
|
|
105
|
+
},
|
|
106
|
+
set(val) {
|
|
107
|
+
const childItems = this.dropdownItems();
|
|
108
|
+
for (let index in childItems) {
|
|
109
|
+
let child = childItems[index];
|
|
110
|
+
let selected = child.value === val;
|
|
111
|
+
|
|
112
|
+
child.internalSelected = selected;
|
|
113
|
+
|
|
114
|
+
if (selected) {
|
|
115
|
+
this.$refs.valueContent.innerHTML = child.internalContent;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (this.dataValue !== val) {
|
|
119
|
+
// only raise event on change
|
|
120
|
+
this.dataValue = val;
|
|
121
|
+
this.$emit('change', this.dataValue);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
methods: {
|
|
127
|
+
onCvMount(srcComponent) {
|
|
128
|
+
if (srcComponent.internalSelected) {
|
|
129
|
+
this.internalValue = srcComponent.value;
|
|
130
|
+
} else {
|
|
131
|
+
if (this.internalValue === srcComponent.value) {
|
|
132
|
+
srcComponent.internalSelected = true;
|
|
133
|
+
this.internalValue = srcComponent.value;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
onCvBeforeDestroy(srcComponent) {
|
|
138
|
+
if (srcComponent.value === this.internalValue) {
|
|
139
|
+
this.internalValue = null;
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
dropdownItems() {
|
|
143
|
+
return this.$children.filter(item => item.$_CvDropdownItem);
|
|
144
|
+
},
|
|
145
|
+
doMove(up) {
|
|
146
|
+
// requery could have changed
|
|
147
|
+
let currentFocusEl = this.$el.querySelector('.cv-dropdown-item :focus');
|
|
148
|
+
let currentFocusValue;
|
|
149
|
+
let childItems = this.dropdownItems();
|
|
150
|
+
let last = childItems.length - 1;
|
|
151
|
+
let currentFocusIndex = up ? 0 : last;
|
|
152
|
+
let nextFocusIndex;
|
|
153
|
+
|
|
154
|
+
if (currentFocusEl) {
|
|
155
|
+
currentFocusValue = currentFocusEl.parentNode.getAttribute(
|
|
156
|
+
'data-value'
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (currentFocusValue !== undefined) {
|
|
161
|
+
currentFocusIndex = childItems.findIndex(
|
|
162
|
+
child => child.value === currentFocusValue
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
if (up) {
|
|
167
|
+
nextFocusIndex = currentFocusIndex > 0 ? currentFocusIndex - 1 : last;
|
|
168
|
+
if (childItems[nextFocusIndex].internalSelected) {
|
|
169
|
+
nextFocusIndex = nextFocusIndex > 0 ? nextFocusIndex - 1 : last;
|
|
170
|
+
}
|
|
171
|
+
} else {
|
|
172
|
+
nextFocusIndex = currentFocusIndex < last ? currentFocusIndex + 1 : 0;
|
|
173
|
+
if (childItems[nextFocusIndex].internalSelected) {
|
|
174
|
+
nextFocusIndex = nextFocusIndex < last ? nextFocusIndex + 1 : 0;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
childItems[nextFocusIndex].setFocus();
|
|
179
|
+
},
|
|
180
|
+
onDown() {
|
|
181
|
+
if (!this.open) {
|
|
182
|
+
this.open = true;
|
|
183
|
+
} else {
|
|
184
|
+
this.doMove(false);
|
|
185
|
+
}
|
|
186
|
+
},
|
|
187
|
+
onUp() {
|
|
188
|
+
if (this.open) {
|
|
189
|
+
this.doMove(true);
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
onEsc() {
|
|
193
|
+
this.open = false;
|
|
194
|
+
this.$el.focus();
|
|
195
|
+
},
|
|
196
|
+
onClick(ev) {
|
|
197
|
+
this.open = !this.open;
|
|
198
|
+
if (!this.open) {
|
|
199
|
+
this.$el.focus();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
if (ev.target.classList.contains('bx--dropdown-link')) {
|
|
203
|
+
const targetItemEl = ev.target.parentNode;
|
|
204
|
+
const newValue = targetItemEl.getAttribute('data-value');
|
|
205
|
+
|
|
206
|
+
this.internalValue = newValue;
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
};
|
|
211
|
+
</script>
|
|
212
|
+
|
|
213
|
+
<style lang="scss"></style>
|
|
@@ -44,6 +44,10 @@ export default {
|
|
|
44
44
|
},
|
|
45
45
|
mounted() {
|
|
46
46
|
this.$_CvDropdownItem = true; // for use by parent with $children
|
|
47
|
+
this.$parent.$emit('cv:mounted', this);
|
|
48
|
+
},
|
|
49
|
+
beforeDestroy() {
|
|
50
|
+
this.$parent.$emit('cv:beforeDestory', this);
|
|
47
51
|
},
|
|
48
52
|
computed: {
|
|
49
53
|
internalSelected: {
|
|
@@ -1,186 +1,39 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
Carbon Style Dropdown
|
|
3
|
-
|
|
4
|
-
Attributes:
|
|
5
|
-
placeholder: Placeholder text displayed before any selection is made.
|
|
6
|
-
|
|
7
|
-
Usage:
|
|
8
|
-
<cv-dropdown placeholder="Choose an option">
|
|
9
|
-
<cv-dropdown-item value="10">Option 1</cv-dropdown-item>
|
|
10
|
-
<cv-dropdown-item value="20">Option 2</cv-dropdown-item>
|
|
11
|
-
<cv-dropdown-item value="30">Option 3</cv-dropdown-item>
|
|
12
|
-
<cv-dropdown-item value="40">Option 4</cv-dropdown-item>
|
|
13
|
-
<cv-dropdown-item value="50">Option 5</cv-dropdown-item>
|
|
14
|
-
</cv-dropdown>
|
|
15
|
-
|
|
16
|
-
-->
|
|
17
|
-
|
|
18
1
|
<template>
|
|
19
|
-
<
|
|
20
|
-
|
|
21
|
-
:data-value="internalValue"
|
|
22
|
-
class="cv-dropdown bx--dropdown"
|
|
23
|
-
tabindex="0"
|
|
24
|
-
:class="{
|
|
25
|
-
'bx--dropdown--light': theme === 'light',
|
|
26
|
-
'bx--dropdown--up': up,
|
|
27
|
-
'bx--dropdown--open': open,
|
|
28
|
-
}"
|
|
2
|
+
<component
|
|
3
|
+
:is="tagType"
|
|
29
4
|
v-bind="$attrs"
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
@keydown.esc.prevent="onEsc"
|
|
34
|
-
@click="onClick"
|
|
5
|
+
v-on="$listeners"
|
|
6
|
+
:value="value"
|
|
7
|
+
class="cv-dropdown"
|
|
35
8
|
>
|
|
36
|
-
<
|
|
37
|
-
|
|
38
|
-
class="bx--dropdown__arrow"
|
|
39
|
-
width="10"
|
|
40
|
-
height="5"
|
|
41
|
-
viewBox="0 0 10 5"
|
|
42
|
-
fill-rule="evenodd"
|
|
43
|
-
>
|
|
44
|
-
<path d="M10 0L5 5 0 0z"></path>
|
|
45
|
-
</svg>
|
|
46
|
-
<li>
|
|
47
|
-
<ul class="bx--dropdown-list">
|
|
48
|
-
<slot></slot>
|
|
49
|
-
</ul>
|
|
50
|
-
</li>
|
|
51
|
-
</ul>
|
|
9
|
+
<slot></slot>
|
|
10
|
+
</component>
|
|
52
11
|
</template>
|
|
53
12
|
|
|
54
13
|
<script>
|
|
55
|
-
import
|
|
14
|
+
import { componentsX } from '../../_internal/_feature-flags';
|
|
15
|
+
import CvDropdownInnerFormItem from './_cv-dropdown-inner-form-item';
|
|
16
|
+
import CvDropdownInner from './_cv-dropdown-inner';
|
|
56
17
|
|
|
57
18
|
export default {
|
|
58
19
|
name: 'CvDropdown',
|
|
59
|
-
|
|
20
|
+
components: { CvDropdownInnerFormItem, CvDropdownInner },
|
|
21
|
+
inheritAttrs: false,
|
|
60
22
|
props: {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
default: 'Choose an option',
|
|
64
|
-
},
|
|
65
|
-
up: Boolean,
|
|
66
|
-
value: String, // initial value of the dropdown,
|
|
67
|
-
},
|
|
68
|
-
data() {
|
|
69
|
-
return {
|
|
70
|
-
open: false,
|
|
71
|
-
dataValue: this.value,
|
|
72
|
-
};
|
|
23
|
+
value: String,
|
|
24
|
+
formItem: { type: Boolean, default: componentsX },
|
|
73
25
|
},
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
this.internalValue = this.internalValue; // forces update of value
|
|
26
|
+
computed: {
|
|
27
|
+
tagType() {
|
|
28
|
+
return this.formItem
|
|
29
|
+
? 'cv-dropdown-inner-form-item'
|
|
30
|
+
: 'cv-dropdown-inner';
|
|
31
|
+
},
|
|
81
32
|
},
|
|
82
33
|
model: {
|
|
83
34
|
prop: 'value',
|
|
84
35
|
event: 'change',
|
|
85
36
|
},
|
|
86
|
-
watch: {
|
|
87
|
-
value(val) {
|
|
88
|
-
this.internalValue = val;
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
computed: {
|
|
92
|
-
internalValue: {
|
|
93
|
-
get() {
|
|
94
|
-
return this.dataValue;
|
|
95
|
-
},
|
|
96
|
-
set(val) {
|
|
97
|
-
const childItems = this.dropdownItems();
|
|
98
|
-
for (let index in childItems) {
|
|
99
|
-
let child = childItems[index];
|
|
100
|
-
let selected = child.value === val;
|
|
101
|
-
child.internalSelected = selected;
|
|
102
|
-
|
|
103
|
-
if (selected) {
|
|
104
|
-
this.$refs.valueContent.innerHTML = child.internalContent;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
if (this.dataValue !== val) {
|
|
108
|
-
// only raise event on change
|
|
109
|
-
this.dataValue = val;
|
|
110
|
-
this.$emit('change', this.dataValue);
|
|
111
|
-
}
|
|
112
|
-
},
|
|
113
|
-
},
|
|
114
|
-
},
|
|
115
|
-
methods: {
|
|
116
|
-
dropdownItems() {
|
|
117
|
-
return this.$children.filter(item => item.$_CvDropdownItem);
|
|
118
|
-
},
|
|
119
|
-
doMove(up) {
|
|
120
|
-
// requery could have changed
|
|
121
|
-
let currentFocusEl = this.$el.querySelector('.cv-dropdown-item :focus');
|
|
122
|
-
let currentFocusValue;
|
|
123
|
-
let childItems = this.dropdownItems();
|
|
124
|
-
let last = childItems.length - 1;
|
|
125
|
-
let currentFocusIndex = up ? 0 : last;
|
|
126
|
-
let nextFocusIndex;
|
|
127
|
-
|
|
128
|
-
if (currentFocusEl) {
|
|
129
|
-
currentFocusValue = currentFocusEl.parentNode.getAttribute(
|
|
130
|
-
'data-value'
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (currentFocusValue !== undefined) {
|
|
135
|
-
currentFocusIndex = childItems.findIndex(
|
|
136
|
-
child => child.value === currentFocusValue
|
|
137
|
-
);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
if (up) {
|
|
141
|
-
nextFocusIndex = currentFocusIndex > 0 ? currentFocusIndex - 1 : last;
|
|
142
|
-
if (childItems[nextFocusIndex].internalSelected) {
|
|
143
|
-
nextFocusIndex = nextFocusIndex > 0 ? nextFocusIndex - 1 : last;
|
|
144
|
-
}
|
|
145
|
-
} else {
|
|
146
|
-
nextFocusIndex = currentFocusIndex < last ? currentFocusIndex + 1 : 0;
|
|
147
|
-
if (childItems[nextFocusIndex].internalSelected) {
|
|
148
|
-
nextFocusIndex = nextFocusIndex < last ? nextFocusIndex + 1 : 0;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
childItems[nextFocusIndex].setFocus();
|
|
153
|
-
},
|
|
154
|
-
onDown() {
|
|
155
|
-
if (!this.open) {
|
|
156
|
-
this.open = true;
|
|
157
|
-
} else {
|
|
158
|
-
this.doMove(false);
|
|
159
|
-
}
|
|
160
|
-
},
|
|
161
|
-
onUp() {
|
|
162
|
-
if (this.open) {
|
|
163
|
-
this.doMove(true);
|
|
164
|
-
}
|
|
165
|
-
},
|
|
166
|
-
onEsc() {
|
|
167
|
-
this.open = false;
|
|
168
|
-
this.$el.focus();
|
|
169
|
-
},
|
|
170
|
-
onClick(ev) {
|
|
171
|
-
this.open = !this.open;
|
|
172
|
-
if (!this.open) {
|
|
173
|
-
this.$el.focus();
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
if (ev.target.classList.contains('bx--dropdown-link')) {
|
|
177
|
-
const targetItemEl = ev.target.parentNode;
|
|
178
|
-
const newValue = targetItemEl.getAttribute('data-value');
|
|
179
|
-
|
|
180
|
-
this.internalValue = newValue;
|
|
181
|
-
}
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
37
|
};
|
|
185
38
|
</script>
|
|
186
39
|
|