Skip to content

Commit

Permalink
fixed dropdown getting trapped in modal, modal elongating after closi…
Browse files Browse the repository at this point in the history
…ng dropdown, dropdown rendering above input, and other observed buggy behavior
  • Loading branch information
thanksameeelian committed Apr 4, 2023
1 parent 67b4388 commit afb762d
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 9 deletions.
1 change: 1 addition & 0 deletions docs/pages/kselectinkmodal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
:options="options"
label="Who are you?"
placeholder="Nobody"
:insideModal="true"
/>
<p>Value: {{ exampleData }}</p>
</KModal>
Expand Down
45 changes: 37 additions & 8 deletions lib/KModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@
:tabindex="0"
role="dialog"
aria-labelledby="modal-title"
:style="[ modalSizeStyles, { background: $themeTokens.surface } ]"
:style="[
modalSizeStyles,
{ background: $themeTokens.surface },
containsKSelect ? { overflowY: 'unset' } : { overflowY: 'auto' }
]"
>

<!-- Modal Title -->
Expand Down Expand Up @@ -48,7 +52,10 @@
borderTop: `1px solid ${$themeTokens.fineLine}`,
borderBottom: `1px solid ${$themeTokens.fineLine}`,
} : {} ]"
:class="{ 'scroll-shadow': scrollShadow }"
:class="{
'scroll-shadow': scrollShadow,
'contains-kselect': containsKSelect
}"
>
<!-- @slot Main content of modal -->
<slot></slot>
Expand Down Expand Up @@ -182,6 +189,8 @@
lastFocus: null,
maxContentHeight: '1000',
contentHeight: 0,
previousContentHeight: 0,
containsKSelect: false,
scrollShadow: false,
delayedEnough: false,
};
Expand Down Expand Up @@ -241,6 +250,10 @@
});
window.addEventListener('focus', this.focusElementTest, true);
window.setTimeout(() => (this.delayedEnough = true), 500);
// if modal contains KSelect, special classes & styles will be applied
const kSelectCheck = document.getElementsByClassName('ui-select k-select');
this.containsKSelect = kSelectCheck.length > 0;
},
updated() {
this.updateContentSectionStyle();
Expand All @@ -265,24 +278,35 @@
updateContentSectionStyle: debounce(function() {
if (this.$refs.title && this.$refs.actions) {
if (Math.abs(this.$refs.content.scrollHeight - this.contentHeight) >= 8) {
// if there's dropdown & it is opened, the new scrollHeight detected shouldn't be applied,
// or else the modal will elongate after the dropdown content has been closed
this.previousContentHeight = this.contentHeight;
this.contentHeight = this.$refs.content.scrollHeight;
}
const maxContentHeightCheck =
this.windowHeight -
this.$refs.title.clientHeight -
this.$refs.actions.clientHeight -
32;
// to prevent max height from toggling between pixels
// we set a threshold of how many pixels the height should change before we update
if (Math.abs(maxContentHeightCheck - this.maxContentHeight) >= 8) {
this.maxContentHeight = maxContentHeightCheck;
this.scrollShadow = this.maxContentHeight < this.$refs.content.scrollHeight;
if (!this.containsKSelect) {
this.maxContentHeight = maxContentHeightCheck;
this.scrollShadow = this.maxContentHeight < this.$refs.content.scrollHeight;
} else if (this.containsKSelect && this.previousContentHeight > 0) {
// if there's dropdown & it is opened, the new scrollHeight detected shouldn't be applied
this.maxContentHeight = this.previousContentHeight;
}
}
// make sure that overflow-y won't be updated to 'auto' if this
// function is running for the first time
// (otherwise Firefox would add a vertical scrollbar right away)
if (this.$refs.content.clientHeight !== 0) {
// make sure that overflow-y won't be updated to 'auto' if this function is running for the first time
// (otherwise Firefox would add a vertical scrollbar right away) + don't apply if modal contains KSelect
// (otherwise KSelect will be trapped inside modal if KSelect is opened a second time)
if (this.$refs.content.clientHeight !== 0 && !this.containsKSelect) {
// add a vertical scrollbar if content doesn't fit
if (this.$refs.content.scrollHeight > this.$refs.content.clientHeight) {
this.$refs.content.style.overflowY = 'auto';
Expand Down Expand Up @@ -395,6 +419,7 @@
.content {
padding: 0 24px;
overflow-x: hidden;
}
.scroll-shadow {
Expand All @@ -407,6 +432,10 @@
background-size: 100% 20px, 100% 20px, 100% 10px, 100% 10px;
}
.contains-kselect {
overflow: unset;
}
.actions {
padding: 24px;
text-align: right;
Expand Down
10 changes: 9 additions & 1 deletion lib/KSelect/KeenUiSelect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,10 @@
type: String,
default: 'left', // 'left' or 'right'
},
insideModal: {
type: Boolean,
default: false,
},
label: {
type: String,
default: null,
Expand Down Expand Up @@ -744,7 +748,11 @@
},
toggleDropdown() {
this.calculateSpaceBelow();
// if called on dropdown inside modal, dropdown will generally render above input/placeholder when opened,
// rather than below it: we want to render dropdown above input only in cases where there isn't enough
// space available beneath input, but when dropdown extends outside a modal the func doesn't work as intended
if (!this.insideModal) this.calculateSpaceBelow();
this[this.showDropdown ? 'closeDropdown' : 'openDropdown']();
},
Expand Down
8 changes: 8 additions & 0 deletions lib/KSelect/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
:options="options"
:label="label"
:floatingLabel="floatingLabel"
:insideModal="insideModal"
:disabled="disabled"
:invalid="invalid"
:error="invalidText"
Expand Down Expand Up @@ -100,6 +101,13 @@
type: String,
default: null,
},
/**
* Whether situated inside a modal or not
*/
insideModal: {
type: Boolean,
default: false,
},
/**
* Whether disabled or not
*/
Expand Down

0 comments on commit afb762d

Please sign in to comment.