Et2Select changes:

- Position search & edit inputs to avoid reflow
- When editing a freeEntry, blurring accepts the current value, before it canceled the edit
This commit is contained in:
nathan 2022-08-04 15:50:52 -06:00
parent f08eaa9fdc
commit 045f322bf6
3 changed files with 27 additions and 17 deletions

View File

@ -62,8 +62,8 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
{ {
return [ return [
// Parent (SlSelect) returns a single cssResult, not an array // Parent (SlSelect) returns a single cssResult, not an array
super.styles,
shoelace, shoelace,
super.styles,
css` css`
:host { :host {
display: block; display: block;
@ -336,7 +336,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
{ {
overflow = this.displayTags.pop(); 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)); this.displayTags = checkedItems.map(item => this._createTagNode(item));
// Re-slice & add overflow tag // Re-slice & add overflow tag
@ -453,6 +453,12 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
return ""; return "";
} }
public get _menuItems() : HTMLElement[]
{
return [...this.querySelectorAll<SlMenuItem>(this.optionTag)];
}
/** /**
* Override parent to always call validate(), as our simple implementation needs to validate on clear as well. * Override parent to always call validate(), as our simple implementation needs to validate on clear as well.
* *

View File

@ -177,8 +177,9 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
margin-left: 0px; margin-left: 0px;
width: 100%; width: 100%;
height: var(--sl-input-height-medium); height: var(--sl-input-height-medium);
position: relative; position: absolute;
background-color: white; background-color: white;
z-index: 1;
} }
/* Search UI active - show textbox & stuff */ /* Search UI active - show textbox & stuff */
::slotted(.search_input.active),.search_input.active, ::slotted(.search_input.active),.search_input.active,
@ -407,7 +408,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
} }
// Overridden to add options if allowFreeEntries=true // 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); this.createFreeEntry(this.value);
} }
@ -415,7 +416,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
{ {
this.value.forEach((e) => this.value.forEach((e) =>
{ {
if(!this.menuItems.find(o => o.value == e)) if(!this._menuItems.find(o => o.value == e))
{ {
this.createFreeEntry(e); this.createFreeEntry(e);
} }
@ -583,6 +584,10 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
{ {
this.dropdown.hide(); this.dropdown.hide();
} }
else
{
this._searchInputNode.focus();
}
} }
else if(event.key == "Enter") else if(event.key == "Enter")
{ {
@ -608,7 +613,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
// Stop propagation, or parent key handler will add again // Stop propagation, or parent key handler will add again
event.stopImmediatePropagation(); 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 // Prevent default, since that would try to submit
event.preventDefault(); event.preventDefault();
@ -798,14 +803,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
// Once added to options, add to value / tags // Once added to options, add to value / tags
this.updateComplete.then(() => this.updateComplete.then(() =>
{ {
this.menuItems.forEach(o => this.handleMenuSlotChange();
{
if(o.value == text)
{
o.dispatchEvent(new Event("click"));
}
});
this.syncItemsFromValue();
}); });
return true; return true;
} }
@ -865,10 +863,15 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
protected stopEdit(abort = false) protected stopEdit(abort = false)
{ {
// type to select will focus matching entries, but we don't want to stop the edit yet // 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")
{
if(abort.relatedTarget?.localName == "sl-menu-item")
{ {
return; return;
} }
// Edit lost focus, accept changes
abort = false;
}
let value = abort ? this._editInputNode.dataset.initial : this._editInputNode.value; let value = abort ? this._editInputNode.dataset.initial : this._editInputNode.value;
@ -888,7 +891,7 @@ export const Et2WithSearchMixin = <T extends Constructor<LitElement>>(superclass
this._searchInputNode.value = ""; this._searchInputNode.value = "";
// Reset options. It might be faster to re-create instead. // Reset options. It might be faster to re-create instead.
this.menuItems.forEach((item) => this._menuItems.forEach((item) =>
{ {
item.disabled = false; item.disabled = false;
item.classList.remove("match"); item.classList.remove("match");

View File

@ -92,6 +92,7 @@
::part(form-control-input) { ::part(form-control-input) {
flex: 1 1 auto; flex: 1 1 auto;
position: relative;
} }
::part(form-control-help-text) { ::part(form-control-help-text) {