goodteditor-ui 1.0.12 → 1.0.13

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.
Files changed (75) hide show
  1. package/.eslintrc.js +7 -7
  2. package/.prettierrc +14 -14
  3. package/README.md +35 -35
  4. package/babel.config.js +5 -5
  5. package/dist/js.png +0 -0
  6. package/index.js +51 -51
  7. package/jsconfig.json +13 -13
  8. package/package.json +57 -57
  9. package/src/App.vue +36 -36
  10. package/src/components/ui/Avatar.md +68 -68
  11. package/src/components/ui/Avatar.vue +177 -177
  12. package/src/components/ui/Badge.md +20 -20
  13. package/src/components/ui/Badge.vue +75 -75
  14. package/src/components/ui/Collapse.md +90 -90
  15. package/src/components/ui/Collapse.vue +86 -86
  16. package/src/components/ui/ColorPicker/Alpha.vue +114 -114
  17. package/src/components/ui/ColorPicker/Colors.vue +117 -117
  18. package/src/components/ui/ColorPicker/Hue.vue +113 -113
  19. package/src/components/ui/ColorPicker/Preview.vue +55 -55
  20. package/src/components/ui/ColorPicker/Saturation.vue +123 -123
  21. package/src/components/ui/ColorPicker/mixin.js +105 -105
  22. package/src/components/ui/ColorPicker.md +17 -17
  23. package/src/components/ui/ColorPicker.vue +314 -314
  24. package/src/components/ui/Datalist.md +41 -41
  25. package/src/components/ui/Datalist.vue +157 -157
  26. package/src/components/ui/DatePicker.md +168 -168
  27. package/src/components/ui/DatePicker.vue +527 -527
  28. package/src/components/ui/FileSelector.md +105 -105
  29. package/src/components/ui/FileSelector.vue +82 -82
  30. package/src/components/ui/Grid.md +130 -130
  31. package/src/components/ui/Grid.vue +92 -92
  32. package/src/components/ui/Image.md +59 -59
  33. package/src/components/ui/Image.vue +57 -57
  34. package/src/components/ui/InputAutocomplete.md +115 -115
  35. package/src/components/ui/InputAutocomplete.vue +341 -341
  36. package/src/components/ui/InputColorPicker.md +51 -51
  37. package/src/components/ui/InputColorPicker.vue +151 -151
  38. package/src/components/ui/InputDatePicker.md +121 -121
  39. package/src/components/ui/InputDatePicker.vue +310 -310
  40. package/src/components/ui/InputTags.md +51 -51
  41. package/src/components/ui/InputTags.vue +184 -184
  42. package/src/components/ui/InputTimePicker.md +25 -25
  43. package/src/components/ui/InputTimePicker.vue +253 -253
  44. package/src/components/ui/InputUnits.md +20 -20
  45. package/src/components/ui/InputUnits.vue +257 -257
  46. package/src/components/ui/Lazy.md +37 -37
  47. package/src/components/ui/Lazy.vue +92 -92
  48. package/src/components/ui/Pagination.md +74 -74
  49. package/src/components/ui/Pagination.vue +138 -138
  50. package/src/components/ui/Paginator.md +34 -34
  51. package/src/components/ui/Paginator.vue +83 -83
  52. package/src/components/ui/Popover.md +34 -34
  53. package/src/components/ui/Popover.vue +258 -209
  54. package/src/components/ui/Popup.md +59 -59
  55. package/src/components/ui/Popup.vue +150 -150
  56. package/src/components/ui/ResponsiveContainer.md +58 -58
  57. package/src/components/ui/ResponsiveContainer.vue +99 -99
  58. package/src/components/ui/Select.md +187 -187
  59. package/src/components/ui/Select.vue +420 -420
  60. package/src/components/ui/TimePicker.md +50 -50
  61. package/src/components/ui/TimePicker.vue +252 -252
  62. package/src/components/ui/Tooltip.md +114 -52
  63. package/src/components/ui/Tooltip.vue +113 -113
  64. package/src/components/ui/utils/FormComponent.js +107 -107
  65. package/src/components/ui/utils/Helpers.js +84 -61
  66. package/src/components/ui/utils/WithPopover.js +99 -81
  67. package/src/main.js +8 -8
  68. package/styleguide.config.js +37 -37
  69. package/vue.config.js +8 -8
  70. package/.idea/codeStyles/Project.xml +0 -51
  71. package/.idea/codeStyles/codeStyleConfig.xml +0 -5
  72. package/.idea/goodt-ui.iml +0 -12
  73. package/.idea/inspectionProfiles/Project_Default.xml +0 -6
  74. package/.idea/modules.xml +0 -8
  75. package/.idea/vcs.xml +0 -6
