From 045f322bf689085fd69251a1d3d1724e15cc0384 Mon Sep 17 00:00:00 2001 From: nathan Date: Thu, 4 Aug 2022 15:50:52 -0600 Subject: [PATCH] Et2Select changes: - Position search & edit inputs to avoid reflow - When editing a freeEntry, blurring accepts the current value, before it canceled the edit --- api/js/etemplate/Et2Select/Et2Select.ts | 10 +++++-- api/js/etemplate/Et2Select/SearchMixin.ts | 33 ++++++++++++----------- api/templates/default/etemplate2.css | 1 + 3 files changed, 27 insertions(+), 17 deletions(-) diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts index 7c7b5b0871..6a818ffc19 100644 --- a/api/js/etemplate/Et2Select/Et2Select.ts +++ b/api/js/etemplate/Et2Select/Et2Select.ts @@ -62,8 +62,8 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect) { return [ // Parent (SlSelect) returns a single cssResult, not an array - super.styles, shoelace, + super.styles, css` :host { display: block; @@ -336,7 +336,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect) { overflow = this.displayTags.pop(); } - const checkedItems = Object.values(this.menuItems).filter(item => this.value.includes(item.value)); + const checkedItems = Object.values(this._menuItems).filter(item => this.value.includes(item.value)); this.displayTags = checkedItems.map(item => this._createTagNode(item)); // Re-slice & add overflow tag @@ -453,6 +453,12 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect) return ""; } + public get _menuItems() : HTMLElement[] + { + return [...this.querySelectorAll(this.optionTag)]; + } + + /** * Override parent to always call validate(), as our simple implementation needs to validate on clear as well. * diff --git a/api/js/etemplate/Et2Select/SearchMixin.ts b/api/js/etemplate/Et2Select/SearchMixin.ts index 143237231a..a4a1000594 100644 --- a/api/js/etemplate/Et2Select/SearchMixin.ts +++ b/api/js/etemplate/Et2Select/SearchMixin.ts @@ -177,8 +177,9 @@ export const Et2WithSearchMixin = >(superclass margin-left: 0px; width: 100%; height: var(--sl-input-height-medium); - position: relative; + position: absolute; background-color: white; + z-index: 1; } /* Search UI active - show textbox & stuff */ ::slotted(.search_input.active),.search_input.active, @@ -407,7 +408,7 @@ export const Et2WithSearchMixin = >(superclass } // Overridden to add options if allowFreeEntries=true - if(typeof this.value == "string" && !this.menuItems.find(o => o.value == this.value)) + if(typeof this.value == "string" && !this._menuItems.find(o => o.value == this.value)) { this.createFreeEntry(this.value); } @@ -415,7 +416,7 @@ export const Et2WithSearchMixin = >(superclass { this.value.forEach((e) => { - if(!this.menuItems.find(o => o.value == e)) + if(!this._menuItems.find(o => o.value == e)) { this.createFreeEntry(e); } @@ -583,6 +584,10 @@ export const Et2WithSearchMixin = >(superclass { this.dropdown.hide(); } + else + { + this._searchInputNode.focus(); + } } else if(event.key == "Enter") { @@ -608,7 +613,7 @@ export const Et2WithSearchMixin = >(superclass // Stop propagation, or parent key handler will add again event.stopImmediatePropagation(); - if(event.key == "Enter" && this.allowFreeEntries) + if(Et2WidgetWithSearch.TAG_BREAK.indexOf(event.key) !== -1 && this.allowFreeEntries) { // Prevent default, since that would try to submit event.preventDefault(); @@ -798,14 +803,7 @@ export const Et2WithSearchMixin = >(superclass // Once added to options, add to value / tags this.updateComplete.then(() => { - this.menuItems.forEach(o => - { - if(o.value == text) - { - o.dispatchEvent(new Event("click")); - } - }); - this.syncItemsFromValue(); + this.handleMenuSlotChange(); }); return true; } @@ -865,9 +863,14 @@ export const Et2WithSearchMixin = >(superclass protected stopEdit(abort = false) { // type to select will focus matching entries, but we don't want to stop the edit yet - if(typeof abort == "object" && abort.type == "blur" && abort.relatedTarget?.localName == "sl-menu-item") + if(typeof abort == "object" && abort.type == "blur") { - return; + if(abort.relatedTarget?.localName == "sl-menu-item") + { + return; + } + // Edit lost focus, accept changes + abort = false; } let value = abort ? this._editInputNode.dataset.initial : this._editInputNode.value; @@ -888,7 +891,7 @@ export const Et2WithSearchMixin = >(superclass this._searchInputNode.value = ""; // Reset options. It might be faster to re-create instead. - this.menuItems.forEach((item) => + this._menuItems.forEach((item) => { item.disabled = false; item.classList.remove("match"); diff --git a/api/templates/default/etemplate2.css b/api/templates/default/etemplate2.css index 678a5dbb80..1730726f8d 100644 --- a/api/templates/default/etemplate2.css +++ b/api/templates/default/etemplate2.css @@ -92,6 +92,7 @@ ::part(form-control-input) { flex: 1 1 auto; + position: relative; } ::part(form-control-help-text) {