|
323 | 323 | </span>
|
324 | 324 | </slot>
|
325 | 325 |
|
326 |
| - <input |
327 |
| - ref="search" |
328 |
| - v-model="search" |
329 |
| - @keydown.delete="maybeDeleteValue" |
330 |
| - @keyup.esc="onEscape" |
331 |
| - @keydown.up.prevent="typeAheadUp" |
332 |
| - @keydown.down.prevent="typeAheadDown" |
333 |
| - @keydown.enter.prevent="typeAheadSelect" |
334 |
| - @keydown.tab="onTab" |
335 |
| - @blur="onSearchBlur" |
336 |
| - @focus="onSearchFocus" |
337 |
| - type="search" |
338 |
| - class="form-control" |
339 |
| - autocomplete="off" |
340 |
| - :disabled="disabled" |
341 |
| - :placeholder="searchPlaceholder" |
342 |
| - :tabindex="tabindex" |
343 |
| - :readonly="!searchable" |
344 |
| - :id="inputId" |
345 |
| - role="combobox" |
346 |
| - :aria-expanded="dropdownOpen" |
347 |
| - aria-label="Search for option" |
348 |
| - > |
| 326 | + <slot name="search" v-bind="scope.search"> |
| 327 | + <input v-bind="scope.search.attributes" v-on="scope.search.events"> |
| 328 | + </slot> |
349 | 329 |
|
350 | 330 | </div>
|
351 | 331 | <div class="vs__actions">
|
|
583 | 563 | },
|
584 | 564 |
|
585 | 565 | /**
|
586 |
| - * Enable/disable creating options from searchInput. |
| 566 | + * Enable/disable creating options from searchEl. |
587 | 567 | * @type {Boolean}
|
588 | 568 | */
|
589 | 569 | taggable: {
|
|
721 | 701 | selectOnTab: {
|
722 | 702 | type: Boolean,
|
723 | 703 | default: false
|
| 704 | + }, |
| 705 | +
|
| 706 | + /** |
| 707 | + * Query Selector used to find the search input |
| 708 | + * when the 'search' scoped slot is used. |
| 709 | + * @type {String} |
| 710 | + */ |
| 711 | + searchInputQuerySelector: { |
| 712 | + type: String, |
| 713 | + default: '[type=search]' |
724 | 714 | }
|
725 | 715 | },
|
726 | 716 |
|
|
871 | 861 | onAfterSelect(option) {
|
872 | 862 | if (this.closeOnSelect) {
|
873 | 863 | this.open = !this.open
|
874 |
| - this.$refs.search.blur() |
| 864 | + this.searchEl.blur() |
875 | 865 | }
|
876 | 866 |
|
877 | 867 | if (this.clearSearchOnSelect) {
|
|
885 | 875 | * @return {void}
|
886 | 876 | */
|
887 | 877 | toggleDropdown(e) {
|
888 |
| - if (e.target === this.$refs.openIndicator || e.target === this.$refs.search || e.target === this.$refs.toggle || |
| 878 | + if (e.target === this.$refs.openIndicator || e.target === this.searchEl || e.target === this.$refs.toggle || |
889 | 879 | e.target.classList.contains('selected-tag') || e.target === this.$el) {
|
890 | 880 | if (this.open) {
|
891 |
| - this.$refs.search.blur() // dropdown will close on blur |
| 881 | + this.searchEl.blur() // dropdown will close on blur |
892 | 882 | } else {
|
893 | 883 | if (!this.disabled) {
|
894 | 884 | this.open = true
|
895 |
| - this.$refs.search.focus() |
| 885 | + this.searchEl.focus() |
896 | 886 | }
|
897 | 887 | }
|
898 | 888 | }
|
|
957 | 947 | */
|
958 | 948 | onEscape() {
|
959 | 949 | if (!this.search.length) {
|
960 |
| - this.$refs.search.blur() |
| 950 | + this.searchEl.blur() |
961 | 951 | } else {
|
962 | 952 | this.search = ''
|
963 | 953 | }
|
|
996 | 986 | * @return {this.value}
|
997 | 987 | */
|
998 | 988 | maybeDeleteValue() {
|
999 |
| - if (!this.$refs.search.value.length && this.mutableValue) { |
| 989 | + if (!this.searchEl.value.length && this.mutableValue) { |
1000 | 990 | return this.multiple ? this.mutableValue.pop() : this.mutableValue = null
|
1001 | 991 | }
|
1002 | 992 | },
|
|
1044 | 1034 | */
|
1045 | 1035 | onMousedown() {
|
1046 | 1036 | this.mousedown = true
|
| 1037 | + }, |
| 1038 | +
|
| 1039 | + /** |
| 1040 | + * Search 'input' KeyBoardEvent handler. |
| 1041 | + * @param e {KeyboardEvent} |
| 1042 | + * @return {Function} |
| 1043 | + */ |
| 1044 | + onSearchKeyDown (e) { |
| 1045 | + switch (e.which) { |
| 1046 | + case 8: |
| 1047 | + // delete |
| 1048 | + return this.maybeDeleteValue(); |
| 1049 | + } |
| 1050 | + }, |
| 1051 | +
|
| 1052 | + /** |
| 1053 | + * Search 'input' KeyBoardEvent handler. |
| 1054 | + * @param e {KeyboardEvent} |
| 1055 | + * @return {Function} |
| 1056 | + */ |
| 1057 | + onSearchKeyUp (e) { |
| 1058 | + switch (e.which) { |
| 1059 | + case 27: |
| 1060 | + // esc |
| 1061 | + return this.onEscape(); |
| 1062 | + case 38: |
| 1063 | + // up.prevent |
| 1064 | + e.preventDefault(); |
| 1065 | + return this.typeAheadUp(); |
| 1066 | + case 40: |
| 1067 | + // down.prevent |
| 1068 | + e.preventDefault(); |
| 1069 | + return this.typeAheadDown(); |
| 1070 | + case 13: |
| 1071 | + // enter.prevent |
| 1072 | + e.preventDefault(); |
| 1073 | + return this.typeAheadSelect(); |
| 1074 | + case 9: |
| 1075 | + // tab |
| 1076 | + return this.onTab(); |
| 1077 | + } |
1047 | 1078 | }
|
1048 | 1079 | },
|
1049 | 1080 |
|
1050 | 1081 | computed: {
|
1051 | 1082 |
|
| 1083 | + /** |
| 1084 | + * Find the search input DOM element. |
| 1085 | + * @returns {HTMLInputElement} |
| 1086 | + */ |
| 1087 | + searchEl () { |
| 1088 | + return !!this.$scopedSlots['search'] |
| 1089 | + ? this.$refs.selectedOptions.querySelector(this.searchInputQuerySelector) |
| 1090 | + : this.$refs.search; |
| 1091 | + }, |
| 1092 | +
|
| 1093 | + /** |
| 1094 | + * The object to be bound to the $slots.search scoped slot. |
| 1095 | + * @returns {Object} |
| 1096 | + */ |
| 1097 | + scope () { |
| 1098 | + return { |
| 1099 | + search: { |
| 1100 | + attributes: { |
| 1101 | + 'disabled': this.disabled, |
| 1102 | + 'placeholder': this.searchPlaceholder, |
| 1103 | + 'tabindex': this.tabindex, |
| 1104 | + 'readonly': !this.searchable, |
| 1105 | + 'id': this.inputId, |
| 1106 | + 'value': this.search, |
| 1107 | + 'aria-expanded': this.dropdownOpen, |
| 1108 | + 'aria-label': 'Search for option', |
| 1109 | + 'ref': 'search', |
| 1110 | + 'role': 'combobox', |
| 1111 | + 'type': 'search', |
| 1112 | + 'autocomplete': 'off', |
| 1113 | + 'class': 'form-control', |
| 1114 | + }, |
| 1115 | + events: { |
| 1116 | + 'keydown': this.onSearchKeyDown, |
| 1117 | + 'keyup': this.onSearchKeyUp, |
| 1118 | + 'blur': this.onSearchBlur, |
| 1119 | + 'focus': this.onSearchFocus, |
| 1120 | + 'input': (e) => this.search = e.target.value, |
| 1121 | + }, |
| 1122 | + }, |
| 1123 | + }; |
| 1124 | + }, |
| 1125 | +
|
1052 | 1126 | /**
|
1053 | 1127 | * Classes to be output on .dropdown
|
1054 | 1128 | * @return {Object}
|
|
0 commit comments