@citizenplane/pimp 6.4.1 → 8.0.0

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 (77) hide show
  1. package/.eslintrc.js +3 -6
  2. package/.lintstagedrc.json +4 -0
  3. package/README.md +18 -6
  4. package/dist/favicon.ico +0 -0
  5. package/dist/pimp.es.js +10635 -0
  6. package/dist/pimp.umd.js +9 -35597
  7. package/dist/style.css +1 -0
  8. package/jest.config.js +11 -11
  9. package/package-lock.json +7787 -13517
  10. package/package.json +38 -42
  11. package/src/App.vue +12 -17
  12. package/src/README.md +23 -9
  13. package/src/assets/styles/base/_base.scss +3 -16
  14. package/src/assets/styles/helpers/_functions.scss +1 -1
  15. package/src/assets/styles/helpers/_keyframes.scss +26 -29
  16. package/src/assets/styles/lib/_normalize.scss +19 -17
  17. package/src/assets/styles/variables/_colors.scss +16 -16
  18. package/src/assets/styles/variables/_sizing.scss +1 -1
  19. package/src/assets/styles/variables/_spacing.scss +2 -2
  20. package/src/components/atomic-elements/CpBadge.vue +41 -29
  21. package/src/components/buttons/CpButton.vue +10 -6
  22. package/src/components/core/playground-sections/SectionAtomicElements.vue +21 -5
  23. package/src/components/core/playground-sections/SectionButtons.vue +14 -11
  24. package/src/components/core/playground-sections/SectionDatePickers.vue +31 -17
  25. package/src/components/core/playground-sections/SectionFeedbackIndicators.vue +1 -1
  26. package/src/components/core/playground-sections/SectionInputs.vue +3 -3
  27. package/src/components/core/playground-sections/SectionListsAndTables.vue +2 -2
  28. package/src/components/core/playground-sections/SectionSelectMenus.vue +13 -13
  29. package/src/components/core/playground-sections/SectionSelects.vue +1 -1
  30. package/src/components/core/playground-sections/SectionSimpleInputs.vue +20 -18
  31. package/src/components/core/playground-sections/SectionToasters.vue +1 -1
  32. package/src/components/core/playground-sections/SectionToggles.vue +23 -36
  33. package/src/components/core/playground-sections/SectionTypography.vue +1 -1
  34. package/src/components/date-pickers/CpCalendar.vue +60 -14
  35. package/src/components/date-pickers/CpDate.vue +11 -13
  36. package/src/components/date-pickers/CpDatepicker.vue +55 -8
  37. package/src/components/feedback-indicators/CpAlert.vue +5 -15
  38. package/src/components/feedback-indicators/CpToaster.vue +299 -86
  39. package/src/components/helpers-utilities/TransitionExpand.vue +52 -58
  40. package/src/components/index.js +38 -73
  41. package/src/components/inputs/CpInput.vue +19 -54
  42. package/src/components/inputs/CpTextarea.vue +8 -9
  43. package/src/components/lists-and-table/CpTable/CpTableEmptyState/index.vue +1 -6
  44. package/src/components/lists-and-table/CpTable/index.scss +16 -9
  45. package/src/components/lists-and-table/CpTable/index.vue +6 -5
  46. package/src/components/selects/CpSelect.vue +10 -11
  47. package/src/components/selects/CpSelectMenu/index.vue +13 -23
  48. package/src/components/toggles/CpCheckbox/index.scss +9 -6
  49. package/src/components/toggles/CpCheckbox/index.vue +3 -7
  50. package/src/components/toggles/CpRadio/index.scss +12 -5
  51. package/src/components/toggles/CpRadio/index.vue +34 -47
  52. package/src/components/toggles/CpSwitch/index.vue +18 -17
  53. package/src/components/typography/CpHeading/index.vue +2 -2
  54. package/src/components/visual/CpIcon.vue +156 -0
  55. package/src/directives/ClickOutside.js +13 -0
  56. package/src/directives/ResizeSelect.js +1 -1
  57. package/src/libs/CoreDatepicker.vue +127 -133
  58. package/src/main.js +16 -10
  59. package/src/plugins/toaster.js +69 -0
  60. package/src/utils/constants/src/Intent.js +4 -4
  61. package/vite.config.js +45 -0
  62. package/dist/demo.html +0 -10
  63. package/dist/img/chevron-down-icon.dd31db33.svg +0 -3
  64. package/dist/pimp.common.js +0 -35587
  65. package/dist/pimp.common.js.map +0 -1
  66. package/dist/pimp.css +0 -1
  67. package/dist/pimp.umd.js.map +0 -1
  68. package/dist/pimp.umd.min.js +0 -2
  69. package/dist/pimp.umd.min.js.map +0 -1
  70. package/public/index.html +0 -17
  71. package/src/components/core/playground-sections/SectionMultiSelects.vue +0 -57
  72. package/src/components/selects/CpMultiselect.vue +0 -211
  73. package/src/helpers/multiselectMixin.js +0 -765
  74. package/src/helpers/pointerMixin.js +0 -135
  75. package/src/libs/CoreMultiSelect.vue +0 -618
  76. package/src/libs/CoreToaster.vue +0 -269
  77. package/vue.config.js +0 -20
