Switch Et2Select to be based on Shoelace select instead of LionSelect

This commit is contained in:
nathan 2022-05-27 14:12:31 -06:00
parent 0963f7d548
commit c212734618
3 changed files with 58 additions and 66 deletions

View File

@ -1,21 +1,24 @@
import {SelectOption} from "../Et2Select/FindSelectOptions"; import {SelectOption} from "../Et2Select/FindSelectOptions";
import {css, html, TemplateResult} from "@lion/core"; import {css, html, SlotMixin, TemplateResult} from "@lion/core";
import {LionOption} from "@lion/select-rich";
import {Et2Select} from "../Et2Select/Et2Select"; import {Et2Select} from "../Et2Select/Et2Select";
import shoelace from "../Styles/shoelace";
let i : LionOption;
export class Et2LinkAppSelect extends Et2Select export class Et2LinkAppSelect extends SlotMixin(Et2Select)
{ {
static get styles() static get styles()
{ {
return [ return [
...super.styles, ...super.styles,
shoelace,
css` css`
:host { :host {
--icon-width: 20px; --icon-width: 20px;
display: inline-block;
}
:host([app_icons]) {
max-width: 75px;
}
.select__menu {
overflow-x: hidden;
} }
::part(control) { ::part(control) {
border: none; border: none;
@ -24,6 +27,9 @@ export class Et2LinkAppSelect extends Et2Select
et2-image { et2-image {
width: var(--icon-width); width: var(--icon-width);
} }
::slotted(img), img {
vertical-align: middle;
}
` `
] ]
} }
@ -44,7 +50,7 @@ export class Et2LinkAppSelect extends Et2Select
/** /**
* Show application icons instead of application names * Show application icons instead of application names
*/ */
"app_icons": {type: Boolean} "app_icons": {type: Boolean, reflect: true}
} }
}; };
@ -52,15 +58,14 @@ export class Et2LinkAppSelect extends Et2Select
{ {
return { return {
...super.slots, ...super.slots,
input: () => "": () =>
{ {
const select = document.createElement("sl-select");
const icon = document.createElement("et2-image"); const icon = document.createElement("et2-image");
icon.setAttribute("slot", "prefix"); icon.setAttribute("slot", "prefix");
icon.setAttribute("src", "api/navbar"); icon.setAttribute("src", "api/navbar");
icon.style.width = "var(--icon-width)"; icon.style.width = "var(--icon-width)";
select.appendChild(icon); return icon;
return select;
} }
} }
} }
@ -75,8 +80,8 @@ export class Et2LinkAppSelect extends Et2Select
constructor() constructor()
{ {
super(); super();
this.__app_icons = true; this.app_icons = true;
this.__application_list = []; this.application_list = [];
// Select options are based off abilities registered with link system // Select options are based off abilities registered with link system
this._reset_select_options(); this._reset_select_options();
@ -95,13 +100,13 @@ export class Et2LinkAppSelect extends Et2Select
} }
} }
// Set icon // Set icon
this._inputNode.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar"); this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
// Register to // Register to
this._inputNode.addEventListener("sl-change", () => this.addEventListener("sl-change", () =>
{ {
// Set icon // Set icon
this._inputNode.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar"); this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
// update preference // update preference
let appname = ""; let appname = "";
@ -129,29 +134,6 @@ export class Et2LinkAppSelect extends Et2Select
} }
} }
/**
* Get the node where we're putting the selection options
*
* @returns {HTMLElement}
*/
get _optionTargetNode() : HTMLElement
{
return this._inputNode;
}
/**
* Overwritten as sometimes called before this._inputNode is available,
* and our options are text anyway
*
* @param {*} v - modelValue: can be an Object, Number, String depending on the
* input type(date, number, email etc)
* @returns {string} formattedValue
*/
formatter(v)
{
return v;
}
/** /**
* Limited select options here * Limited select options here
* This method will check properties and set select options appropriately * This method will check properties and set select options appropriately
@ -197,20 +179,6 @@ export class Et2LinkAppSelect extends Et2Select
return html` return html`
<et2-image style="width: var(--icon-width)" slot="prefix" src="${url}"></et2-image>`; <et2-image style="width: var(--icon-width)" slot="prefix" src="${url}"></et2-image>`;
} }
set value(new_value)
{
super.value = new_value;
if(this._inputNode)
{
this._inputNode.value = new_value;
}
}
get value()
{
return this._inputNode?.value || "";
}
} }
// @ts-ignore TypeScript is not recognizing that this widget is a LitElement // @ts-ignore TypeScript is not recognizing that this widget is a LitElement

View File

@ -8,16 +8,20 @@
*/ */
import {LionSelect} from "@lion/select";
import {css, html, PropertyValues, TemplateResult} from "@lion/core"; import {css, html, PropertyValues, TemplateResult} from "@lion/core";
import {cssImage} from "../Et2Widget/Et2Widget"; import {cssImage} from "../Et2Widget/Et2Widget";
import {StaticOptions} from "./StaticOptions"; import {StaticOptions} from "./StaticOptions";
import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin"; import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin";
import {SelectOption} from "./FindSelectOptions"; import {SelectOption} from "./FindSelectOptions";
import {Et2InvokerMixin} from "../Et2Url/Et2InvokerMixin"; import {Et2InvokerMixin} from "../Et2Url/Et2InvokerMixin";
import {SlSelect} from "@shoelace-style/shoelace";
import {egw} from "../../jsapi/egw_global";
import shoelace from "../Styles/shoelace";
// export Et2WidgetWithSelect which is used as type in other modules // export Et2WidgetWithSelect which is used as type in other modules
export class Et2WidgetWithSelect extends Et2widgetWithSelectMixin(LionSelect){}; export class Et2WidgetWithSelect extends Et2widgetWithSelectMixin(SlSelect)
{
};
export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect) export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
{ {
@ -25,6 +29,7 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
{ {
return [ return [
...super.styles, ...super.styles,
shoelace,
css` css`
:host { :host {
display: block; display: block;
@ -98,7 +103,7 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
*/ */
get _optionTargetNode() : HTMLElement get _optionTargetNode() : HTMLElement
{ {
return this._inputNode; return <HTMLElement><unknown>this;
} }
static get properties() static get properties()
@ -266,22 +271,21 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
if(changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('empty_label')) if(changedProperties.has('select_options') || changedProperties.has("value") || changedProperties.has('empty_label'))
{ {
const modelValueArr = Array.isArray(this.modelValue) ? this.modelValue : this.modelValue.split(','); const valueArray = Array.isArray(this.value) ? this.value : this.value.split(',');
// value not in options AND NOT (having an empty label and value) // value not in options AND NOT (having an empty label and value)
if(this.select_options.length > 0 && this.select_options.filter((option) => modelValueArr.find(val => val == option.value)).length === 0 && if(this.select_options.length > 0 && this.select_options.filter((option) => valueArray.find(val => val == option.value)).length === 0 &&
!(typeof this.empty_label !== 'undefined' && (this.modelValue || "") === "")) !(typeof this.empty_label !== 'undefined' && (this.value || "") === ""))
{ {
// --> use first option // --> use first option
this.modelValue = "" + this.select_options[0]?.value; // ""+ to cast value of 0 to "0", to not replace with "" this.value = "" + this.select_options[0]?.value; // ""+ to cast value of 0 to "0", to not replace with ""
} }
// Re-set value, the option for it may have just shown up // Re-set value, the option for it may have just shown up
this.value = this.modelValue || ""; this.value = this.value || "";
} }
// propagate multiple to selectbox // propagate multiple to selectbox
if (changedProperties.has('multiple')) if (changedProperties.has('multiple'))
{ {
this._inputNode.multiple = this.multiple;
// switch the expand button off // switch the expand button off
if (this.multiple) if (this.multiple)
{ {
@ -297,15 +301,19 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
return html``; return html``;
} }
return html` return html`
<option value="" ?selected=${!this.modelValue}>${this.empty_label}</option>`; <sl-menu-item value="">${this.empty_label}</sl-menu-item>`;
} }
_optionTemplate(option : SelectOption) : TemplateResult _optionTemplate(option : SelectOption) : TemplateResult
{ {
let icon = option.icon ? html`
<et2-image slot="prefix" src="${option.icon}"></et2-image>` : "";
return html` return html`
<option value="${option.value}" title="${option.title}" ?selected=${option.value == this.modelValue}> <sl-menu-item value="${option.value}" title="${option.title}">
${icon}
${option.label} ${option.label}
</option>`; </sl-menu-item>`;
} }
} }
@ -346,7 +354,7 @@ export class Et2SelectBitwise extends Et2Select
expanded_value.push(right); expanded_value.push(right);
} }
} }
this.modelValue = expanded_value; super.value = expanded_value;
this.requestUpdate("value", oldValue); this.requestUpdate("value", oldValue);
} }

View File

@ -11,6 +11,22 @@ registerIconLibrary('default', {
resolver: name => `${egw.webserverUrl}/node_modules/@shoelace-style/shoelace/dist/assets/icons/${name}.svg`, resolver: name => `${egw.webserverUrl}/node_modules/@shoelace-style/shoelace/dist/assets/icons/${name}.svg`,
}); });
/**
* Override some shoelace icons with EGroupware
*/
const egw_icons = {'chevron-down': 'arrow_down'}
registerIconLibrary("system", {
resolver: (name) =>
{
if(egw_icons[name])
{
return `${egw.webserverUrl}/pixelegg/images/${egw_icons[name]}.svg`;
}
return "";
}
});
/** /**
* Customise shoelace styles to match our stuff * Customise shoelace styles to match our stuff
* External CSS will override this * External CSS will override this