fix: 🐛 Dropdown z-index problem

Z-index of dropdown does not work because it's parent has a transform
property. To avoid this, we float the dropdown using fixed co-ordinates
and then update the x, y positions.
This commit is contained in:
Faris Ansari 2018-12-28 19:16:26 +05:30
parent d494590b70
commit 3fc8ac9e72
3 changed files with 62 additions and 35 deletions

View File

@ -63,51 +63,72 @@ export default class ColumnManager {
} }
bindDropdown() { bindDropdown() {
let $activeDropdown;
let activeClass = 'dt-dropdown--active';
let toggleClass = '.dt-dropdown__toggle'; let toggleClass = '.dt-dropdown__toggle';
let dropdownClass = '.dt-dropdown__list';
$.on(this.header, 'click', toggleClass, (e, $button) => { // attach the dropdown list to container
const $dropdown = $.closest('.dt-dropdown', $button); this.instance.dropdownContainer.innerHTML = this.getDropdownListHTML();
this.$dropdownList = this.instance.dropdownContainer.firstElementChild;
if (!$dropdown.classList.contains(activeClass)) { $.on(this.header, 'click', toggleClass, e => {
deactivateDropdown(); this.openDropdown(e);
$dropdown.classList.add(activeClass);
$activeDropdown = $dropdown;
} else {
deactivateDropdown();
}
}); });
const deactivateDropdownOnBodyClick = (e) => { const deactivateDropdownOnBodyClick = (e) => {
const selector = [toggleClass, toggleClass + ' *'].join(','); const selector = [
toggleClass, toggleClass + ' *',
dropdownClass, dropdownClass + ' *'
].join(',');
if (e.target.matches(selector)) return; if (e.target.matches(selector)) return;
deactivateDropdown(); deactivateDropdown();
}; };
$.on(document.body, 'click', deactivateDropdownOnBodyClick); $.on(document.body, 'click', deactivateDropdownOnBodyClick);
document.addEventListener('scroll', deactivateDropdown, true);
this.instance.on('onDestroy', () => { this.instance.on('onDestroy', () => {
$.off(document.body, 'click', deactivateDropdownOnBodyClick); $.off(document.body, 'click', deactivateDropdownOnBodyClick);
$.off(document, 'scroll', deactivateDropdown);
}); });
const dropdownItems = this.options.headerDropdown; $.on(this.$dropdownList, 'click', '.dt-dropdown__list-item', (e, $item) => {
if (!this._dropdownActiveColIndex) return;
$.on(this.header, 'click', '.dt-dropdown__list-item', (e, $item) => { const dropdownItems = this.options.headerDropdown;
const $col = $.closest('.dt-cell', $item); const { index } = $.data($item);
const { const colIndex = this._dropdownActiveColIndex;
index
} = $.data($item);
const {
colIndex
} = $.data($col);
let callback = dropdownItems[index].action; let callback = dropdownItems[index].action;
callback && callback.call(this.instance, this.getColumn(colIndex)); callback && callback.call(this.instance, this.getColumn(colIndex));
this.hideDropdown();
}); });
const _this = this;
function deactivateDropdown(e) { function deactivateDropdown(e) {
$activeDropdown && $activeDropdown.classList.remove(activeClass); _this.hideDropdown();
$activeDropdown = null;
} }
this.hideDropdown();
}
openDropdown(e) {
if (!this._dropdownWidth) {
$.style(this.$dropdownList, { display: '' });
this._dropdownWidth = $.style(this.$dropdownList, 'width');
}
$.style(this.$dropdownList, {
display: '',
left: (e.clientX - this._dropdownWidth + 4) + 'px',
top: (e.clientY + 4) + 'px'
});
const $cell = $.closest('.dt-cell', e.target);
const { colIndex } = $.data($cell);
this._dropdownActiveColIndex = colIndex;
}
hideDropdown() {
$.style(this.$dropdownList, {
display: 'none'
});
this._dropdownActiveColIndex = null;
} }
bindResizeColumn() { bindResizeColumn() {
@ -370,17 +391,24 @@ export default class ColumnManager {
} }
getDropdownHTML() { getDropdownHTML() {
const { dropdownButton, headerDropdown: dropdownItems } = this.options; const { dropdownButton } = this.options;
return ` return `
<div class="dt-dropdown"> <div class="dt-dropdown">
<div class="dt-dropdown__toggle">${dropdownButton}</div> <div class="dt-dropdown__toggle">${dropdownButton}</div>
<div class="dt-dropdown__list">
${dropdownItems.map((d, i) => `
<div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
`).join('')}
</div>
</div> </div>
`; `;
} }
getDropdownListHTML() {
const { headerDropdown: dropdownItems } = this.options;
return `
<div class="dt-dropdown__list">
${dropdownItems.map((d, i) => `
<div class="dt-dropdown__list-item" data-index="${i}">${d.label}</div>
`).join('')}
</div>
`;
}
} }

View File

@ -78,6 +78,7 @@ class DataTable {
</span> </span>
</div> </div>
<div class="dt-toast"></div> <div class="dt-toast"></div>
<div class="dt-dropdown-container"></div>
<textarea class="dt-paste-target"></textarea> <textarea class="dt-paste-target"></textarea>
</div> </div>
`; `;
@ -89,6 +90,7 @@ class DataTable {
this.freezeContainer = $('.dt-freeze', this.wrapper); this.freezeContainer = $('.dt-freeze', this.wrapper);
this.toastMessage = $('.dt-toast', this.wrapper); this.toastMessage = $('.dt-toast', this.wrapper);
this.pasteTarget = $('.dt-paste-target', this.wrapper); this.pasteTarget = $('.dt-paste-target', this.wrapper);
this.dropdownContainer = $('.dt-dropdown-container', this.wrapper);
} }
refresh(data, columns) { refresh(data, columns) {

View File

@ -191,13 +191,10 @@
} }
&__list { &__list {
display: none; position: fixed;
position: absolute;
min-width: 8rem; min-width: 8rem;
top: 100%;
right: 0;
z-index: 1; z-index: 1;
cursor: pointer;
background-color: var(--dt-cell-bg); background-color: var(--dt-cell-bg);
border-radius: var(--dt-border-radius); border-radius: var(--dt-border-radius);
padding: var(--dt-spacer-2) 0; padding: var(--dt-spacer-2) 0;