From c2127346187cf96f11b80b95d23e80886eca39e6 Mon Sep 17 00:00:00 2001 From: nathan Date: Fri, 27 May 2022 14:12:31 -0600 Subject: [PATCH] Switch Et2Select to be based on Shoelace select instead of LionSelect --- api/js/etemplate/Et2Link/Et2LinkAppSelect.ts | 74 ++++++-------------- api/js/etemplate/Et2Select/Et2Select.ts | 34 +++++---- api/js/etemplate/Styles/shoelace.ts | 16 +++++ 3 files changed, 58 insertions(+), 66 deletions(-) diff --git a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts index 5d14a83d2f..3d93938ed8 100644 --- a/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts +++ b/api/js/etemplate/Et2Link/Et2LinkAppSelect.ts @@ -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` `; } - - 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 diff --git a/api/js/etemplate/Et2Select/Et2Select.ts b/api/js/etemplate/Et2Select/Et2Select.ts index 9be6ac055c..a6605bedcb 100644 --- a/api/js/etemplate/Et2Select/Et2Select.ts +++ b/api/js/etemplate/Et2Select/Et2Select.ts @@ -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 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` - `; + ${this.empty_label}`; } _optionTemplate(option : SelectOption) : TemplateResult { + let icon = option.icon ? html` + ` : ""; + return html` - `; + `; } } @@ -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); } diff --git a/api/js/etemplate/Styles/shoelace.ts b/api/js/etemplate/Styles/shoelace.ts index 2caa22468b..5dc34eeb9f 100644 --- a/api/js/etemplate/Styles/shoelace.ts +++ b/api/js/etemplate/Styles/shoelace.ts @@ -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