@@ -1,420 +1,420 @@
1
- <template>
2
- <div
3
- class="ui-select form-elem"
4
- :class="cssClassExt"
5
- @keydown.prevent="onKeyDown"
6
- @click="onClick"
7
- tabindex="0"
8
- :data-popover="popoverTargetId"
9
- >
10
- <div class="ui-select-label u-select-none">
11
- <template v-if="multiple">
12
- <template v-if="optionsSelected.length">
13
- <!--
14
- @slot Label slot for multiple mode
15
- @binding {Object} option option
16
- @binding {any} value option's value
17
- @binding {String} label option's label
18
- @binding {Function} deselectOption deselects option function(option:Object)
19
- -->
20
- <slot
21
- name="label-multiple"
22
- v-for="(option, index) in optionsSelected"
23
- v-bind="{
24
- option,
25
- value: getOptionValue(option),
26
- label: getOptionLabel(option),
27
- deselectOption,
28
- }"
29
- >
30
- <ui-badge
31
- class="mar-none mar-right-2"
32
- theme="primary"
33
- size="small"
34
- :key="index"
35
- removable
36
- @click.native.stop
37
- @remove="deselectOption(option)"
38
- >
39
- <span>{{ getOptionLabel(option) }}</span>
40
- </ui-badge>
41
- </slot>
42
- </template>
43
- <div class="ui-select-placeholder events-none" v-else>
44
- <!--
45
- @slot Placeholder slot
46
- -->
47
- <slot name="placeholder">
48
- <input class="w-100" :placeholder="placeholder" />
49
- </slot>
50
- </div>
51
- </template>
52
-
53
- <template v-else>
54
- <!--
55
- @slot Label slot for single mode
56
- @binding {Object} option option
57
- @binding {any} value option's value
58
- @binding {String} label option's label
59
- -->
60
- <slot
61
- name="label"
62
- v-bind="{
63
- option: optionsSelected[0],
64
- value: getOptionValue(optionsSelected[0]),
65
- label: getOptionLabel(optionsSelected[0]),
66
- }"
67
- v-if="optionsSelected.length"
68
- >
69
- {{ getOptionLabel(optionsSelected[0]) }}
70
- </slot>
71
- <div class="ui-select-placeholder events-none" v-else>
72
- <!--
73
- @slot Placeholder slot
74
- -->
75
- <slot name="placeholder">
76
- <input class="w-100" :placeholder="placeholder" />
77
- </slot>
78
- </div>
79
- </template>
80
- </div>
81
- <!--
82
- @slot Open state icon slot
83
- -->
84
- <slot name="icon-open" v-if="popoverShow">
85
- <div class="icon w-auto h-auto mar-left-2 events-none">
86
- <i class="mdi mdi-chevron-up"></i>
87
- </div>
88
- </slot>
89
- <!--
90
- @slot Close state icon slot
91
- -->
92
- <slot name="icon-close" v-else>
93
- <div class="icon w-auto h-auto mar-left-2 events-none">
94
- <i class="mdi mdi-chevron-down"></i>
95
- </div>
96
- </slot>
97
-
98
- <ui-popover :show.sync="popoverShow" v-bind="popoverOptions">
99
- <ui-datalist
100
- class="w-100 pull-left"
101
- @click.native.stop
102
- @select-option="onDatalistSelectOption"
103
- v-bind="{ size, options }"
104
- :cursorIndex.sync="dataListCursorIndex"
105
- ref="datalist"
106
- >
107
- <template #header>
108
- <!--
109
- @slot Dropdown header slot
110
- -->
111
- <slot name="dropdown-header"></slot>
112
- </template>
113
- <template #option="{ option, index, cursorIndex }">
114
- <!--
115
- @slot Label slot for single mode
116
- @binding {Object} option option
117
- @binding {any} value option's value
118
- @binding {String} label option's label
119
- @binding {Number} index option's index
120
- @binding {Boolean} isSelected option selection status
121
- @binding {Number} cursorIndex current cursor index
122
- @binding {Function} selectOption function that selects option
123
- @binding {Function} deselectOption function that deselects option
124
- @binding {Function} toggleOption function that toggles option selection
125
- @binding {Number} optionIndex option's index
126
- @binding {Boolean} isOptionSelected option selection status
127
- -->
128
- <slot
129
- name="option"
130
- v-bind="{
131
- option,
132
- value: getOptionValue(option),
133
- label: getOptionLabel(option),
134
- index,
135
- isSelected: isOptionSelected(option),
136
- cursorIndex,
137
- selectOption,
138
- deselectOption,
139
- toggleOption,
140
- // legacy
141
- optionIndex: index,
142
- isOptionSelected: isOptionSelected(option),
143
- }"
144
- >
145
- <li
146
- :class="{
147
- active: isOptionSelected(option),
148
- 'bg-grey-lighter': index == cursorIndex,
149
- }"
150
- :key="index"
151
- @click="toggleOption(option)"
152
- >
153
- <div class="row row-collapse" v-if="multiple">
154
- <div class="col col-vmid text-truncate">
155
- <div
156
- class="text-truncate"
157
- style="min-height: calc(var(--line-height)*1em)"
158
- >
159
- {{ getOptionLabel(option) }}
160
- </div>
161
- </div>
162
- <div class="col col-auto col-vmid" v-if="isOptionSelected(option)">
163
- <i class="mdi mdi-check" style="line-height:1"></i>
164
- </div>
165
- </div>
166
- <div
167
- class="text-truncate"
168
- style="min-height: calc(var(--line-height)*1rem)"
169
- v-else
170
- >
171
- {{ getOptionLabel(option) }}
172
- </div>
173
- </li>
174
- </slot>
175
- </template>
176
- <template #footer>
177
- <!--
178
- @slot Dropdown footer slot
179
- -->
180
- <slot name="dropdown-footer"></slot>
181
- </template>
182
- </ui-datalist>
183
- </ui-popover>
184
- </div>
185
- </template>
186
- <style lang="less" scoped>
187
- .ui-select {
188
- display: inline-flex;
189
- align-items: center;
190
- &-label {
191
- white-space: nowrap;
192
- text-overflow: ellipsis;
193
- overflow: hidden;
194
- flex: 1 0 0;
195
- }
196
- &-placeholder {
197
- input {
198
- border: none;
199
- margin: 0;
200
- padding: 0;
201
- color: inherit;
202
- background: transparent;
203
- }
204
- }
205
- }
206
- </style>
207
- <script>
208
- import UiBadge from './Badge.vue';
209
- import UiDatalist from './Datalist.vue';
210
- import UiPopover from './Popover.vue';
211
- import FormComponent from './utils/FormComponent';
212
- import WithPopover from './utils/WithPopover';
213
- import { Key } from './utils/Helpers';
214
-
215
- export default {
216
- components: {
217
- UiBadge,
218
- UiDatalist,
219
- UiPopover,
220
- },
221
- mixins: [FormComponent, WithPopover],
222
- props: {
223
- /**
224
- * @model
225
- */
226
- value: {
227
- default() {
228
- return null;
229
- },
230
- },
231
- /**
232
- * Options. Array of Objects (option objects)
233
- */
234
- options: {
235
- type: Array,
236
- default() {
237
- return [];
238
- },
239
- },
240
- /**
241
- * Allow multiple selection
242
- */
243
- multiple: {
244
- type: Boolean,
245
- default: false,
246
- },
247
- /**
248
- * Defines whether 'value' is the option value field or option object
249
- * @see options
250
- */
251
- valueObjects: {
252
- type: Boolean,
253
- default: false,
254
- },
255
- /**
256
- * Defines the 'value' field of the option Object
257
- */
258
- valueField: {
259
- type: String,
260
- default: 'value',
261
- },
262
- /**
263
- * Defines the 'label' field of the option Object
264
- */
265
- labelField: {
266
- type: String,
267
- default: 'label',
268
- },
269
- autoWidth: {
270
- default: true,
271
- },
272
- },
273
- data() {
274
- return {
275
- optionsSelected: [],
276
- dataListCursorIndex: -1,
277
- };
278
- },
279
- computed: {
280
- /**
281
- * @return {object}
282
- */
283
- cssClassExt() {
284
- let obj = { 'u-select-none': this.readonly };
285
- return { ...this.cssClass, ...obj };
286
- },
287
- },
288
- watch: {
289
- value: {
290
- handler(model) {
291
- this.importModel(model);
292
- },
293
- immediate: true,
294
- },
295
- options() {
296
- this.importModel(this.value);
297
- },
298
- },
299
- methods: {
300
- importModel(model) {
301
- let ci = -1;
302
- let tmp = [];
303
- model = this.multiple ? (Array.isArray(model) ? model : [model]) : [model];
304
- model.forEach(modelItem => {
305
- let modelItemValue = this.valueObjects ? this.getOptionValue(modelItem) : modelItem;
306
- let optionIndex = this.options.findIndex(optionItem => {
307
- let optionItemValue = this.getOptionValue(optionItem);
308
- return optionItemValue === modelItemValue;
309
- });
310
- if (optionIndex >= 0) {
311
- ci = ci < 0 ? optionIndex : ci;
312
- tmp.push(this.options[optionIndex]);
313
- }
314
- });
315
- this.dataListCursorIndex = ci;
316
- this.optionsSelected = tmp;
317
- },
318
- exportModel() {
319
- let model = this.optionsSelected.map(option =>
320
- this.valueObjects ? option : this.getOptionValue(option)
321
- );
322
- if (this.multiple) {
323
- return model;
324
- }
325
- return model && model.length ? model[0] : null;
326
- },
327
- triggerModelChange() {
328
- let value = this.exportModel();
329
- /**
330
- * Input event
331
- * @property {any} value
332
- */
333
- this.$emit('input', value);
334
- /**
335
- * Change event
336
- * @property {any} model
337
- * @property {Array} meta
338
- */
339
- this.$emit('change', value);
340
- },
341
- getOptionLabel(option) {
342
- let label = option ? option[this.labelField] : null;
343
- return label == null ? option : label;
344
- },
345
- getOptionValue(option) {
346
- let value = option ? option[this.valueField] : null;
347
- // @NOTE option.value might be 'null'
348
- return value === undefined ? option : value;
349
- },
350
- getOptionIndex(option) {
351
- return this.options.findIndex(
352
- o => this.getOptionValue(o) === this.getOptionValue(option)
353
- );
354
- },
355
- isOptionSelected(option) {
356
- return !!this.optionsSelected.find(
357
- o => this.getOptionValue(o) === this.getOptionValue(option)
358
- );
359
- },
360
- selectOption(option) {
361
- if (this.isOptionSelected(option)) {
362
- return;
363
- }
364
- if (this.multiple) {
365
- this.optionsSelected.push(option);
366
- } else {
367
- this.optionsSelected = [option];
368
- this.popoverShow = false;
369
- }
370
- this.triggerModelChange();
371
- },
372
- deselectOption(option) {
373
- if (!this.multiple) {
374
- this.popoverShow = false;
375
- return;
376
- }
377
- this.optionsSelected = this.optionsSelected.filter(
378
- o => this.getOptionValue(o) !== this.getOptionValue(option)
379
- );
380
- this.triggerModelChange();
381
- },
382
- toggleOption(option) {
383
- if (!this.isOptionSelected(option)) {
384
- this.selectOption(option);
385
- } else {
386
- this.deselectOption(option);
387
- }
388
- },
389
- getDatalistRef() {
390
- return this.$refs.datalist;
391
- },
392
- onClick(e) {
393
- this.togglePopover();
394
- this.rootHasFocus = true;
395
- this.$el.focus();
396
- if (this.popoverShow && this.optionsSelected.length) {
397
- this.dataListCursorIndex = this.getOptionIndex(this.optionsSelected[0]);
398
- }
399
- },
400
- onDatalistSelectOption({ option }) {
401
- this.toggleOption(option);
402
- },
403
- onKeyDown(e) {
404
- let list = this.getDatalistRef();
405
- if (e.key === Key.ESC) {
406
- this.popoverShow = false;
407
- return;
408
- }
409
- if (e.key === Key.ENTER) {
410
- if (!this.popoverShow) {
411
- this.popoverShow = true;
412
- }
413
- }
414
- if (this.popoverShow) {
415
- list && list.onKeyDown(e);
416
- }
417
- },
418
- },
419
- };
420
- </script>
1
+ <template>
2
+ <div
3
+ class="ui-select form-elem"
4
+ :class="cssClassExt"
5
+ @keydown.prevent="onKeyDown"
6
+ @click="onClick"
7
+ tabindex="0"
8
+ :data-popover="popoverTargetId"
9
+ >
10
+ <div class="ui-select-label u-select-none">
11
+ <template v-if="multiple">
12
+ <template v-if="optionsSelected.length">
13
+ <!--
14
+ @slot Label slot for multiple mode
15
+ @binding {Object} option option
16
+ @binding {any} value option's value
17
+ @binding {String} label option's label
18
+ @binding {Function} deselectOption deselects option function(option:Object)
19
+ -->
20
+ <slot
21
+ name="label-multiple"
22
+ v-for="(option, index) in optionsSelected"
23
+ v-bind="{
24
+ option,
25
+ value: getOptionValue(option),
26
+ label: getOptionLabel(option),
27
+ deselectOption,
28
+ }"
29
+ >
30
+ <ui-badge
31
+ class="mar-none mar-right-2"
32
+ theme="primary"
33
+ size="small"
34
+ :key="index"
35
+ removable
36
+ @click.native.stop
37
+ @remove="deselectOption(option)"
38
+ >
39
+ <span>{{ getOptionLabel(option) }}</span>
40
+ </ui-badge>
41
+ </slot>
42
+ </template>
43
+ <div class="ui-select-placeholder events-none" v-else>
44
+ <!--
45
+ @slot Placeholder slot
46
+ -->
47
+ <slot name="placeholder">
48
+ <input class="w-100" :placeholder="placeholder" />
49
+ </slot>
50
+ </div>
51
+ </template>
52
+
53
+ <template v-else>
54
+ <!--
55
+ @slot Label slot for single mode
56
+ @binding {Object} option option
57
+ @binding {any} value option's value
58
+ @binding {String} label option's label
59
+ -->
60
+ <slot
61
+ name="label"
62
+ v-bind="{
63
+ option: optionsSelected[0],
64
+ value: getOptionValue(optionsSelected[0]),
65
+ label: getOptionLabel(optionsSelected[0]),
66
+ }"
67
+ v-if="optionsSelected.length"
68
+ >
69
+ {{ getOptionLabel(optionsSelected[0]) }}
70
+ </slot>
71
+ <div class="ui-select-placeholder events-none" v-else>
72
+ <!--
73
+ @slot Placeholder slot
74
+ -->
75
+ <slot name="placeholder">
76
+ <input class="w-100" :placeholder="placeholder" />
77
+ </slot>
78
+ </div>
79
+ </template>
80
+ </div>
81
+ <!--
82
+ @slot Open state icon slot
83
+ -->
84
+ <slot name="icon-open" v-if="popoverShow">
85
+ <div class="icon w-auto h-auto mar-left-2 events-none">
86
+ <i class="mdi mdi-chevron-up"></i>
87
+ </div>
88
+ </slot>
89
+ <!--
90
+ @slot Close state icon slot
91
+ -->
92
+ <slot name="icon-close" v-else>
93
+ <div class="icon w-auto h-auto mar-left-2 events-none">
94
+ <i class="mdi mdi-chevron-down"></i>
95
+ </div>
96
+ </slot>
97
+
98
+ <ui-popover :show.sync="popoverShow" v-bind="popoverOptions">
99
+ <ui-datalist
100
+ class="w-100 pull-left"
101
+ @click.native.stop
102
+ @select-option="onDatalistSelectOption"
103
+ v-bind="{ size, options }"
104
+ :cursorIndex.sync="dataListCursorIndex"
105
+ ref="datalist"
106
+ >
107
+ <template #header>
108
+ <!--
109
+ @slot Dropdown header slot
110
+ -->
111
+ <slot name="dropdown-header"></slot>
112
+ </template>
113
+ <template #option="{ option, index, cursorIndex }">
114
+ <!--
115
+ @slot Label slot for single mode
116
+ @binding {Object} option option
117
+ @binding {any} value option's value
118
+ @binding {String} label option's label
119
+ @binding {Number} index option's index
120
+ @binding {Boolean} isSelected option selection status
121
+ @binding {Number} cursorIndex current cursor index
122
+ @binding {Function} selectOption function that selects option
123
+ @binding {Function} deselectOption function that deselects option
124
+ @binding {Function} toggleOption function that toggles option selection
125
+ @binding {Number} optionIndex option's index
126
+ @binding {Boolean} isOptionSelected option selection status
127
+ -->
128
+ <slot
129
+ name="option"
130
+ v-bind="{
131
+ option,
132
+ value: getOptionValue(option),
133
+ label: getOptionLabel(option),
134
+ index,
135
+ isSelected: isOptionSelected(option),
136
+ cursorIndex,
137
+ selectOption,
138
+ deselectOption,
139
+ toggleOption,
140
+ // legacy
141
+ optionIndex: index,
142
+ isOptionSelected: isOptionSelected(option),
143
+ }"
144
+ >
145
+ <li
146
+ :class="{
147
+ active: isOptionSelected(option),
148
+ 'bg-grey-lighter': index == cursorIndex,
149
+ }"
150
+ :key="index"
151
+ @click="toggleOption(option)"
152
+ >
153
+ <div class="row row-collapse" v-if="multiple">
154
+ <div class="col col-vmid text-truncate">
155
+ <div
156
+ class="text-truncate"
157
+ style="min-height: calc(var(--line-height)*1em)"
158
+ >
159
+ {{ getOptionLabel(option) }}
160
+ </div>
161
+ </div>
162
+ <div class="col col-auto col-vmid" v-if="isOptionSelected(option)">
163
+ <i class="mdi mdi-check" style="line-height:1"></i>
164
+ </div>
165
+ </div>
166
+ <div
167
+ class="text-truncate"
168
+ style="min-height: calc(var(--line-height)*1rem)"
169
+ v-else
170
+ >
171
+ {{ getOptionLabel(option) }}
172
+ </div>
173
+ </li>
174
+ </slot>
175
+ </template>
176
+ <template #footer>
177
+ <!--
178
+ @slot Dropdown footer slot
179
+ -->
180
+ <slot name="dropdown-footer"></slot>
181
+ </template>
182
+ </ui-datalist>
183
+ </ui-popover>
184
+ </div>
185
+ </template>
186
+ <style lang="less" scoped>
187
+ .ui-select {
188
+ display: inline-flex;
189
+ align-items: center;
190
+ &-label {
191
+ white-space: nowrap;
192
+ text-overflow: ellipsis;
193
+ overflow: hidden;
194
+ flex: 1 0 0;
195
+ }
196
+ &-placeholder {
197
+ input {
198
+ border: none;
199
+ margin: 0;
200
+ padding: 0;
201
+ color: inherit;
202
+ background: transparent;
203
+ }
204
+ }
205
+ }
206
+ </style>
207
+ <script>
208
+ import UiBadge from './Badge.vue';
209
+ import UiDatalist from './Datalist.vue';
210
+ import UiPopover from './Popover.vue';
211
+ import FormComponent from './utils/FormComponent';
212
+ import WithPopover from './utils/WithPopover';
213
+ import { Key } from './utils/Helpers';
214
+
215
+ export default {
216
+ components: {
217
+ UiBadge,
218
+ UiDatalist,
219
+ UiPopover,
220
+ },
221
+ mixins: [FormComponent, WithPopover],
222
+ props: {
223
+ /**
224
+ * @model
225
+ */
226
+ value: {
227
+ default() {
228
+ return null;
229
+ },
230
+ },
231
+ /**
232
+ * Options. Array of Objects (option objects)
233
+ */
234
+ options: {
235
+ type: Array,
236
+ default() {
237
+ return [];
238
+ },
239
+ },
240
+ /**
241
+ * Allow multiple selection
242
+ */
243
+ multiple: {
244
+ type: Boolean,
245
+ default: false,
246
+ },
247
+ /**
248
+ * Defines whether 'value' is the option value field or option object
249
+ * @see options
250
+ */
251
+ valueObjects: {
252
+ type: Boolean,
253
+ default: false,
254
+ },
255
+ /**
256
+ * Defines the 'value' field of the option Object
257
+ */
258
+ valueField: {
259
+ type: String,
260
+ default: 'value',
261
+ },
262
+ /**
263
+ * Defines the 'label' field of the option Object
264
+ */
265
+ labelField: {
266
+ type: String,
267
+ default: 'label',
268
+ },
269
+ autoWidth: {
270
+ default: true,
271
+ },
272
+ },
273
+ data() {
274
+ return {
275
+ optionsSelected: [],
276
+ dataListCursorIndex: -1,
277
+ };
278
+ },
279
+ computed: {
280
+ /**
281
+ * @return {object}
282
+ */
283
+ cssClassExt() {
284
+ let obj = { 'u-select-none': this.readonly };
285
+ return { ...this.cssClass, ...obj };
286
+ },
287
+ },
288
+ watch: {
289
+ value: {
290
+ handler(model) {
291
+ this.importModel(model);
292
+ },
293
+ immediate: true,
294
+ },
295
+ options() {
296
+ this.importModel(this.value);
297
+ },
298
+ },
299
+ methods: {
300
+ importModel(model) {
301
+ let ci = -1;
302
+ let tmp = [];
303
+ model = this.multiple ? (Array.isArray(model) ? model : [model]) : [model];
304
+ model.forEach(modelItem => {
305
+ let modelItemValue = this.valueObjects ? this.getOptionValue(modelItem) : modelItem;
306
+ let optionIndex = this.options.findIndex(optionItem => {
307
+ let optionItemValue = this.getOptionValue(optionItem);
308
+ return optionItemValue === modelItemValue;
309
+ });
310
+ if (optionIndex >= 0) {
311
+ ci = ci < 0 ? optionIndex : ci;
312
+ tmp.push(this.options[optionIndex]);
313
+ }
314
+ });
315
+ this.dataListCursorIndex = ci;
316
+ this.optionsSelected = tmp;
317
+ },
318
+ exportModel() {
319
+ let model = this.optionsSelected.map(option =>
320
+ this.valueObjects ? option : this.getOptionValue(option)
321
+ );
322
+ if (this.multiple) {
323
+ return model;
324
+ }
325
+ return model && model.length ? model[0] : null;
326
+ },
327
+ triggerModelChange() {
328
+ let value = this.exportModel();
329
+ /**
330
+ * Input event
331
+ * @property {any} value
332
+ */
333
+ this.$emit('input', value);
334
+ /**
335
+ * Change event
336
+ * @property {any} model
337
+ * @property {Array} meta
338
+ */
339
+ this.$emit('change', value);
340
+ },
341
+ getOptionLabel(option) {
342
+ let label = option ? option[this.labelField] : null;
343
+ return label == null ? option : label;
344
+ },
345
+ getOptionValue(option) {
346
+ let value = option ? option[this.valueField] : null;
347
+ // @NOTE option.value might be 'null'
348
+ return value === undefined ? option : value;
349
+ },
350
+ getOptionIndex(option) {
351
+ return this.options.findIndex(
352
+ o => this.getOptionValue(o) === this.getOptionValue(option)
353
+ );
354
+ },
355
+ isOptionSelected(option) {
356
+ return !!this.optionsSelected.find(
357
+ o => this.getOptionValue(o) === this.getOptionValue(option)
358
+ );
359
+ },
360
+ selectOption(option) {
361
+ if (this.isOptionSelected(option)) {
362
+ return;
363
+ }
364
+ if (this.multiple) {
365
+ this.optionsSelected.push(option);
366
+ } else {
367
+ this.optionsSelected = [option];
368
+ this.popoverShow = false;
369
+ }
370
+ this.triggerModelChange();
371
+ },
372
+ deselectOption(option) {
373
+ if (!this.multiple) {
374
+ this.popoverShow = false;
375
+ return;
376
+ }
377
+ this.optionsSelected = this.optionsSelected.filter(
378
+ o => this.getOptionValue(o) !== this.getOptionValue(option)
379
+ );
380
+ this.triggerModelChange();
381
+ },
382
+ toggleOption(option) {
383
+ if (!this.isOptionSelected(option)) {
384
+ this.selectOption(option);
385
+ } else {
386
+ this.deselectOption(option);
387
+ }
388
+ },
389
+ getDatalistRef() {
390
+ return this.$refs.datalist;
391
+ },
392
+ onClick(e) {
393
+ this.togglePopover();
394
+ this.rootHasFocus = true;
395
+ this.$el.focus();
396
+ if (this.popoverShow && this.optionsSelected.length) {
397
+ this.dataListCursorIndex = this.getOptionIndex(this.optionsSelected[0]);
398
+ }
399
+ },
400
+ onDatalistSelectOption({ option }) {
401
+ this.toggleOption(option);
402
+ },
403
+ onKeyDown(e) {
404
+ let list = this.getDatalistRef();
405
+ if (e.key === Key.ESC) {
406
+ this.popoverShow = false;
407
+ return;
408
+ }
409
+ if (e.key === Key.ENTER) {
410
+ if (!this.popoverShow) {
411
+ this.popoverShow = true;
412
+ }
413
+ }
414
+ if (this.popoverShow) {
415
+ list && list.onKeyDown(e);
416
+ }
417
+ },
418
+ },
419
+ };
420
+ </script>