@@ -1,765 +0,0 @@
1
- function isEmpty(opt) {
2
- if (opt === 0) return false
3
- if (Array.isArray(opt) && opt.length === 0) return true
4
- return !opt
5
- }
6
-
7
- function not(fun) {
8
- return (...params) => !fun(...params)
9
- }
10
-
11
- function includes(str, query) {
12
- /* istanbul ignore else */
13
- if (str === undefined) str = 'undefined'
14
- if (str === null) str = 'null'
15
- if (str === false) str = 'false'
16
- const text = str.toString().toLowerCase()
17
- return text.includes(query.trim())
18
- }
19
-
20
- function filterOptions(options, search, label, customLabel) {
21
- return options.filter((option) => includes(customLabel(option, label), search))
22
- }
23
-
24
- function stripGroups(options) {
25
- return options.filter((option) => !option.$isLabel)
26
- }
27
-
28
- function flattenOptions(values, label, value) {
29
- return (options) => {
30
- return options.reduce((prev, curr) => {
31
- /* istanbul ignore else */
32
- if (curr[values] && curr[values].length) {
33
- prev.push({
34
- $groupLabel: curr.group[label],
35
- $groupValue: curr.group[value],
36
- $isLabel: true,
37
- })
38
- return prev.concat(curr[values])
39
- }
40
- return prev
41
- }, [])
42
- }
43
- }
44
-
45
- function filterGroups(search, label, values, groupLabel, customLabel) {
46
- return (groups) =>
47
- groups.map((group) => {
48
- /* istanbul ignore else */
49
- /* eslint no-console: ["error", { allow: ["warn", "error"] }] */
50
- if (!group[values]) {
51
- console.warn(`Options passed to vue-multiselect do not contain groups, despite the config.`)
52
- return []
53
- }
54
- const groupOptions = filterOptions(group[values], search, label, customLabel)
55
-
56
- return groupOptions.length
57
- ? {
58
- [groupLabel]: group[groupLabel],
59
- [values]: groupOptions,
60
- }
61
- : []
62
- })
63
- }
64
-
65
- const flow =
66
- (...fns) =>
67
- (x) =>
68
- fns.reduce((v, f) => f(v), x)
69
-
70
- export default {
71
- data() {
72
- return {
73
- search: '',
74
- isOpen: false,
75
- preferredOpenDirection: 'below',
76
- optimizedHeight: this.maxHeight,
77
- }
78
- },
79
- props: {
80
- /**
81
- * Decide whether to filter the results based on search query.
82
- * Useful for async filtering, where we search through more complex data.
83
- * @type {Boolean}
84
- */
85
- internalSearch: {
86
- type: Boolean,
87
- default: false,
88
- },
89
- /**
90
- * Array of available options: Objects, Strings or Integers.
91
- * If array of objects, visible label will default to option.label.
92
- * If `labal` prop is passed, label will equal option['label']
93
- * @type {Array}
94
- */
95
- options: {
96
- type: Array,
97
- required: true,
98
- },
99
- /**
100
- * Equivalent to the `multiple` attribute on a `<select>` input.
101
- * @default false
102
- * @type {Boolean}
103
- */
104
- multiple: {
105
- type: Boolean,
106
- default: false,
107
- },
108
- /**
109
- * Presets the selected options value.
110
- * @type {Object||Array||String||Integer}
111
- */
112
- value: {
113
- type: null,
114
- default() {
115
- return []
116
- },
117
- },
118
- /**
119
- * Key to compare objects
120
- * @default 'id'
121
- * @type {String}
122
- */
123
- trackBy: {
124
- type: String,
125
- },
126
- /**
127
- * Label to look for in option Object
128
- * @default 'label'
129
- * @type {String}
130
- */
131
- label: {
132
- type: String,
133
- },
134
- /**
135
- * Enable/disable search in options
136
- * @default true
137
- * @type {Boolean}
138
- */
139
- searchable: {
140
- type: Boolean,
141
- default: true,
142
- },
143
- /**
144
- * Clear the search input after `)
145
- * @default true
146
- * @type {Boolean}
147
- */
148
- clearOnSelect: {
149
- type: Boolean,
150
- default: true,
151
- },
152
- /**
153
- * Hide already selected options
154
- * @default false
155
- * @type {Boolean}
156
- */
157
- hideSelected: {
158
- type: Boolean,
159
- default: false,
160
- },
161
- /**
162
- * Equivalent to the `placeholder` attribute on a `<select>` input.
163
- * @default 'Select option'
164
- * @type {String}
165
- */
166
- placeholder: {
167
- type: String,
168
- default: 'Select option',
169
- },
170
- /**
171
- * Allow to remove all selected values
172
- * @default true
173
- * @type {Boolean}
174
- */
175
- allowEmpty: {
176
- type: Boolean,
177
- default: true,
178
- },
179
- /**
180
- * Reset this.internalValue, this.search after this.internalValue changes.
181
- * Useful if want to create a stateless dropdown.
182
- * @default false
183
- * @type {Boolean}
184
- */
185
- resetAfter: {
186
- type: Boolean,
187
- default: false,
188
- },
189
- /**
190
- * Enable/disable closing after selecting an option
191
- * @default true
192
- * @type {Boolean}
193
- */
194
- closeOnSelect: {
195
- type: Boolean,
196
- default: true,
197
- },
198
- /**
199
- * Function to interpolate the custom label
200
- * @default false
201
- * @type {Function}
202
- */
203
- customLabel: {
204
- type: Function,
205
- default(option, label) {
206
- if (isEmpty(option)) return ''
207
- return label ? option[label] : option
208
- },
209
- },
210
- /**
211
- * Disable / Enable tagging
212
- * @default false
213
- * @type {Boolean}
214
- */
215
- taggable: {
216
- type: Boolean,
217
- default: false,
218
- },
219
- /**
220
- * String to show when highlighting a potential tag
221
- * @default 'Press enter to create a tag'
222
- * @type {String}
223
- */
224
- tagPlaceholder: {
225
- type: String,
226
- default: 'Press enter to create a tag',
227
- },
228
- /**
229
- * By default new tags will appear above the search results.
230
- * Changing to 'bottom' will revert this behaviour
231
- * and will proritize the search results
232
- * @default 'top'
233
- * @type {String}
234
- */
235
- tagPosition: {
236
- type: String,
237
- default: 'top',
238
- },
239
- /**
240
- * Number of allowed selected options. No limit if 0.
241
- * @default 0
242
- * @type {Number}
243
- */
244
- max: {
245
- type: [Number, Boolean],
246
- default: false,
247
- },
248
- /**
249
- * Will be passed with all events as second param.
250
- * Useful for identifying events origin.
251
- * @default null
252
- * @type {String|Integer}
253
- */
254
- id: {
255
- default: null,
256
- },
257
- /**
258
- * Limits the options displayed in the dropdown
259
- * to the first X options.
260
- * @default 1000
261
- * @type {Integer}
262
- */
263
- optionsLimit: {
264
- type: Number,
265
- default: 1000,
266
- },
267
- /**
268
- * Name of the property containing
269
- * the group values
270
- * @type {String}
271
- */
272
- groupValues: {
273
- type: String,
274
- },
275
- /**
276
- * Name of the property containing
277
- * the key group value
278
- * @type {String}
279
- */
280
- groupValue: {
281
- type: String,
282
- },
283
- /**
284
- * Name of the property containing
285
- * the group label
286
- * @type {String}
287
- */
288
- groupLabel: {
289
- type: String,
290
- },
291
- /**
292
- * Allow to select all group values
293
- * by selecting the group label
294
- * @default false
295
- * @type {Boolean}
296
- */
297
- groupSelect: {
298
- type: Boolean,
299
- default: false,
300
- },
301
- /**
302
- * Allow to select only group values
303
- * by selecting the group label
304
- * @default false
305
- * @type {Boolean}
306
- */
307
- groupSelectUnique: {
308
- type: Boolean,
309
- default: false,
310
- },
311
- /**
312
- * Array of keyboard keys to block
313
- * when selecting
314
- * @default 1000
315
- * @type {String}
316
- */
317
- blockKeys: {
318
- type: Array,
319
- default() {
320
- return []
321
- },
322
- },
323
- /**
324
- * Prevent from wiping up the search value
325
- * @default false
326
- * @type {Boolean}
327
- */
328
- preserveSearch: {
329
- type: Boolean,
330
- default: false,
331
- },
332
- /**
333
- * Select 1st options if value is empty
334
- * @default false
335
- * @type {Boolean}
336
- */
337
- preselectFirst: {
338
- type: Boolean,
339
- default: false,
340
- },
341
- /**
342
- * Select only group of group and childrens
343
- * @default false
344
- * @type {Boolean}
345
- */
346
- groupUniqueSelect: {
347
- type: Boolean,
348
- default: false,
349
- },
350
- },
351
- mounted() {
352
- /* istanbul ignore else */
353
- if (!this.multiple && this.max) {
354
- console.warn('[Vue-Multiselect warn]: Max prop should not be used when prop Multiple equals false.')
355
- }
356
- if (this.preselectFirst && !this.internalValue.length && this.options.length) {
357
- this.select(this.filteredOptions[0])
358
- }
359
- },
360
- computed: {
361
- internalValue() {
362
- return this.value || this.value === 0 ? (Array.isArray(this.value) ? this.value : [this.value]) : []
363
- },
364
- filteredOptions() {
365
- const search = this.search || ''
366
- const normalizedSearch = search.toLowerCase().trim()
367
-
368
- let options = this.options.concat()
369
-
370
- /* istanbul ignore else */
371
- if (this.internalSearch) {
372
- options = this.groupValues
373
- ? this.filterAndFlat(options, normalizedSearch, this.label)
374
- : filterOptions(options, normalizedSearch, this.label, this.customLabel)
375
- } else {
376
- options = this.groupValues
377
- ? flattenOptions(this.groupValues, this.groupLabel, this.groupValue)(options)
378
- : options
379
- }
380
-
381
- options = this.hideSelected ? options.filter(not(this.isSelected)) : options
382
-
383
- /* istanbul ignore else */
384
- if (this.taggable && normalizedSearch.length && !this.isExistingOption(normalizedSearch)) {
385
- if (this.tagPosition === 'bottom') {
386
- options.push({ isTag: true, label: search })
387
- } else {
388
- options.unshift({ isTag: true, label: search })
389
- }
390
- }
391
-
392
- return options.slice(0, this.optionsLimit)
393
- },
394
- valueKeys() {
395
- if (this.trackBy) {
396
- return this.internalValue.map((element) => element[this.trackBy])
397
- } else {
398
- return this.internalValue
399
- }
400
- },
401
- optionKeys() {
402
- const options = this.groupValues ? this.flatAndStrip(this.options) : this.options
403
- return options.map((element) => this.customLabel(element, this.label).toString().toLowerCase())
404
- },
405
- currentOptionLabel() {
406
- if (!this.multiple && this.internalValue.length > 1) {
407
- let label = ''
408
- this.internalValue.forEach((item, index) => {
409
- if (index !== 0) label += ', ' + item.label
410
- else label += item.label
411
- })
412
- return label
413
- }
414
-
415
- if (this.internalValue.length) {
416
- return this.multiple ? (this.searchable ? '' : this.placeholder) : this.getOptionLabel(this.internalValue[0])
417
- } else {
418
- return this.multiple ? (this.searchable ? '' : this.placeholder) : this.searchable ? '' : this.placeholder
419
- }
420
- },
421
- },
422
- watch: {
423
- internalValue() {
424
- /* istanbul ignore else */
425
- if (this.resetAfter && this.internalValue.length) {
426
- this.search = ''
427
- this.$emit('input', this.multiple ? [] : null)
428
- }
429
- },
430
- search() {
431
- this.$emit('search-change', this.search, this.id)
432
- },
433
- },
434
- methods: {
435
- /**
436
- * Returns the internalValue in a way it can be emited to the parent
437
- * @returns {Object||Array||String||Integer}
438
- */
439
- getValue() {
440
- return this.multiple ? this.internalValue : this.internalValue.length === 0 ? null : this.internalValue[0]
441
- },
442
- /**
443
- * Filters and then flattens the options list
444
- * @returns {Array} returns a filtered and flat options list
445
- * @param options
446
- * @param search
447
- * @param label
448
- */
449
- filterAndFlat(options, search, label) {
450
- return flow(
451
- filterGroups(search, label, this.groupValues, this.groupLabel, this.customLabel),
452
- flattenOptions(this.groupValues, this.groupLabel, this.groupValue),
453
- )(options)
454
- },
455
- /**
456
- * Flattens and then strips the group labels from the options list
457
- * @returns {Array} returns a flat options list without group labels
458
- * @param options
459
- */
460
- flatAndStrip(options) {
461
- return flow(flattenOptions(this.groupValues, this.groupLabel, this.groupValue), stripGroups)(options)
462
- },
463
- /**
464
- * Updates the search value
465
- * @param query
466
- */
467
- updateSearch(query) {
468
- this.search = query
469
- },
470
- /**
471
- * Finds out if the given query is already present
472
- * in the available options
473
- * @returns {Boolean} returns true if element is available
474
- * @param query
475
- */
476
- isExistingOption(query) {
477
- return !this.options ? false : this.optionKeys.includes(query)
478
- },
479
- /**
480
- * Finds out if the given element is already present
481
- * in the result value
482
- * @param {Object||String||Integer} option passed element to check
483
- * @returns {Boolean} returns true if element is selected
484
- */
485
- isSelected(option) {
486
- const opt = this.trackBy ? option[this.trackBy] : option
487
- return this.valueKeys.includes(opt)
488
- },
489
- /**
490
- * Finds out if the given option is disabled
491
- * @param {Object||String||Integer} option passed element to check
492
- * @returns {Boolean} returns true if element is disabled
493
- */
494
- isOptionDisabled(option) {
495
- return !!option.$isDisabled
496
- },
497
- /**
498
- * Returns empty string when options is null/undefined
499
- * Returns tag query if option is tag.
500
- * Returns the customLabel() results and casts it to string.
501
- *
502
- * @returns {Object||String}
503
- * @param option
504
- */
505
- getOptionLabel(option) {
506
- if (isEmpty(option)) return ''
507
- /* istanbul ignore else */
508
- if (option.isTag) return option.label
509
- /* istanbul ignore else */
510
- if (option.$isLabel) return option.$groupLabel
511
-
512
- const label = this.customLabel(option, this.label)
513
- /* istanbul ignore else */
514
- if (isEmpty(label)) return ''
515
- return label
516
- },
517
- /**
518
- * Add the given option to the list of selected options
519
- * or sets the option as the selected option.
520
- * If option is already selected -> remove it from the results.
521
- *
522
- * @param {Object||String||Integer} option to select/deselect
523
- * @param key
524
- */
525
- select(option, key) {
526
- /* istanbul ignore else */
527
- if (option.$isLabel && this.groupSelect) {
528
- this.selectGroup(option)
529
- return
530
- }
531
- if (this.blockKeys.includes(key) || this.disabled || option.$isDisabled || option.$isLabel) return
532
- /* istanbul ignore else */
533
- if (this.max && this.multiple && this.internalValue.length === this.max) return
534
- /* istanbul ignore else */
535
- if (key === 'Tab' && !this.pointerDirty) return
536
- if (option.isTag) {
537
- this.$emit('tag', option.label, this.id)
538
- this.search = ''
539
- if (this.closeOnSelect && !this.multiple) this.deactivate()
540
- } else {
541
- const isSelected = this.isSelected(option)
542
-
543
- if (isSelected) {
544
- if (key !== 'Tab') this.removeElement(option)
545
- return
546
- }
547
-
548
- this.$emit('select', option, this.id)
549
- this.$emit('input', this.multiple ? this.internalValue.concat([option]) : [option], this.id)
550
-
551
- /* istanbul ignore else */
552
- if (this.clearOnSelect) this.search = ''
553
- }
554
- /* istanbul ignore else */
555
- if (this.closeOnSelect) this.deactivate()
556
- },
557
- /**
558
- * Add the given group options to the list of selected options
559
- * If all group optiona are already selected -> remove it from the results.
560
- *
561
- * @param selectedGroup
562
- */
563
- selectGroup(selectedGroup) {
564
- const group = this.options.find((option) => {
565
- return option.group[this.groupLabel] === selectedGroup.$groupLabel
566
- })
567
- if (!group) return
568
-
569
- if (this.groupSelect && this.groupSelectUnique) {
570
- const newValue = {
571
- label: selectedGroup.$groupLabel,
572
- code: selectedGroup.$groupValue,
573
- }
574
- let valueToAdd = []
575
-
576
- if (!this.multiple) {
577
- valueToAdd = this.internalValue.length && this.internalValue[0].code === newValue.code ? [] : [newValue]
578
- } else {
579
- // if multiple, we find for the item, if existing, we remove it, else, we add it to the values
580
- valueToAdd = this.internalValue.find((item) => item.code === newValue.code)
581
- ? this.internalValue.filter((item) => item.code !== newValue.code)
582
- : this.internalValue.concat(newValue)
583
- }
584
- this.$emit('select', valueToAdd, this.id)
585
- this.$emit('input', valueToAdd, this.id)
586
- } else if (this.wholeGroupSelected(group)) {
587
- this.removeAllElementFromGroup(group)
588
- } else {
589
- const optionsToAdd = group[this.groupValues].filter(
590
- (option) => !(this.isOptionDisabled(option) || this.isSelected(option)),
591
- )
592
- let values = []
593
-
594
- // As multiple equal false, we are looking if the optionsToAdd have the same group as originaly selected or not, if yes we add to internalValue, else we replace
595
- if (this.groupSelect && !this.multiple && this.internalValue.length) {
596
- const found = this.options.some((option, index) =>
597
- option.items.some(
598
- (item) =>
599
- item.code === this.internalValue[0].code &&
600
- selectedGroup.$groupValue === this.options[index].group.code,
601
- ),
602
- )
603
-
604
- values = found === true ? this.internalValue.concat(optionsToAdd) : optionsToAdd
605
- } else {
606
- values = this.internalValue.concat(optionsToAdd)
607
- }
608
- this.$emit('select', values, this.id)
609
- this.$emit('input', values, this.id)
610
- }
611
- if (this.closeOnSelect) this.deactivate()
612
- },
613
- removeAllElementFromGroup(group) {
614
- this.$emit('remove', group[this.groupValues], this.id)
615
-
616
- const newValue = this.internalValue.filter((option) => !group[this.groupValues].includes(option))
617
-
618
- this.$emit('input', newValue, this.id)
619
- },
620
- /**
621
- * Helper to identify if all values in a group are selected
622
- *
623
- * @param {Object} group to validated selected values against
624
- */
625
- wholeGroupSelected(group) {
626
- return group[this.groupValues].every((option) => this.isSelected(option) || this.isOptionDisabled(option))
627
- },
628
- /**
629
- * Helper to identify if all values in a group are disabled
630
- *
631
- * @param {Object} group to check for disabled values
632
- */
633
- wholeGroupDisabled(group) {
634
- return group[this.groupValues].every(this.isOptionDisabled)
635
- },
636
- /**
637
- * Removes the given option from the selected options.
638
- * Additionally checks this.allowEmpty prop if option can be removed when
639
- * it is the last selected option.
640
- *
641
- * @param {type} option description
642
- * @param shouldClose
643
- * @returns {type} description
644
- */
645
- removeElement(option, shouldClose = true) {
646
- /* istanbul ignore else */
647
- if (this.disabled) return
648
- /* istanbul ignore else */
649
- if (option.$isDisabled) return
650
- /* istanbul ignore else */
651
- if (!this.allowEmpty && this.internalValue.length <= 1) {
652
- this.deactivate()
653
- return
654
- }
655
-
656
- const index =
657
- typeof option === 'object' ? this.valueKeys.indexOf(option[this.trackBy]) : this.valueKeys.indexOf(option)
658
-
659
- this.$emit('remove', option, this.id)
660
- if (this.multiple) {
661
- const newValue = this.internalValue.slice(0, index).concat(this.internalValue.slice(index + 1))
662
- this.$emit('input', newValue, this.id)
663
- } else {
664
- this.$emit('input', null, this.id)
665
- }
666
-
667
- /* istanbul ignore else */
668
- if (this.closeOnSelect && shouldClose) this.deactivate()
669
- },
670
- /**
671
- * Calls this.removeElement() with the last element
672
- * from this.internalValue (selected element Array)
673
- *
674
- * @fires this#removeElement
675
- */
676
- removeLastElement() {
677
- /* istanbul ignore else */
678
- if (this.blockKeys.includes('Delete')) return
679
- /* istanbul ignore else */
680
- if (this.search.length === 0 && Array.isArray(this.internalValue) && this.internalValue.length) {
681
- this.removeElement(this.internalValue[this.internalValue.length - 1], false)
682
- }
683
- },
684
- /**
685
- * Opens the multiselect’s dropdown.
686
- * Sets this.isOpen to TRUE
687
- */
688
- activate() {
689
- /* istanbul ignore else */
690
- if (this.isOpen || this.disabled) return
691
-
692
- this.adjustPosition()
693
- /* istanbul ignore else */
694
- if (this.groupValues && this.pointer === 0 && this.filteredOptions.length) {
695
- this.pointer = 1
696
- }
697
-
698
- this.isOpen = true
699
- /* istanbul ignore else */
700
- if (this.searchable) {
701
- if (!this.preserveSearch) this.search = ''
702
- this.$nextTick(() => this.$refs.search && this.$refs.search.focus())
703
- } else {
704
- this.$el.focus()
705
- }
706
- this.$emit('open', this.id)
707
- },
708
- /**
709
- * Closes the multiselect’s dropdown.
710
- * Sets this.isOpen to FALSE
711
- */
712
- deactivate() {
713
- /* istanbul ignore else */
714
- if (!this.isOpen) return
715
-
716
- this.isOpen = false
717
- /* istanbul ignore else */
718
- if (this.searchable) {
719
- this.$refs.search && this.$refs.search.blur()
720
- } else {
721
- this.$el.blur()
722
- }
723
- if (!this.preserveSearch) this.search = ''
724
- this.$emit('close', this.getValue(), this.id)
725
- },
726
- /**
727
- * Call this.activate() or this.deactivate()
728
- * depending on this.isOpen value.
729
- *
730
- * @fires this#activate || this#deactivate
731
- * @property {Boolean} isOpen indicates if dropdown is open
732
- */
733
- toggle() {
734
- this.isOpen ? this.deactivate() : this.activate()
735
- },
736
- /**
737
- * Updates the hasEnoughSpace variable used for
738
- * detecting where to expand the dropdown
739
- */
740
- adjustPosition() {
741
- if (typeof window === 'undefined') return
742
-
743
- const spaceAbove = this.$el.getBoundingClientRect().top
744
- const spaceBelow = window.innerHeight - this.$el.getBoundingClientRect().bottom
745
- const hasEnoughSpaceBelow = spaceBelow > this.maxHeight
746
- const spaceWidth = window.innerWidth
747
-
748
- if (spaceWidth <= 768) {
749
- this.preferredOpenDirection = 'below'
750
- this.optimizedHeight = this.maxHeight
751
- } else if (
752
- hasEnoughSpaceBelow ||
753
- spaceBelow > spaceAbove ||
754
- this.openDirection === 'below' ||
755
- this.openDirection === 'bottom'
756
- ) {
757
- this.preferredOpenDirection = 'below'
758
- this.optimizedHeight = Math.min(spaceBelow - 40, this.maxHeight)
759
- } else {
760
- this.preferredOpenDirection = 'above'
761
- this.optimizedHeight = Math.min(spaceAbove - 40, this.maxHeight)
762
- }
763
- },
764
- },
765
- }