diff --git a/lib/KModal.vue b/lib/KModal.vue index d23e5b701..1cc9ca907 100644 --- a/lib/KModal.vue +++ b/lib/KModal.vue @@ -365,7 +365,6 @@ top: 50%; left: 50%; margin: 0 auto; - overflow-y: auto; border-radius: $radius; transform: translate(-50%, -50%); @@ -396,7 +395,6 @@ .content { padding: 0 24px; - overflow-x: hidden; } .scroll-shadow { diff --git a/lib/KSelect/KeenUiSelect.vue b/lib/KSelect/KeenUiSelect.vue index 6b7a93593..b966eec45 100644 --- a/lib/KSelect/KeenUiSelect.vue +++ b/lib/KSelect/KeenUiSelect.vue @@ -32,6 +32,7 @@ :class="$computedClass({ ':focus': $coreOutline })" :tabindex="disabled ? null : '0'" + @click="toggleDropdown" @focus="onFocus" @keydown.enter.prevent="openDropdown" @keydown.space.prevent="openDropdown" @@ -74,18 +75,11 @@ /> - +
-
+
@@ -200,7 +194,6 @@ import startswith from 'lodash/startsWith'; import sortby from 'lodash/sortBy'; import UiIcon from '../keen/UiIcon'; - import UiPopover from '../keen/UiPopover'; import { looseIndexOf, looseEqual } from '../keen/helpers/util'; import { scrollIntoView, resetScroll } from '../keen/helpers/element-scroll'; @@ -211,7 +204,6 @@ name: 'KeenUiSelect', components: { UiIcon, - UiPopover, KeenUiSelectOption, }, props: { @@ -327,6 +319,7 @@ isActive: false, isTouched: false, highlightedOption: null, + showDropdown: false, initialValue: JSON.stringify(this.value), quickMatchString: '', quickMatchTimeout: null, @@ -470,6 +463,7 @@ option[this.keys.label].toLowerCase(), this.quickMatchString.toLowerCase() ); + return option; }); }, @@ -506,6 +500,16 @@ resetScroll(this.$refs.optionsList); }, + showDropdown() { + if (this.showDropdown) { + this.onOpen(); + this.$emit('dropdown-open'); + } else { + this.onClose(); + this.$emit('dropdown-close'); + } + }, + query() { this.$emit('query-change', this.query); }, @@ -530,7 +534,7 @@ }, mounted() { - this.addExternalClickListener(this.$el, this.onExternalClick); + document.addEventListener('click', this.onExternalClick); // Find nearest scrollable ancestor this.scrollableAncestor = this.$el; while ( @@ -551,29 +555,10 @@ }, beforeDestroy() { - this.removeExternalClickListener(); + document.removeEventListener('click', this.onExternalClick); }, methods: { - addExternalClickListener(element = this.$el, callback = null) { - this.externalClickListener = e => { - if (!element.contains(e.target)) { - if (typeof callback === 'function') { - callback(e); - } else { - this.$emit('external-click', e); - } - } - }; - - document.addEventListener('click', this.externalClickListener); - }, - - removeExternalClickListener() { - document.removeEventListener('click', this.externalClickListener); - this.externalClickListener = null; - }, - setValue(value) { value = value ? value : this.multiple ? [] : ''; @@ -758,6 +743,11 @@ this.query = ''; }, + toggleDropdown() { + this.calculateSpaceBelow(); + this[this.showDropdown ? 'closeDropdown' : 'openDropdown'](); + }, + openDropdown() { if (this.disabled || this.clearableState) { return; @@ -767,7 +757,7 @@ this.highlightNextOption(); } - this.$refs.dropdown.open(); + this.showDropdown = true; // IE: clicking label doesn't focus the select element // to set isActive to true if (!this.isActive) { @@ -776,7 +766,7 @@ }, closeDropdown(options = { autoBlur: false }) { - this.$refs.dropdown.close(); + this.showDropdown = false; this.query = ''; if (!this.isTouched) { this.isTouched = true; @@ -790,35 +780,8 @@ } }, - // !!!!!!!!!!!!!!! functionality lost due to refactoring when updating this file to align with - // changes KeenUI's made to their source code to fix "dropdown getting stuck inside modal" problem -- KeenUi also - // refactored their UiPopover, adding in a new JS dropdown library and a couple related dependencies. i wanted to - // avoid expanding the scope of this PR and its testing so did not make the same changes to our vendored UiPopover, - // concerned about unintended effects on our other components that use our current version of UiPopover. - - // i have attempted to take what we need from KeenUI's update to UiSelect and accomplish the rest through - // additional functions & CSS targeting. the dropdown now extends beyond the modal as desired but you cannot tab - // through it and it does not highlight upon mouseover (though that specifically could be solved with CSS :hover - // targeting, it doesn't address the underlying loss of functionality) - // - // each time i end up in a tangle...some highlights (lowlights haha): - - // - with unintended side effects leading to behavior of dropdown closing upon highlight; - - // - unsuccessfully attempted to adapt functionality from KDropdownMenu where UiPopover is ostensibly working with - // highlight functions [rather than CSS targeting of :hover] & tabbing through options; - // - // - this onMouseover function is "working" and mouseovers are registering, still not providing desired - // highlight-upon-hover functionality; - // - // - CSS targeting of each element on :hover in KeenUiSelectOption solves highlight-upon-hover issue on surface - // level but does not address inability to tab through options and simply disguises broken functionality underneath). - // - - // have tried to clean up most attempts since they were muddying the waters 🫠 - onMouseover(option) { - if (this.$refs.dropdown.isOpen()) { + if (this.showDropdown) { this.highlightOption(option, { autoScroll: false }); } }, @@ -836,20 +799,15 @@ this.isActive = false; this.$emit('blur', e); - if (this.$refs.dropdown.isOpen()) { + if (this.showDropdown) { this.closeDropdown({ autoBlur: true }); } }, onOpen() { - document.addEventListener('scroll', this.onExternalScroll, true); - this.$emit('dropdown-open'); - - this.$refs.dropdown.$el.style.width = this.$refs.label.getBoundingClientRect().width + 'px'; - this.highlightedOption = this.multiple ? null : this.value; this.$nextTick(() => { - this.$refs[this.hasSearch ? 'searchInput' : 'dropdownContent'].focus(); + this.$refs[this.hasSearch ? 'searchInput' : 'dropdown'].focus(); const selectedOption = this.$refs.optionsList.querySelector('.is-selected'); if (selectedOption) { this.scrollOptionIntoView(selectedOption); @@ -862,24 +820,16 @@ }, onClose() { - document.removeEventListener('scroll', this.onExternalScroll, true); - this.highlightedOption = this.multiple ? null : this.value; - - this.$emit('dropdown-close'); - }, - - onExternalClick() { - if (this.$refs.dropdown.isOpen()) { - this.closeDropdown({ autoBlur: true }); - } else if (this.isActive) { - this.isActive = false; - } }, - onExternalScroll(e) { - if (e.target !== this.$refs.optionsList) { - this.closeDropdown(); + onExternalClick(e) { + if (!this.$el.contains(e.target)) { + if (this.showDropdown) { + this.closeDropdown({ autoBlur: true }); + } else if (this.isActive) { + this.isActive = false; + } } }, @@ -903,7 +853,6 @@ resetTouched(options = { touched: false }) { this.isTouched = options.touched; }, - calculateSpaceBelow() { // Get the height of element const buttonHeight = this.$el.getBoundingClientRect().height; @@ -1049,6 +998,7 @@ } .ui-select-label { + position: relative; display: block; width: 100%; padding: 0; @@ -1122,6 +1072,7 @@ .ui-select-dropdown { position: absolute; + z-index: $z-index-dropdown; display: block; width: 100%; min-width: rem-calc(180px); @@ -1130,10 +1081,7 @@ margin-bottom: rem-calc(8px); list-style-type: none; outline: none; - } - - .ui-select-dropdown-content { - outline: none; + box-shadow: 1px 2px 8px $md-grey-600; } .ui-select-search-input { @@ -1222,6 +1170,20 @@ } } + // ================================================ + // Transitions + // ================================================ + + .ui-select-transition-fade-enter-active, + .ui-select-transition-fade-leave-active { + transition: opacity 0.2s ease; + } + + .ui-select-transition-fade-enter, + .ui-select-transition-fade-leave-active { + opacity: 0; + } + /* stylelint-enable */ .overlay-close-button {