mirror of
https://github.com/EGroupware/egroupware.git
synced 2024-11-07 08:34:42 +01:00
Et2TreeDropdown improvements
- multiple=false rendering - fix some display search vs tree weirdness - fix some keyboard actions - translate placeholder - blur widget after option selected when multiple=false - implement clearable attribute
This commit is contained in:
parent
2e0010d138
commit
2da2ac81fa
@ -1043,7 +1043,7 @@ export class Et2Tree extends Et2WidgetWithSelectMixin(LitElement) implements Fin
|
||||
>
|
||||
<sl-icon name="chevron-right" slot="expand-icon"></sl-icon>
|
||||
<sl-icon name="chevron-down" slot="collapse-icon"></sl-icon>
|
||||
${repeat(this._selectOptions, this._optionTemplate)}
|
||||
${repeat(this._selectOptions, (o) => o.value, this._optionTemplate)}
|
||||
</sl-tree>
|
||||
`;
|
||||
}
|
||||
|
@ -9,6 +9,10 @@ export default css`
|
||||
display: none;
|
||||
}
|
||||
|
||||
.form-control-input {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Label */
|
||||
|
||||
.form-control--has-label .form-control__label {
|
||||
@ -37,14 +41,26 @@ export default css`
|
||||
margin-top: var(--sl-spacing-3x-small);
|
||||
}
|
||||
|
||||
.tree-dropdown__value-input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
z-index: -1;
|
||||
}
|
||||
.tree-dropdown__combobox {
|
||||
min-height: calc(var(--sl-input-height-medium) - 2 * var(--sl-input-border-width));
|
||||
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: flex-start;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
vertical-align: middle;
|
||||
|
||||
background-color: var(--sl-input-background-color);
|
||||
border: solid var(--sl-input-border-width) var(--sl-input-border-color);
|
||||
@ -58,6 +74,12 @@ export default css`
|
||||
|
||||
transition: var(--sl-transition-fast) color, var(--sl-transition-fast) border, var(--sl-transition-fast) box-shadow,
|
||||
var(--sl-transition-fast) background-color;
|
||||
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
:host([multiple]) .tree-dropdown__combobox {
|
||||
align-items: flex-start
|
||||
}
|
||||
|
||||
.tree-dropdown--disabled {
|
||||
@ -91,6 +113,7 @@ export default css`
|
||||
transition: var(--sl-transition-medium) rotate ease;
|
||||
rotate: 0;
|
||||
margin-inline-start: var(--sl-spacing-small);
|
||||
order: 99;
|
||||
}
|
||||
|
||||
.tree-dropdown--open .tree-dropdown__expand-icon {
|
||||
@ -103,9 +126,18 @@ export default css`
|
||||
order: 1;
|
||||
}
|
||||
|
||||
/* Single */
|
||||
|
||||
|
||||
/* End single */
|
||||
|
||||
/* Tags */
|
||||
|
||||
.tree-dropdown__tags {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree-dropdown--multiple.tree-dropdown--has-value:not(.tree-dropdown--placeholder-visible) .tree-dropdown__tags {
|
||||
display: flex;
|
||||
flex: 2 1 auto;
|
||||
flex-wrap: wrap;
|
||||
@ -116,6 +148,7 @@ export default css`
|
||||
min-width: 0px;
|
||||
}
|
||||
|
||||
|
||||
/* Limit tag size */
|
||||
|
||||
.tree_tag {
|
||||
@ -132,10 +165,6 @@ export default css`
|
||||
|
||||
/* Search box */
|
||||
|
||||
:host([readonly]) .tree-dropdown__search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.tree-dropdown__search {
|
||||
flex: 1 1 7em;
|
||||
order: 10;
|
||||
@ -143,9 +172,10 @@ export default css`
|
||||
border: none;
|
||||
outline: none;
|
||||
|
||||
color: var(--sl-input-color);
|
||||
font-size: var(--sl-input-font-size-medium);
|
||||
padding-block: 0;
|
||||
padding-inline: var(--sl-input-spacing-medium);
|
||||
cursor: inherit;
|
||||
}
|
||||
|
||||
.form-control--medium .tree-dropdown__search {
|
||||
@ -153,6 +183,14 @@ export default css`
|
||||
height: calc(var(--sl-input-height-medium) * 0.8);
|
||||
}
|
||||
|
||||
:host([open]) .tree-dropdown__search {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
:host(:not([open])) .tree-dropdown--has-value.tree-dropdown--multiple .tree-dropdown__search {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.tree-dropdown--disabled .tree-dropdown__search {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
@ -161,17 +199,6 @@ export default css`
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
/* tag takes full width when widget is not multiple and has value and does not have focus */
|
||||
|
||||
:host(:not([multiple])) .tree-dropdown--has-value .tree-dropdown__search {
|
||||
display: none;
|
||||
}
|
||||
|
||||
:host(:not([multiple])) .tree-dropdown--focused .tree-dropdown__search,
|
||||
:host(:not([multiple])) .tree-dropdown--open .tree-dropdown__search {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.tree-dropdown__suffix {
|
||||
order: 20;
|
||||
}
|
||||
|
@ -11,9 +11,10 @@ import {SlPopup, SlRemoveEvent, SlTreeItem} from "@shoelace-style/shoelace";
|
||||
import shoelace from "../Styles/shoelace";
|
||||
import styles from "./Et2TreeDropdown.styles";
|
||||
import {Et2Tag} from "../Et2Select/Tag/Et2Tag";
|
||||
import {SearchMixin, SearchResult, SearchResultsInterface} from "../Et2Widget/SearchMixin";
|
||||
import {SearchMixin, SearchResult, SearchResultElement, SearchResultsInterface} from "../Et2Widget/SearchMixin";
|
||||
import {Et2InputWidgetInterface} from "../Et2InputWidget/Et2InputWidget";
|
||||
import {Required} from "../Validators/Required";
|
||||
import {SelectOption} from "../Et2Select/FindSelectOptions";
|
||||
|
||||
|
||||
interface TreeSearchResults extends SearchResultsInterface<TreeItemData>
|
||||
@ -56,11 +57,26 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* List of properties that get translated
|
||||
* @returns object
|
||||
*/
|
||||
static get translate()
|
||||
{
|
||||
return {
|
||||
...super.translate,
|
||||
placeholder: true,
|
||||
}
|
||||
}
|
||||
|
||||
/** Placeholder text to show as a hint when the select is empty. */
|
||||
@property() placeholder = "";
|
||||
|
||||
@property({type: Boolean, reflect: true}) multiple = false;
|
||||
|
||||
/** Adds a clear button when the dropdown is not empty. */
|
||||
@property({type: Boolean}) clearable = false;
|
||||
|
||||
/** The component's help text. If you need to display HTML, use the `help-text` slot instead. */
|
||||
@property({attribute: 'help-text'}) helpText = "";
|
||||
|
||||
@ -122,6 +138,8 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
protected readonly hasSlotController = new HasSlotController(<LitElement><unknown>this, "help-text", "label");
|
||||
private __value : string[];
|
||||
|
||||
protected displayLabel = '';
|
||||
|
||||
constructor()
|
||||
{
|
||||
super();
|
||||
@ -133,11 +151,30 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
connectedCallback()
|
||||
{
|
||||
super.connectedCallback();
|
||||
document.addEventListener("click", this.handleDocumentClick);
|
||||
}
|
||||
|
||||
disconnectedCallback()
|
||||
{
|
||||
super.disconnectedCallback();
|
||||
document.removeEventListener("click", this.handleDocumentClick);
|
||||
}
|
||||
|
||||
willUpdate(changedProperties)
|
||||
{
|
||||
super.willUpdate(changedProperties);
|
||||
|
||||
// Child tree not updating when our emptyLabel changes
|
||||
if(this._tree && (changedProperties.has("select_options") || changedProperties.has("emptyLabel")))
|
||||
{
|
||||
let options = this.multiple || !this.emptyLabel ? this.select_options : [{
|
||||
value: "",
|
||||
label: this.emptyLabel
|
||||
}, ...this.select_options];
|
||||
|
||||
this._tree._selectOptions = <TreeItemData[]>options;
|
||||
this._tree.requestUpdate("_selectOptions");
|
||||
}
|
||||
}
|
||||
|
||||
updated(changedProperties : PropertyValues)
|
||||
@ -188,6 +225,17 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
const oldValue = this.__value;
|
||||
// Filter to make sure there are no trailing commas or duplicates
|
||||
this.__value = Array.from(new Set(<string[]>new_value.filter(v => v)));
|
||||
|
||||
this.displayLabel = "";
|
||||
if(!this.multiple)
|
||||
{
|
||||
const option = this.optionSearch(this.__value[0], this.select_options, 'value', 'children');
|
||||
if(option)
|
||||
{
|
||||
this.displayLabel = option.label;
|
||||
}
|
||||
}
|
||||
|
||||
this.requestUpdate("value", oldValue);
|
||||
}
|
||||
|
||||
@ -199,47 +247,49 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
}
|
||||
|
||||
|
||||
get select_options() : SelectOption[]
|
||||
{
|
||||
return super.select_options;
|
||||
}
|
||||
|
||||
set select_options(new_options : SelectOption[])
|
||||
{
|
||||
super.select_options = new_options;
|
||||
|
||||
// Overridden so we can update displayLabel in the case where value got set before selectOptions
|
||||
if(this.value && !this.multiple)
|
||||
{
|
||||
const option = this.optionSearch(typeof this.value == "string" ? this.value : this.value[0], this.select_options, 'value', 'children');
|
||||
if(option)
|
||||
{
|
||||
this.displayLabel = option.label;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets focus on the control. */
|
||||
focus(options? : FocusOptions)
|
||||
{
|
||||
this.hasFocus = true;
|
||||
// Should not be needed, but not firing the update
|
||||
this.requestUpdate("hasFocus");
|
||||
|
||||
if(this._searchNode)
|
||||
{
|
||||
this._searchNode.focus(options);
|
||||
}
|
||||
this.handleFocus();
|
||||
}
|
||||
|
||||
/** Removes focus from the control. */
|
||||
blur()
|
||||
{
|
||||
this.open = false;
|
||||
this.treeOrSearch = "tree";
|
||||
this.hasFocus = false;
|
||||
this._popup.active = false;
|
||||
// Should not be needed, but not firing the update
|
||||
this.requestUpdate("open");
|
||||
this.requestUpdate("hasFocus");
|
||||
this._searchNode.blur();
|
||||
|
||||
clearTimeout(this._searchTimeout);
|
||||
this.handleBlur();
|
||||
}
|
||||
|
||||
|
||||
/** Shows the tree. */
|
||||
async show()
|
||||
{
|
||||
if(this.open || this.disabled)
|
||||
if(this.readonly || this.disabled)
|
||||
{
|
||||
this.open = false;
|
||||
this.requestUpdate("open", true);
|
||||
return undefined;
|
||||
return this.updateComplete;
|
||||
}
|
||||
|
||||
document.addEventListener("click", this.handleDocumentClick);
|
||||
this.open = true;
|
||||
this.requestUpdate("open", false)
|
||||
return this.updateComplete
|
||||
@ -253,8 +303,6 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
return undefined;
|
||||
}
|
||||
|
||||
document.removeEventListener("click", this.handleDocumentClick);
|
||||
|
||||
this.open = false;
|
||||
this._popup.active = false;
|
||||
this._searchNode.value = "";
|
||||
@ -311,10 +359,25 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
return super.localSearch(search, searchOptions, this.select_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggles a search result's selected state
|
||||
* Overridden to handle multiple attribute so only 1 result is selected
|
||||
*/
|
||||
protected toggleResultSelection(result : HTMLElement & SearchResultElement, force? : boolean)
|
||||
{
|
||||
if(!this.multiple)
|
||||
{
|
||||
this._resultNodes.forEach(t => t.selected = false);
|
||||
}
|
||||
|
||||
super.toggleResultSelection(result, force);
|
||||
}
|
||||
|
||||
protected searchResultSelected()
|
||||
{
|
||||
super.searchResultSelected();
|
||||
|
||||
const oldValue = [...this.value];
|
||||
if(this.multiple && typeof this.value !== "undefined")
|
||||
{
|
||||
// Add in the new result(s), no duplicates
|
||||
@ -328,9 +391,50 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
|
||||
// Done with search, show the tree
|
||||
this.treeOrSearch = "tree";
|
||||
// Close the dropdown
|
||||
this.hide();
|
||||
this.requestUpdate("value");
|
||||
|
||||
// Close the dropdown, move on
|
||||
if(!this.multiple || this.egw().preference("select_multiple_close") == "close")
|
||||
{
|
||||
this.blur();
|
||||
}
|
||||
else
|
||||
{
|
||||
this._tree.value = <string[]>this.value;
|
||||
}
|
||||
|
||||
// Update values
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
});
|
||||
this._tree.requestUpdate("value", oldValue);
|
||||
this.requestUpdate("value", oldValue);
|
||||
}
|
||||
|
||||
private handleClearClick(event : MouseEvent)
|
||||
{
|
||||
event.stopPropagation();
|
||||
|
||||
if(this.value.length > 0)
|
||||
{
|
||||
this.value = [];
|
||||
this.displayInput.focus({preventScroll: true});
|
||||
|
||||
// Emit after update
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.emit('sl-clear');
|
||||
this.emit('sl-input');
|
||||
this.emit('sl-change');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private handleClearMouseDown(event : MouseEvent)
|
||||
{
|
||||
// Don't lose focus or propagate events when clicking the clear button
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -403,11 +507,60 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
event.preventDefault();
|
||||
this.hide()
|
||||
}
|
||||
else
|
||||
{
|
||||
this.blur();
|
||||
}
|
||||
this.blur();
|
||||
}
|
||||
|
||||
private handleFocus()
|
||||
{
|
||||
this.hasFocus = true;
|
||||
// Should not be needed, but not firing the update
|
||||
this.requestUpdate("hasFocus");
|
||||
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
if(this._searchNode)
|
||||
{
|
||||
this._searchNode.focus();
|
||||
}
|
||||
else
|
||||
{
|
||||
this._tree.focus();
|
||||
}
|
||||
|
||||
this.dispatchEvent(new Event("sl-focus"));
|
||||
})
|
||||
}
|
||||
|
||||
private handleBlur()
|
||||
{
|
||||
this.open = false;
|
||||
this.treeOrSearch = "tree";
|
||||
this.hasFocus = false;
|
||||
this.resultsOpen = false;
|
||||
this._popup.active = false;
|
||||
// Should not be needed, but not firing the update
|
||||
this.requestUpdate("resultsOpen");
|
||||
this.requestUpdate("open");
|
||||
this.requestUpdate("hasFocus");
|
||||
this._searchNode?.blur();
|
||||
|
||||
clearTimeout(this._searchTimeout);
|
||||
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("sl-blur"));
|
||||
})
|
||||
}
|
||||
|
||||
protected handleClick(event)
|
||||
{
|
||||
// Open if clicking somewhere in the widget
|
||||
if(event.target.classList.contains("tree-dropdown__combobox"))
|
||||
{
|
||||
event.stopPropagation();
|
||||
this.show();
|
||||
this.handleFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private handleSearchFocus()
|
||||
@ -419,12 +572,28 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
// Reset tags to not take focus
|
||||
this.setCurrentTag(null);
|
||||
|
||||
this.show();
|
||||
}
|
||||
|
||||
private handleSearchBlur(event)
|
||||
{
|
||||
// Focus lost to some other internal component - ignore it
|
||||
if(event.composedPath().includes(this.shadowRoot))
|
||||
{
|
||||
return;
|
||||
}
|
||||
this.handleBlur();
|
||||
}
|
||||
|
||||
handleSearchKeyDown(event)
|
||||
{
|
||||
super.handleSearchKeyDown(event);
|
||||
|
||||
if(event.key == "ArrowDown" && !this.open && !this.resultsOpen)
|
||||
{
|
||||
this.show();
|
||||
}
|
||||
|
||||
// Left at beginning goes to tags
|
||||
if(this._searchNode.selectionStart == 0 && event.key == "ArrowLeft")
|
||||
{
|
||||
@ -492,30 +661,31 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
this.value = [...this.value, id];
|
||||
}
|
||||
}
|
||||
this.requestUpdate("value", oldValue);
|
||||
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
});
|
||||
if(!this.multiple)
|
||||
if(!this.multiple || this.egw().preference("select_multiple_close") == "close")
|
||||
{
|
||||
this.hide();
|
||||
this.blur();
|
||||
}
|
||||
}
|
||||
|
||||
handleTriggerClick()
|
||||
handleTriggerClick(event)
|
||||
{
|
||||
event.stopPropagation();
|
||||
|
||||
this.hasFocus = true;
|
||||
if(this.open)
|
||||
{
|
||||
this._popup.active = false;
|
||||
this._searchNode.value = "";
|
||||
document.removeEventListener("click", this.handleDocumentClick);
|
||||
}
|
||||
else
|
||||
{
|
||||
this._popup.active = true;
|
||||
document.addEventListener("click", this.handleDocumentClick);
|
||||
}
|
||||
this.open = this._popup.active;
|
||||
this.treeOrSearch = "tree";
|
||||
@ -523,7 +693,7 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this._tree.style.minWidth = getComputedStyle(this).width;
|
||||
this._tree.focus();
|
||||
this.focus();
|
||||
})
|
||||
}
|
||||
|
||||
@ -546,18 +716,49 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
|
||||
inputTemplate()
|
||||
{
|
||||
let placeholder = this.egw().lang("search");
|
||||
if(this.disabled || this.readonly || (this.open && this.value))
|
||||
{
|
||||
placeholder = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
placeholder = this.emptyLabel || this.placeholder;
|
||||
}
|
||||
return html`
|
||||
<input id="search" type="text" part="input"
|
||||
class="tree-dropdown__search search__input"
|
||||
autocomplete="off"
|
||||
spellcheck="false"
|
||||
autocapitalize="off"
|
||||
aria-controls="listbox"
|
||||
aria-expanded=${this.open ? 'true' : 'false'}
|
||||
aria-haspopup="listbox"
|
||||
aria-labelledby="label"
|
||||
aria-disabled=${this.disabled ? 'true' : 'false'}
|
||||
aria-describedby="help-text"
|
||||
role="combobox"
|
||||
|
||||
?disabled=${this.disabled}
|
||||
?readonly=${this.readonly}
|
||||
placeholder="${this.hasFocus || this.value.length > 0 || this.disabled || this.readonly ? "" : this.egw().lang(this.placeholder || this.emptyLabel)}"
|
||||
placeholder="${placeholder}"
|
||||
tabindex="0"
|
||||
.value=${this.hasFocus ? "" : this.displayLabel}
|
||||
@keydown=${this.handleSearchKeyDown}
|
||||
@blur=${() => {this.hasFocus = false;}}
|
||||
@blur=${this.handleSearchBlur}
|
||||
@focus=${this.handleSearchFocus}
|
||||
@paste=${this.handlePaste}
|
||||
/>
|
||||
<input
|
||||
class="tree-dropdown__value-input"
|
||||
type="text"
|
||||
?disabled=${this.disabled}
|
||||
?required=${this.required}
|
||||
.value=${Array.isArray(this.value) ? this.value.join(', ') : this.value}
|
||||
tabindex="-1"
|
||||
aria-hidden="true"
|
||||
@focus=${this.handleFocus}
|
||||
@blur=${this.handleBlur}
|
||||
/>
|
||||
`;
|
||||
}
|
||||
@ -578,15 +779,23 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
return literal`et2-tag`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows the currently selected values as tags when multiple=true
|
||||
*
|
||||
* @returns {TemplateResult}
|
||||
*/
|
||||
tagsTemplate()
|
||||
{
|
||||
const value = this.getValueAsArray();
|
||||
return html`${map(value, (value, index) =>
|
||||
{
|
||||
// Deal with value that is not in options
|
||||
const option = this.optionSearch(value, this.select_options, 'value', 'children');
|
||||
return option ? this.tagTemplate(option) : nothing;
|
||||
})}`;
|
||||
return html`
|
||||
<div part="tags" class="tree-dropdown__tags">
|
||||
${map(value, (value, index) =>
|
||||
{
|
||||
// Deal with value that is not in options
|
||||
const option = this.optionSearch(value, this.select_options, 'value', 'children');
|
||||
return option ? this.tagTemplate(option) : nothing;
|
||||
})}
|
||||
</div>`;
|
||||
}
|
||||
|
||||
tagTemplate(option : TreeItemData)
|
||||
@ -633,8 +842,12 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
const hasLabel = this.label ? true : !!hasLabelSlot;
|
||||
const hasValue = this.value && this.value.length > 0;
|
||||
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
|
||||
const hasClearIcon = this.clearable && !this.disabled && this.value.length > 0;
|
||||
const isPlaceholderVisible = (this.placeholder || this.emptyLabel) && this.value.length === 0 && !this.disabled && !this.readonly;
|
||||
|
||||
let options = this.multiple || !this.emptyLabel ? this.select_options : [{
|
||||
value: "",
|
||||
label: this.emptyLabel
|
||||
}, ...this.select_options];
|
||||
return html`
|
||||
<div
|
||||
part="form-control"
|
||||
@ -662,6 +875,7 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
'tree-dropdown--disabled': this.disabled,
|
||||
'tree-dropdown--readonly': this.readonly,
|
||||
'tree-dropdown--focused': this.hasFocus,
|
||||
'tree-dropdown--multiple': this.multiple,
|
||||
'tree-dropdown--placeholder-visible': isPlaceholderVisible,
|
||||
'tree-dropdown--searching': this.treeOrSearch == "search",
|
||||
'tree-dropdown--has-value': hasValue
|
||||
@ -672,7 +886,6 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
auto-size-padding="10"
|
||||
?active=${this.open}
|
||||
placement=${this.placement || "bottom"}
|
||||
stay-open-on-select
|
||||
strategy="fixed"
|
||||
?disabled=${this.disabled}
|
||||
>
|
||||
@ -681,12 +894,28 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
class="tree-dropdown__combobox"
|
||||
slot="anchor"
|
||||
@keydown=${this.handleComboboxKeyDown}
|
||||
@click=${this.handleClick}
|
||||
>
|
||||
<slot part="prefix" name="prefix" class="tree-dropdown__prefix"></slot>
|
||||
<div part="tags" class="tree-dropdown__tags">
|
||||
${this.tagsTemplate()}
|
||||
${this.inputTemplate()}
|
||||
</div>
|
||||
${this.multiple ? this.tagsTemplate() : nothing}
|
||||
${this.inputTemplate()}
|
||||
${hasClearIcon
|
||||
? html`
|
||||
<button
|
||||
part="clear-button"
|
||||
class="select__clear"
|
||||
type="button"
|
||||
aria-label=${this.localize.term('clearEntry')}
|
||||
@mousedown=${this.handleClearMouseDown}
|
||||
@click=${this.handleClearClick}
|
||||
tabindex="-1"
|
||||
>
|
||||
<slot name="clear-icon">
|
||||
<sl-icon name="x-circle-fill" library="system"></sl-icon>
|
||||
</slot>
|
||||
</button>
|
||||
`
|
||||
: ''}
|
||||
<slot part="suffix" name="suffix" class="tree-dropdown__suffix"></slot>
|
||||
<slot name="expand-icon" part="expand-icon" class="tree-dropdown__expand-icon"
|
||||
@click=${this.handleTriggerClick}>
|
||||
@ -702,7 +931,7 @@ export class Et2TreeDropdown extends SearchMixin<Constructor<any> & Et2InputWidg
|
||||
?readonly=${this.readonly}
|
||||
?disabled=${this.disabled}
|
||||
value=${this.multiple ? nothing : this.value}
|
||||
._selectOptions=${this.select_options}
|
||||
._selectOptions=${options}
|
||||
.actions=${this.actions}
|
||||
.styleTemplate=${() => this.styleTemplate()}
|
||||
.autoloading="${this.autoloading}"
|
||||
|
@ -505,6 +505,11 @@ export const SearchMixin = <T extends Constructor<Et2InputWidgetInterface &
|
||||
{
|
||||
this.value = [this.selectedResults[0]?.value] ?? [];
|
||||
}
|
||||
// Dispatch the change event
|
||||
this.updateComplete.then(() =>
|
||||
{
|
||||
this.dispatchEvent(new Event("change", {bubbles: true}));
|
||||
});
|
||||
*/
|
||||
|
||||
this.updateComplete.then(() =>
|
||||
|
@ -3797,6 +3797,8 @@ export class et2_nextmatch_header_bar extends et2_DOMWidget implements et2_INext
|
||||
!select.select_options.filter(option => option.value === '').length)
|
||||
{
|
||||
select.emptyLabel = this.egw().lang('All categories');
|
||||
// requestUpdate because widget is not firing update itself
|
||||
select.requestUpdate("emptyLabel");
|
||||
}
|
||||
select.requestUpdate("value");
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user