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 {css, html, TemplateResult} from "@lion/core";
import {LionOption} from "@lion/select-rich";
import {css, html, SlotMixin, TemplateResult} from "@lion/core";
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()
{
return [
...super.styles,
shoelace,
css`
:host {
--icon-width: 20px;
display: inline-block;
}
:host([app_icons]) {
max-width: 75px;
}
.select__menu {
overflow-x: hidden;
}
::part(control) {
border: none;
@ -24,6 +27,9 @@ export class Et2LinkAppSelect extends Et2Select
et2-image {
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
*/
"app_icons": {type: Boolean}
"app_icons": {type: Boolean, reflect: true}
}
};
@ -52,15 +58,14 @@ export class Et2LinkAppSelect extends Et2Select
{
return {
...super.slots,
input: () =>
"": () =>
{
const select = document.createElement("sl-select");
const icon = document.createElement("et2-image");
icon.setAttribute("slot", "prefix");
icon.setAttribute("src", "api/navbar");
icon.style.width = "var(--icon-width)";
select.appendChild(icon);
return select;
return icon;
}
}
}
@ -75,8 +80,8 @@ export class Et2LinkAppSelect extends Et2Select
constructor()
{
super();
this.__app_icons = true;
this.__application_list = [];
this.app_icons = true;
this.application_list = [];
// Select options are based off abilities registered with link system
this._reset_select_options();
@ -95,13 +100,13 @@ export class Et2LinkAppSelect extends Et2Select
}
}
// Set icon
this._inputNode.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
// Register to
this._inputNode.addEventListener("sl-change", () =>
this.addEventListener("sl-change", () =>
{
// Set icon
this._inputNode.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
this.querySelector("[slot='prefix']").setAttribute("src", this.value + "/navbar");
// update preference
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
* This method will check properties and set select options appropriately
@ -197,20 +179,6 @@ export class Et2LinkAppSelect extends Et2Select
return html`
<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

View File

@ -8,16 +8,20 @@
*/
import {LionSelect} from "@lion/select";
import {css, html, PropertyValues, TemplateResult} from "@lion/core";
import {cssImage} from "../Et2Widget/Et2Widget";
import {StaticOptions} from "./StaticOptions";
import {Et2widgetWithSelectMixin} from "./Et2WidgetWithSelectMixin";
import {SelectOption} from "./FindSelectOptions";
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 class Et2WidgetWithSelect extends Et2widgetWithSelectMixin(LionSelect){};
export class Et2WidgetWithSelect extends Et2widgetWithSelectMixin(SlSelect)
{
};
export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
{
@ -25,6 +29,7 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
{
return [
...super.styles,
shoelace,
css`
:host {
display: block;
@ -98,7 +103,7 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
*/
get _optionTargetNode() : HTMLElement
{
return this._inputNode;
return <HTMLElement><unknown>this;
}
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'))
{
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)
if(this.select_options.length > 0 && this.select_options.filter((option) => modelValueArr.find(val => val == option.value)).length === 0 &&
!(typeof this.empty_label !== 'undefined' && (this.modelValue || "") === ""))
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.value || "") === ""))
{
// --> 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
this.value = this.modelValue || "";
this.value = this.value || "";
}
// propagate multiple to selectbox
if (changedProperties.has('multiple'))
{
this._inputNode.multiple = this.multiple;
// switch the expand button off
if (this.multiple)
{
@ -297,15 +301,19 @@ export class Et2Select extends Et2InvokerMixin(Et2WidgetWithSelect)
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
{
let icon = option.icon ? html`
<et2-image slot="prefix" src="${option.icon}"></et2-image>` : "";
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>`;
</sl-menu-item>`;
}
}
@ -346,7 +354,7 @@ export class Et2SelectBitwise extends Et2Select
expanded_value.push(right);
}
}
this.modelValue = expanded_value;
super.value = expanded_value;
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`,
});
/**
* 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
* External CSS will override this