Remove Lion

This commit is contained in:
nathan 2024-05-07 14:46:44 -06:00
parent 2b90e9fc8d
commit ba744d3292
45 changed files with 656 additions and 407 deletions

View File

@ -20,7 +20,7 @@ import {et2_selectbox} from "../../api/js/etemplate/et2_widget_selectbox";
import {fetchAll, nm_action, nm_compare_field} from "../../api/js/etemplate/et2_extension_nextmatch_actions"; import {fetchAll, nm_action, nm_compare_field} from "../../api/js/etemplate/et2_extension_nextmatch_actions";
import "./CRM"; import "./CRM";
import {egw} from "../../api/js/jsapi/egw_global"; import {egw} from "../../api/js/jsapi/egw_global";
import {LitElement} from "@lion/core"; import {LitElement} from "lit";
import {Et2SelectCountry} from "../../api/js/etemplate/Et2Select/Select/Et2SelectCountry"; import {Et2SelectCountry} from "../../api/js/etemplate/Et2Select/Select/Et2SelectCountry";
import {Et2SelectState} from "../../api/js/etemplate/Et2Select/Select/Et2SelectState"; import {Et2SelectState} from "../../api/js/etemplate/Et2Select/Select/Et2SelectState";

View File

@ -17,13 +17,13 @@ import {etemplate2} from "../../api/js/etemplate/etemplate2";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog"; import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
import {egw} from "../../api/js/jsapi/egw_global.js"; import {egw} from "../../api/js/jsapi/egw_global.js";
import {egwAction, egwActionObject} from '../../api/js/egw_action/egw_action'; import {egwAction, egwActionObject} from '../../api/js/egw_action/egw_action';
import {LitElement} from "@lion/core";
import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch"; import {et2_nextmatch} from "../../api/js/etemplate/et2_extension_nextmatch";
import {et2_DOMWidget} from "../../api/js/etemplate/et2_core_DOMWidget"; import {et2_DOMWidget} from "../../api/js/etemplate/et2_core_DOMWidget";
import {Et2SelectAccount} from "../../api/js/etemplate/Et2Select/Select/Et2SelectAccount"; import {Et2SelectAccount} from "../../api/js/etemplate/Et2Select/Select/Et2SelectAccount";
import {EgwAction} from "../../api/js/egw_action/EgwAction"; import {EgwAction} from "../../api/js/egw_action/EgwAction";
import {EgwActionObject} from "../../api/js/egw_action/EgwActionObject"; import {EgwActionObject} from "../../api/js/egw_action/EgwActionObject";
import type {Et2Button} from "../../api/js/etemplate/Et2Button/Et2Button"; import type {Et2Button} from "../../api/js/etemplate/Et2Button/Et2Button";
import {LitElement} from "lit";
/** /**
* UI for Admin * UI for Admin

View File

@ -52,7 +52,6 @@ export class Et2Avatar extends Et2Widget(SlAvatar) implements et2_IDetachedDOM
/** /**
* The label of the image * The label of the image
* Actually not used as label, but we put it as title * Actually not used as label, but we put it as title
* Added here as there's no Lion parent
*/ */
label: { label: {
type: String type: String

View File

@ -9,20 +9,19 @@
*/ */
import {css, html} from "lit"; import {css, html, nothing} from "lit";
import 'lit-flatpickr'; import 'lit-flatpickr';
import {dateStyles} from "./DateStyles"; import {dateStyles} from "./DateStyles";
import type {Instance} from 'flatpickr/dist/types/instance'; import type {Instance} from 'flatpickr/dist/types/instance';
import {default as scrollPlugin} from "flatpickr/dist/plugins/scrollPlugin.js"; import {default as scrollPlugin} from "flatpickr/dist/plugins/scrollPlugin.js";
import {default as ShortcutButtonsPlugin} from "shortcut-buttons-flatpickr/dist/shortcut-buttons-flatpickr"; import {default as ShortcutButtonsPlugin} from "shortcut-buttons-flatpickr/dist/shortcut-buttons-flatpickr.js";
import flatpickr from "flatpickr"; import flatpickr from "flatpickr";
import {egw} from "../../jsapi/egw_global"; import {egw} from "../../jsapi/egw_global";
import type {HTMLElementWithValue} from "@lion/form-core/types/FormControlMixinTypes";
import {Et2Textbox} from "../Et2Textbox/Et2Textbox"; import {Et2Textbox} from "../Et2Textbox/Et2Textbox";
import {FormControlMixin} from "@lion/form-core";
import {LitFlatpickr} from "lit-flatpickr"; import {LitFlatpickr} from "lit-flatpickr";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import shoelace from "../Styles/shoelace"; import shoelace from "../Styles/shoelace";
import {classMap} from "lit/directives/class-map.js";
// list of existing localizations from node_modules/flatpicker/dist/l10n directory: // list of existing localizations from node_modules/flatpicker/dist/l10n directory:
const l10n = [ const l10n = [
@ -224,7 +223,7 @@ export function parseDateTime(dateTimeString)
* Format dates according to user preference * Format dates according to user preference
* *
* @param {Date} date * @param {Date} date
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available * @param [options] Intl options are available
* set 'dateFormat': "Y-m-d" to specify a particular format * set 'dateFormat': "Y-m-d" to specify a particular format
* @returns {string} * @returns {string}
*/ */
@ -261,7 +260,7 @@ export function formatDate(date : Date, options = {dateFormat: ""}) : string
* Format dates according to user preference * Format dates according to user preference
* *
* @param {Date} date * @param {Date} date
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available * @param [options] Intl options are available
* set 'timeFormat': "12" to specify a particular format * set 'timeFormat': "12" to specify a particular format
* @returns {string} * @returns {string}
*/ */
@ -305,8 +304,7 @@ export function formatDateTime(date : Date, options = {dateFormat: "", timeForma
return formatDate(date, options) + " " + formatTime(date, options); return formatDate(date, options) + " " + formatTime(date, options);
} }
// !!! ValidateMixin !!! export class Et2Date extends Et2InputWidget(LitFlatpickr)
export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
{ {
static get styles() static get styles()
{ {
@ -554,7 +552,7 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
options.onChange = this._updateValueOnChange; options.onChange = this._updateValueOnChange;
options.onReady = this._onReady; options.onReady = this._onReady;
// Remove Lion's inert attribute so we can work in Et2Dialog // Remove inert attribute so we can work in Et2Dialog
options.onOpen = [() => options.onOpen = [() =>
{ {
this._instance.calendarContainer?.removeAttribute("inert") this._instance.calendarContainer?.removeAttribute("inert")
@ -968,17 +966,17 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
* This is an et2-textbox, which causes some problems with flatpickr * This is an et2-textbox, which causes some problems with flatpickr
* @protected * @protected
*/ */
get _inputNode() : HTMLElementWithValue get _inputNode() : Et2Textbox
{ {
return this.querySelector('[slot="input"]'); return this.shadowRoot?.querySelector('et2-textbox');
} }
/** /**
* The holder of value for flatpickr * The holder of value for flatpickr
*/ */
get _valueNode() : HTMLElementWithValue get _valueNode() : Et2Textbox
{ {
return this.querySelector('et2-textbox'); return this.shadowRoot?.querySelector('et2-textbox');
} }
/** /**
@ -1037,20 +1035,17 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
this.setDate(date, false, null); this.setDate(date, false, null);
} }
render()
{
return html`
<div part="form-control" class="form-control">
<div class="form-field__group-one" part="form-control-label">${this._groupOneTemplate()}</div>
<div class="form-field__group-two" part="form-control-input">${this._groupTwoTemplate()}</div>
</div>
`;
}
protected _inputGroupInputTemplate() protected _inputTemplate()
{ {
if(typeof egwIsMobile == "function" && egwIsMobile())
{
// Plain input for mobile
return html`<input type=${this._mobileInputType()}></input>`;
}
// This element gets hidden and used for value, but copied by flatpickr and used for input
return html` return html`
<slot name="input"></slot> <et2-textbox type="text" placeholder=${this.placeholder} ?required=${this.required}></et2-textbox>
${this._incrementButtonTemplate()} ${this._incrementButtonTemplate()}
`; `;
} }
@ -1079,6 +1074,32 @@ export class Et2Date extends Et2InputWidget(FormControlMixin(LitFlatpickr))
</et2-button-icon> </et2-button-icon>
</div>`; </div>`;
} }
render()
{
const labelTemplate = this._labelTemplate();
const helpTemplate = this._helpTextTemplate();
return html`
${super.render()}
<div
part="form-control"
class=${classMap({
'form-control': true,
'form-control--medium': true,
'form-control--has-label': labelTemplate !== nothing,
'form-control--has-help-text': helpTemplate !== nothing
})}
>
${labelTemplate}
<div part="form-control-input" class="form-control-input">
${this._inputTemplate()}
</div>
${helpTemplate}
</div>
`;
}
} }
// @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement // @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement

View File

@ -9,12 +9,11 @@
*/ */
import {css, html, LitElement} from "lit"; import {css, html, LitElement, nothing} from "lit";
import {classMap} from "lit/directives/class-map.js"; import {classMap} from "lit/directives/class-map.js";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {sprintf} from "../../egw_action/egw_action_common"; import {sprintf} from "../../egw_action/egw_action_common";
import {dateStyles} from "./DateStyles"; import {dateStyles} from "./DateStyles";
import {FormControlMixin} from "@lion/form-core";
import shoelace from "../Styles/shoelace"; import shoelace from "../Styles/shoelace";
export interface formatOptions export interface formatOptions
@ -112,7 +111,7 @@ export function formatDuration(value : number | string, options : formatOptions)
* If not specified, the time is in assumed to be minutes and will be displayed with a calculated unit * If not specified, the time is in assumed to be minutes and will be displayed with a calculated unit
* but this can be specified with the properties. * but this can be specified with the properties.
*/ */
export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)) export class Et2DateDuration extends Et2InputWidget(LitElement)
{ {
static get styles() static get styles()
{ {
@ -125,7 +124,7 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
max-width: 100%; max-width: 100%;
} }
.input-group { .form-control-input {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: nowrap; flex-wrap: nowrap;
@ -399,35 +398,29 @@ export class Et2DateDuration extends Et2InputWidget(FormControlMixin(LitElement)
render() render()
{ {
return html`
<div part="form-control" class=${classMap({
'form-control': true,
'form-control--has-label': this.label.split("%")[0] || false
})}>
<div class="form-field__group-one form-control__label" part="form-control-label">
${this._groupOneTemplate()}
</div>
<div class="form-field__group-two" part="form-control-input">${this._groupTwoTemplate()}</div>
</div>
`;
}
/** const labelTemplate = this._labelTemplate();
* @return {TemplateResult} const helpTemplate = this._helpTextTemplate();
* @protected
*/
// eslint-disable-next-line class-methods-use-this
_inputGroupInputTemplate()
{
return html` return html`
<div class="input-group__input" @sl-change=${() => <div
{ part="form-control"
this.dispatchEvent(new Event("change", {bubbles: true})); class=${classMap({
}}> 'form-control': true,
<slot name="input"> 'form-control--medium': true,
'form-control--has-label': labelTemplate !== nothing,
'form-control--has-help-text': helpTemplate !== nothing
})}
>
${labelTemplate}
<div part="form-control-input" class="form-control-input" @sl-change=${() =>
{
this.dispatchEvent(new Event("change", {bubbles: true}));
}}>
${this._inputTemplate()} ${this._inputTemplate()}
${this._formatTemplate()} ${this._formatTemplate()}
</slot> </div>
${helpTemplate}
</div> </div>
`; `;
} }

View File

@ -1,5 +1,4 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {FormControlMixin} from "@lion/form-core";
import {css, html, LitElement, TemplateResult} from "lit"; import {css, html, LitElement, TemplateResult} from "lit";
import {classMap} from "lit/directives/class-map.js"; import {classMap} from "lit/directives/class-map.js";
import {ifDefined} from "lit/directives/if-defined.js"; import {ifDefined} from "lit/directives/if-defined.js";
@ -14,7 +13,7 @@ import {egw} from "../../jsapi/egw_global";
* If not specified, the time is in assumed to be minutes and will be displayed with a calculated unit * If not specified, the time is in assumed to be minutes and will be displayed with a calculated unit
* but this can be specified with the properties. * but this can be specified with the properties.
*/ */
export class Et2DateRange extends Et2InputWidget(FormControlMixin(LitElement)) export class Et2DateRange extends Et2InputWidget(LitElement)
{ {
static get styles() static get styles()
{ {

View File

@ -28,7 +28,6 @@ export class Et2DateTimeToday extends Et2DateReadonly
* If the date is today, we show just the time. Otherwise, the date. * If the date is today, we show just the time. Otherwise, the date.
* *
* @param {Date} date * @param {Date} date
* @param {import('@lion/localize/types/LocalizeMixinTypes').FormatDateOptions} [options] Intl options are available
* @returns {string} * @returns {string}
*/ */
formatDateTime(date : Date, options = {dateFormat: "", timeFormat: ""}) : string formatDateTime(date : Date, options = {dateFormat: "", timeFormat: ""}) : string

View File

@ -15,7 +15,6 @@ import {classMap} from "lit/directives/class-map.js";
import {ifDefined} from "lit/directives/if-defined.js"; import {ifDefined} from "lit/directives/if-defined.js";
import {repeat} from "lit/directives/repeat.js"; import {repeat} from "lit/directives/repeat.js";
import {styleMap} from "lit/directives/style-map.js"; import {styleMap} from "lit/directives/style-map.js";
import {SlotMixin} from "@lion/core";
import {et2_template} from "../et2_widget_template"; import {et2_template} from "../et2_widget_template";
import type {etemplate2} from "../etemplate2"; import type {etemplate2} from "../etemplate2";
import {egw, IegwAppLocal} from "../../jsapi/egw_global"; import {egw, IegwAppLocal} from "../../jsapi/egw_global";
@ -126,7 +125,7 @@ export interface DialogButton
* *
* Customize initial focus by setting the "autofocus" attribute on a control, otherwise first input will have focus * Customize initial focus by setting the "autofocus" attribute on a control, otherwise first input will have focus
*/ */
export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog)) export class Et2Dialog extends Et2Widget(SlDialog)
{ {
/** /**
* Dialogs don't always get added to an etemplate, so we keep our own egw * Dialogs don't always get added to an etemplate, so we keep our own egw
@ -334,21 +333,6 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
} }
} }
get slots()
{
return {
...super.slots,
'': () =>
{
// to fix problem with Safari 16.2 of NOT displaying the content, we have to use the following,
// instead of just return this._contentTemplate()
let div = document.createElement("div");
render(this._contentTemplate(), div);
return div.children[0];
}
}
}
/* /*
* List of properties that get translated * List of properties that get translated
* Done separately to not interfere with properties - if we re-define label property, * Done separately to not interfere with properties - if we re-define label property,
@ -525,9 +509,11 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
} }
} }
firstUpdated() firstUpdated(changedProperties)
{ {
super.firstUpdated(); super.firstUpdated(changedProperties);
render(this._contentTemplate(), this);
// If we start open, fire handler to get setup done // If we start open, fire handler to get setup done
if(this.open) if(this.open)
@ -764,7 +750,7 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
} }
if(changedProperties.has("buttons")) if(changedProperties.has("buttons"))
{ {
render(this._buttonsTemplate(), this); //render(this._buttonsTemplate(), this);
this.requestUpdate(); this.requestUpdate();
} }
if(changedProperties.has("width")) if(changedProperties.has("width"))
@ -904,7 +890,7 @@ export class Et2Dialog extends Et2Widget(SlotMixin(SlDialog))
<slot>${this.message}</slot>` <slot>${this.message}</slot>`
} }
</div>`; </div>${this._buttonsTemplate()}`;
} }

View File

@ -24,7 +24,6 @@ import {waitForEvent} from "../Et2Widget/event";
import styles from "./Et2Email.styles"; import styles from "./Et2Email.styles";
import {SelectOption} from "../Et2Select/FindSelectOptions"; import {SelectOption} from "../Et2Select/FindSelectOptions";
import {IsEmail} from "../Validators/IsEmail"; import {IsEmail} from "../Validators/IsEmail";
import {Validator} from "@lion/form-core";
import Sortable from "sortablejs/modular/sortable.complete.esm.js"; import Sortable from "sortablejs/modular/sortable.complete.esm.js";
import {SearchMixinInterface} from "../Et2Widget/SearchMixin"; import {SearchMixinInterface} from "../Et2Widget/SearchMixin";

View File

@ -186,7 +186,7 @@ export class Et2Favorites extends Et2DropdownButton implements et2_INextmatchHea
} }
/** @param {import('@lion/core').PropertyValues } changedProperties */ /** @param changedProperties */
updated(changedProperties : PropertyValues) updated(changedProperties : PropertyValues)
{ {
super.updated(changedProperties); super.updated(changedProperties);

View File

@ -10,10 +10,9 @@
import {css, html, LitElement} from "lit"; import {css, html, LitElement} from "lit";
import {SlotMixin} from "@lion/core";
import {Et2Widget} from "../Et2Widget/Et2Widget"; import {Et2Widget} from "../Et2Widget/Et2Widget";
export class Et2Iframe extends Et2Widget(SlotMixin(LitElement)) export class Et2Iframe extends Et2Widget(LitElement)
{ {
static get styles() static get styles()

View File

@ -29,4 +29,5 @@ export class Et2AppIcon extends Et2Image
return super.parse_href(src); return super.parse_href(src);
} }
} }
customElements.define("et2-appicon", Et2AppIcon as any, {extends: 'img'});
customElements.define("et2-appicon", Et2AppIcon as any);

View File

@ -9,29 +9,29 @@
*/ */
import {css, html, LitElement, render} from "lit"; import {css, html, LitElement, render} from "lit";
import {SlotMixin} from "@lion/core";
import {Et2Widget} from "../Et2Widget/Et2Widget"; import {Et2Widget} from "../Et2Widget/Et2Widget";
import {et2_IDetachedDOM} from "../et2_core_interfaces"; import {et2_IDetachedDOM} from "../et2_core_interfaces";
export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_IDetachedDOM export class Et2Image extends Et2Widget(LitElement) implements et2_IDetachedDOM
{ {
static get styles() static get styles()
{ {
return [ return [
...super.styles, ...super.styles,
css` css`
:host { :host {
display: inline-block; display: inline-block;
} }
::slotted(img) {
max-height: 100%; ::slotted(img) {
max-width: 100%; max-height: 100%;
} max-width: 100%;
:host([icon]) { }
height: 1.3rem;
} :host([icon]) {
`, height: 1.3rem;
]; }
`];
} }
static get properties() static get properties()
@ -42,7 +42,6 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
/** /**
* The label of the image * The label of the image
* Actually not used as label, but we put it as title * Actually not used as label, but we put it as title
* Added here as there's no Lion parent
*/ */
label: { label: {
type: String type: String
@ -80,16 +79,6 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
} }
} }
get slots()
{
return {
'': () =>
{
return this._imageTemplate();
}
}
}
constructor() constructor()
{ {
super(); super();
@ -248,4 +237,4 @@ export class Et2Image extends Et2Widget(SlotMixin(LitElement)) implements et2_ID
} }
} }
customElements.define("et2-image", Et2Image, {extends: 'img'}); customElements.define("et2-image", Et2Image)//, {extends: 'img'});

View File

@ -1,15 +1,15 @@
import {css, html, LitElement, nothing, PropertyValues, TemplateResult} from "lit";
import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "../et2_core_interfaces"; import {et2_IInput, et2_IInputNode, et2_ISubmitListener} from "../et2_core_interfaces";
import {Et2Widget} from "../Et2Widget/Et2Widget"; import {Et2Widget} from "../Et2Widget/Et2Widget";
import {css, LitElement, PropertyValues} from "lit"; import {HasSlotController} from "../Et2Widget/slot";
import {Required} from "../Validators/Required";
import {ManualMessage} from "../Validators/ManualMessage";
import {LionValidationFeedback, Validator} from "@lion/form-core";
import {et2_csvSplit} from "../et2_core_common"; import {et2_csvSplit} from "../et2_core_common";
import {dedupeMixin} from "@lion/core";
import {property} from "lit/decorators/property.js"; import {property} from "lit/decorators/property.js";
import {Validator} from "../Validators/Validator";
import {ManualMessage} from "../Validators/ManualMessage";
import {Required} from "../Validators/Required";
import {EgwValidationFeedback} from "../Validators/EgwValidationFeedback";
import {dedupeMixin} from "@open-wc/dedupe-mixin";
// LionValidationFeedback needs to be registered manually
window.customElements.define('lion-validation-feedback', LionValidationFeedback);
/** /**
* This mixin will allow any LitElement to become an Et2InputWidget * This mixin will allow any LitElement to become an Et2InputWidget
@ -69,6 +69,9 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
protected isSlComponent = false; protected isSlComponent = false;
// Allows us to check to see if label or help-text is set. Override to check additional slots.
protected readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
/** WebComponent **/ /** WebComponent **/
static get styles() static get styles()
{ {
@ -95,6 +98,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
.form-control__help-text { .form-control__help-text {
position: relative; position: relative;
width: 100%;
} }
` `
]; ];
@ -111,11 +115,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
label: { label: {
type: String, noAccessor: true type: String, noAccessor: true
}, },
// readOnly is what the property is in Lion, readonly is the attribute
readOnly: {
type: Boolean,
attribute: 'readonly',
},
// readonly is what is in the templates // readonly is what is in the templates
// I put this in here so loadWebComponent finds it when it tries to set it from the template // I put this in here so loadWebComponent finds it when it tries to set it from the template
readonly: { readonly: {
@ -341,7 +341,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
this.updateComplete.then(() => this.updateComplete.then(() =>
{ {
// Remove all messages. Manual will be explicitly replaced, other validators will be re-run on blur. // Remove all messages. Manual will be explicitly replaced, other validators will be re-run on blur.
this.querySelectorAll("lion-validation-feedback").forEach(e => e.remove()); this.querySelectorAll("egw-validation-feedback").forEach(e => e.remove());
}); });
} }
@ -400,6 +400,11 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
return this.__readonly; return this.__readonly;
} }
/**
* Was from early days (Lion)
* @deprecated
* @param {boolean} new_value
*/
set readOnly(new_value) set readOnly(new_value)
{ {
this.readonly = new_value; this.readonly = new_value;
@ -582,7 +587,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
let fieldName = this.id; let fieldName = this.id;
let feedbackData = []; let feedbackData = [];
let resultPromises = []; let resultPromises = [];
this.querySelector("lion-validation-feedback")?.remove(); (<EgwValidationFeedback>this.querySelector("egw-validation-feedback"))?.remove();
// Collect message of a (failing) validator // Collect message of a (failing) validator
const doValidate = async function(validator, value) const doValidate = async function(validator, value)
@ -653,7 +658,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
// Show feedback from all failing validators // Show feedback from all failing validators
if(feedbackData.length > 0) if(feedbackData.length > 0)
{ {
let feedback = <LionValidationFeedback>document.createElement("lion-validation-feedback"); let feedback = document.createElement("egw-validation-feedback");
feedback.feedbackData = feedbackData; feedback.feedbackData = feedbackData;
feedback.slot = "help-text"; feedback.slot = "help-text";
this.append(feedback); this.append(feedback);
@ -719,7 +724,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
*/ */
public get hasFeedbackFor() : string[] public get hasFeedbackFor() : string[]
{ {
let feedback = (<LionValidationFeedback>this.querySelector("lion-validation-feedback"))?.feedbackData || []; let feedback = (this.querySelector("egw-validation-feedback"))?.feedbackData || [];
return feedback.map((f) => f.type); return feedback.map((f) => f.type);
} }
@ -734,7 +739,7 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
{ {
this.submitted = true; this.submitted = true;
// If using Lion validators, run them now // If using validators, run them now
if(this.validate) if(this.validate)
{ {
// Force update now // Force update now
@ -745,6 +750,47 @@ const Et2InputWidgetMixin = <T extends Constructor<LitElement>>(superclass : T)
} }
return true; return true;
} }
/**
* Common sub-template to add a label.
* This goes inside the form control wrapper div, before and at the same depth as the input controls.
*
*
* @returns {TemplateResult} Either a TemplateResult or nothing (the object). Check for nothing to set
* 'form-control--has-label' class on the wrapper div.
* @protected
*/
protected _labelTemplate() : TemplateResult | typeof nothing
{
const hasLabelSlot = this.hasSlotController?.test('label');
const hasLabel = this.label ? true : !!hasLabelSlot;
return hasLabel ? html`
<label
id="label"
part="form-control-label"
class="form-control__label"
aria-hidden=${hasLabel ? 'false' : 'true'}
@click=${typeof this.handleLabelClick == "function" ? this.handleLabelClick : nothing}
>
<slot name="label">${this.label}</slot>
</label>
` : nothing;
}
protected _helpTextTemplate() : TemplateResult | typeof nothing
{
const hasHelpTextSlot = this.hasSlotController?.test('help-text');
const hasHelpText = this.helpText ? true : !!hasHelpTextSlot;
return hasHelpText ? html`
<div
part="form-control-help-text"
id="help-text"
class="form-control__help-text"
aria-hidden=${hasHelpText ? 'false' : 'true'}
>
<slot name="help-text">${this.helpText}</slot>
</div>` : nothing;
}
} }
return Et2InputWidgetClass as Constructor & T; return Et2InputWidgetClass as Constructor & T;

View File

@ -1,7 +1,5 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {css, html, LitElement, PropertyValues} from "lit"; import {css, html, LitElement, PropertyValues} from "lit";
import {FormControlMixin, ValidateMixin} from "@lion/form-core";
import {SlotMixin} from "@lion/core";
import {Et2LinkAppSelect} from "./Et2LinkAppSelect"; import {Et2LinkAppSelect} from "./Et2LinkAppSelect";
import {LinkInfo} from "./Et2Link"; import {LinkInfo} from "./Et2Link";
import {Et2Button} from "../Et2Button/Et2Button"; import {Et2Button} from "../Et2Button/Et2Button";
@ -11,7 +9,7 @@ import {Et2Button} from "../Et2Button/Et2Button";
* *
* *
*/ */
export class Et2LinkAdd extends Et2InputWidget(FormControlMixin(ValidateMixin(SlotMixin(LitElement)))) export class Et2LinkAdd extends Et2InputWidget(LitElement)
{ {
static get styles() static get styles()
{ {

View File

@ -6,37 +6,38 @@
* @link https://www.egroupware.org * @link https://www.egroupware.org
* @author Nathan Gray * @author Nathan Gray
*/ */
import {css, html, LitElement, PropertyValues} from "lit"; import {css, html, LitElement, nothing} from "lit";
import {SlotMixin} from "@lion/core"; import {classMap} from "lit/directives/class-map.js";
import {Et2LinkAppSelect} from "./Et2LinkAppSelect"; import {Et2LinkAppSelect} from "./Et2LinkAppSelect";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {FormControlMixin} from "@lion/form-core";
import {Et2LinkSearch} from "./Et2LinkSearch"; import {Et2LinkSearch} from "./Et2LinkSearch";
import {Et2Link, LinkInfo} from "./Et2Link"; import {Et2Link, LinkInfo} from "./Et2Link";
import {HasSlotController} from "../Et2Widget/slot";
/** /**
* Find and select a single entry using the link system. * Find and select a single entry using the link system.
* *
* *
*/ */
export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitElement))) export class Et2LinkEntry extends Et2InputWidget(LitElement)
{ {
static get styles() static get styles()
{ {
return [ return [
...super.styles, ...super.styles,
css` css`
:host { :host {
display: block; display: block;
} }
:host(.hideApp) ::slotted([slot="app"]) { :host(.hideApp) ::slotted([slot="app"]) {
display: none; display: none;
} }
.input-group__input { .form-control-input {
gap: 0.5rem; display: flex;
} gap: 0.5rem;
}
` `
]; ];
@ -83,52 +84,17 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
} }
} }
get slots()
{
return {
...super.slots,
app: () =>
{
const app = <Et2LinkAppSelect>document.createElement("et2-link-apps")
if(this.__onlyApp)
{
app.onlyApp = this.__onlyApp;
}
else if(typeof this._value !== "undefined" && this._value.app)
{
app.value = this._value.app;
}
return app;
},
select: () =>
{
const select = <Et2LinkSearch><unknown>document.createElement("et2-link-search");
if(typeof this._value !== "undefined" && this._value.id)
{
if(this._value.title)
{
select.select_options = [{value: this._value.id, label: this._value.title}]
}
select.app = this._value.app;
select.value = this._value.id;
}
return select;
}
}
}
/** /**
* We only care about this value until render. After the sub-nodes are created, * We only care about this value until render. After the sub-nodes are created,
* we take their "live" values for our value. * we take their "live" values for our value.
* *
* N.B.: Single underscore! Otherwise we conflict with parent __value
*
* @type {LinkInfo} * @type {LinkInfo}
* @private * @private
*/ */
private _value : LinkInfo; private __value : LinkInfo = {app: "", id: ""};
protected __onlyApp : string; protected __onlyApp : string;
protected readonly hasSlotController = new HasSlotController(this, 'help-text', 'label');
constructor() constructor()
{ {
@ -139,18 +105,18 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
{ {
super.connectedCallback(); super.connectedCallback();
this._handleAppChange = this._handleAppChange.bind(this);
this._handleEntrySelect = this._handleEntrySelect.bind(this);
this._handleEntryClear = this._handleEntryClear.bind(this);
this._handleShow = this._handleShow.bind(this); this._handleShow = this._handleShow.bind(this);
this._handleHide = this._handleHide.bind(this); this._handleHide = this._handleHide.bind(this);
// Clear initial value // Clear initial value
this._value = undefined; this.__value = undefined;
if(!this.readonly) if(!this.readonly)
{ {
this._bindListeners(); this.updateComplete.then(() =>
{
this._bindListeners();
});
} }
} }
@ -160,41 +126,14 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
this._unbindListeners(); this._unbindListeners();
} }
updated(changedProperties : PropertyValues)
{
super.updated(changedProperties);
if(changedProperties.has("required"))
{
this._searchNode.required = this.required;
}
if(changedProperties.has("readonly"))
{
this._appNode.readonly = this._appNode.disabled = this.readonly;
this._searchNode.readonly = this.readonly;
}
// Pass some properties on to app selection
if(changedProperties.has("onlyApp"))
{
this._appNode.onlyApp = this.onlyApp;
}
if(changedProperties.has("applicationList"))
{
this._appNode.applicationList = this.applicationList;
}
if(changedProperties.has("appIcons"))
{
this._appNode.appIcons = this.appIcons;
}
}
set onlyApp(app) set onlyApp(app)
{ {
this.__onlyApp = app || ""; this.__onlyApp = app || "";
// If initial value got set before onlyApp, it still needs app in pre-render value // If initial value got set before onlyApp, it still needs app in pre-render value
if(this._value && app) if(this.__value && app)
{ {
this._value.app = this.__onlyApp; this.__value.app = this.__onlyApp;
} }
if(app) if(app)
{ {
@ -213,16 +152,20 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
set app(app) set app(app)
{ {
this.updateComplete.then(() => if(typeof this.__value !== "object" || this.__value == null)
{ {
this._appNode.value = app; this.__value = <LinkInfo>{app: app}
this._searchNode.app = app; }
}); else
{
this.__value.app = app;
}
this.requestUpdate("value");
} }
get app() get app()
{ {
return this._appNode?.value || ""; return this.__value?.app || "";
} }
set searchOptions(options) set searchOptions(options)
@ -240,12 +183,12 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
get _appNode() : Et2LinkAppSelect get _appNode() : Et2LinkAppSelect
{ {
return this.querySelector("[slot='app']"); return this.shadowRoot?.querySelector("et2-link-apps");
} }
get _searchNode() : Et2LinkSearch get _searchNode() : Et2LinkSearch
{ {
return this.querySelector("[slot='select']"); return <Et2LinkSearch>this.shadowRoot?.querySelector("et2-link-search");
} }
get placeholder() : string get placeholder() : string
@ -263,48 +206,32 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
protected _bindListeners() protected _bindListeners()
{ {
this._appNode.addEventListener("change", this._handleAppChange);
this._searchNode.addEventListener("change", this._handleEntrySelect);
this._searchNode.addEventListener("sl-clear", this._handleEntryClear);
this.addEventListener("sl-show", this._handleShow); this.addEventListener("sl-show", this._handleShow);
this.addEventListener("sl-hide", this._handleHide); this.addEventListener("sl-hide", this._handleHide);
} }
protected _unbindListeners() protected _unbindListeners()
{ {
this._appNode.removeEventListener("change", this._handleAppChange);
this.removeEventListener("sl-select", this._handleEntrySelect);
this.removeEventListener("sl-clear", this._handleEntryClear);
this.removeEventListener("sl-show", this._handleShow); this.removeEventListener("sl-show", this._handleShow);
this.removeEventListener("sl-hide", this._handleHide); this.removeEventListener("sl-hide", this._handleHide);
} }
/**
* Update the search node's app & clear selected value when
* selected app changes.
* @param event
* @protected
*/
protected _handleAppChange(event)
{
this._searchNode.app = this._appNode.value;
this._searchNode.value = "";
this._searchNode.clearSearch();
this._searchNode.focus();
this.requestUpdate('value');
}
/** /**
* Hide app selection when there's an entry * Hide app selection when there's an entry
* @param event * @param event
* @protected * @protected
*/ */
protected _handleEntrySelect(event) protected handleEntrySelect(event)
{ {
event.stopPropagation(); event.stopPropagation();
this.value = <string>this._searchNode.value ?? "";
this.classList.toggle("hideApp", Boolean(typeof this.value == "object" ? this.value?.id : this.value)); this.classList.toggle("hideApp", Boolean(typeof this.value == "object" ? this.value?.id : this.value));
this.dispatchEvent(new Event("change"));
this.updateComplete.then(() =>
{
this.dispatchEvent(new Event("change"));
});
this.requestUpdate('value'); this.requestUpdate('value');
this.validate(); this.validate();
@ -316,13 +243,17 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
* @param event * @param event
* @protected * @protected
*/ */
protected _handleEntryClear(event) protected handleEntryClear(event)
{ {
this.value = ""
this.classList.remove("hideApp") this.classList.remove("hideApp")
this._searchNode.value = ""; this._searchNode.value = "";
this._searchNode.focus(); this._searchNode.focus();
this.dispatchEvent(new Event("change")); this.updateComplete.then(() =>
{
this.dispatchEvent(new Event("change"));
});
this.requestUpdate('value'); this.requestUpdate('value');
this.validate(); this.validate();
@ -362,16 +293,12 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
{ {
return <string>this._searchNode?.value ?? ""; return <string>this._searchNode?.value ?? "";
} }
return this._searchNode ? <LinkInfo>{ return this.__value;
id: this._searchNode.value,
app: this.app,
//search: this._searchNode... // content of search field
} : this._value;
} }
set value(val : LinkInfo | string | number) set value(val : LinkInfo | string | number)
{ {
let value : LinkInfo = {app: this.onlyApp || this.app, id: ""}; let value : LinkInfo = {app: this.onlyApp || (this.app || this._appNode?.value), id: ""};
if(typeof val === 'string' && val.length > 0) if(typeof val === 'string' && val.length > 0)
{ {
@ -399,30 +326,79 @@ export class Et2LinkEntry extends Et2InputWidget(FormControlMixin(SlotMixin(LitE
value = (<LinkInfo>val); value = (<LinkInfo>val);
} }
// If the searchNode is not there yet, hold value. We'll use these values when we create the const oldValue = this.__value;
// slotted searchNode. this.__value = value;
if(this._searchNode == null)
{ this.classList.toggle("hideApp", Boolean(this.__value.id));
this._value = value; this.requestUpdate("value", oldValue);
}
else
{
this.app = this._searchNode.app = value.app;
this._searchNode.value = value.id;
}
this.classList.toggle("hideApp", Boolean(value.id));
} }
protected handleLabelClick()
{
this._searchNode.focus();
}
/** /**
* @return {TemplateResult} * Update the search node's app & clear selected value when
* selected app changes.
* @param event
* @protected * @protected
*/ */
_inputGroupInputTemplate() protected handleAppChange(e)
{ {
this.app = this._appNode.value;
this._searchNode.app = this._appNode.value;
this._searchNode.value = "";
this._searchNode.clearSearch();
this._searchNode.focus();
this.requestUpdate('value');
}
render()
{
const labelTemplate = this._labelTemplate();
const helpTemplate = this._helpTextTemplate();
return html` return html`
<div class="input-group__input" part="control"> <div
<slot name="app"></slot> part="form-control"
<slot name="select"></slot> class=${classMap({
'form-control': true,
'form-control--medium': true,
'form-control--has-label': labelTemplate !== nothing,
'form-control--has-help-text': helpTemplate !== nothing
})}
>
${labelTemplate}
<div part="form-control-input" class="form-control-input">
<et2-link-apps
onlyApp=${this.onlyApp ? this.onlyApp : nothing}
?appIcons=${this.appIcons}
?applicationList=${this.applicationList}
?disabled=${this.disabled}
?readonly=${this.disabled}
.value=${this.__value?.app ? this.__value.app : nothing}
@change=${this.handleAppChange}
></et2-link-apps>
<et2-link-search
?placeholder=${this.placeholder}
?required=${this.required}
?disabled=${this.disabled}
?readonly=${this.readonly}
.app=${this.__value?.app || nothing}
.value=${this.__value?.id || nothing}
@change=${this.handleEntrySelect}
@sl-clear=${this.handleEntryClear}
>
${(this.__value?.title) ? html`
<option value=${this.__value.id}>${this.__value.title}</option>
` : nothing}
</et2-link-search>
</div>
${helpTemplate}
</div> </div>
`; `;
} }

View File

@ -335,5 +335,4 @@ export class Et2LinkString extends Et2Widget(LitElement) implements et2_IDetache
} }
}; };
// @ts-ignore TypeScript says there's something wrong with types customElements.define("et2-link-string", Et2LinkString);
customElements.define("et2-link-string", Et2LinkString, {extends: 'ul'});

View File

@ -11,21 +11,19 @@
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import {FormControlMixin, ValidateMixin} from "@lion/form-core";
import {css, html, LitElement, nothing} from "lit"; import {css, html, LitElement, nothing} from "lit";
import {ScopedElementsMixin} from "@lion/core";
import {et2_createWidget, et2_widget} from "../et2_core_widget"; import {et2_createWidget, et2_widget} from "../et2_core_widget";
import {et2_file} from "../et2_widget_file"; import {et2_file} from "../et2_widget_file";
import {Et2Button} from "../Et2Button/Et2Button"; import {Et2Button} from "../Et2Button/Et2Button";
import {Et2LinkEntry} from "./Et2LinkEntry"; import {Et2LinkEntry} from "./Et2LinkEntry";
import {egw} from "../../jsapi/egw_global"; import {egw} from "../../jsapi/egw_global";
import {LinkInfo} from "./Et2Link"; import {LinkInfo} from "./Et2Link";
import type {ValidationType} from "@lion/form-core/types/validate/ValidateMixinTypes";
import {ManualMessage} from "../Validators/ManualMessage"; import {ManualMessage} from "../Validators/ManualMessage";
import {Et2Tabs} from "../Layout/Et2Tabs/Et2Tabs"; import {Et2Tabs} from "../Layout/Et2Tabs/Et2Tabs";
import {Et2VfsSelectButton} from "../Et2Vfs/Et2VfsSelectButton"; import {Et2VfsSelectButton} from "../Et2Vfs/Et2VfsSelectButton";
import {Et2LinkPasteDialog, getClipboardFiles} from "./Et2LinkPasteDialog"; import {Et2LinkPasteDialog, getClipboardFiles} from "./Et2LinkPasteDialog";
import {waitForEvent} from "../Et2Widget/event"; import {waitForEvent} from "../Et2Widget/event";
import {classMap} from "lit/directives/class-map.js";
/** /**
* Choose an existing entry, VFS file or local file, and link it to the current entry. * Choose an existing entry, VFS file or local file, and link it to the current entry.
@ -33,7 +31,7 @@ import {waitForEvent} from "../Et2Widget/event";
* If there is no "current entry", link information will be stored for submission instead * If there is no "current entry", link information will be stored for submission instead
* of being directly linked. * of being directly linked.
*/ */
export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMixin(ValidateMixin(LitElement)))) export class Et2LinkTo extends Et2InputWidget(LitElement)
{ {
static get properties() static get properties()
{ {
@ -73,15 +71,12 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
.input-group__container { .input-group__container {
flex: 1 1 auto; flex: 1 1 auto;
} }
.input-group {
.form-control-input {
display: flex; display: flex;
width: 100%; width: 100%;
gap: 0.5rem; gap: 0.5rem;
} }
.input-group__before {
display: flex;
gap: 0.5rem;
}
::slotted(.et2_file) { ::slotted(.et2_file) {
width: 30px; width: 30px;
} }
@ -160,13 +155,17 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
return html` return html`
<slot name="before"></slot> <slot name="before"></slot>
<et2-vfs-select <et2-vfs-select
id="link"
?readonly=${this.readonly} ?readonly=${this.readonly}
method=${method || nothing} method=${method || nothing}
method-id=${method_id || nothing} method-id=${method_id || nothing}
multiple multiple
title=${this.egw().lang("select file(s) from vfs")} title=${this.egw().lang("select file(s) from vfs")}
.buttonLabel=${this.egw().lang('Link')} .buttonLabel=${this.egw().lang('Link')}
.onchange=${this.handleVfsSelected} @change=${async() =>
{
this.handleVfsSelected(await this.shadowRoot.getElementById("link")._dialog.getComplete());
}}
> >
<et2-button slot="footer" image="copy" id="copy" style="order:3" noSubmit="true" <et2-button slot="footer" image="copy" id="copy" style="order:3" noSubmit="true"
label=${this.egw().lang("copy")}></et2-button> label=${this.egw().lang("copy")}></et2-button>
@ -586,6 +585,35 @@ export class Et2LinkTo extends Et2InputWidget(ScopedElementsMixin(FormControlMix
{ {
return ['error', 'success']; return ['error', 'success'];
} }
render()
{
const labelTemplate = this._labelTemplate();
const helpTemplate = this._helpTextTemplate();
return html`
<div
part="form-control"
class=${classMap({
'form-control': true,
'form-control--medium': true,
'form-control--has-label': labelTemplate !== nothing,
'form-control--has-help-text': helpTemplate !== nothing
})}
>
${labelTemplate}
<div part="form-control-input" class="form-control-input" @sl-change=${() =>
{
this.dispatchEvent(new Event("change", {bubbles: true}));
}}>
${this._inputGroupBeforeTemplate()}
${this._inputGroupInputTemplate()}
</div>
${helpTemplate}
</div>
`;
}
} }
// @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

@ -546,7 +546,7 @@ export class Et2Select extends Et2WithSearchMixin(Et2WidgetWithSelect)
this.updateComplete.then(() => this.fix_bad_value()); this.updateComplete.then(() => this.fix_bad_value());
} }
/** @param {import('@lion/core').PropertyValues } changedProperties */ /** @param changedProperties */
willUpdate(changedProperties : PropertyValues) willUpdate(changedProperties : PropertyValues)
{ {
super.willUpdate(changedProperties); super.willUpdate(changedProperties);

View File

@ -44,7 +44,6 @@ import {SearchMixinInterface} from "../Et2Widget/SearchMixin";
* *
* Optionally, you can override: * Optionally, you can override:
* - _emptyLabelTemplate(): How to render the empty label * - _emptyLabelTemplate(): How to render the empty label
* - slots(): Most Lion components have an input slot where the <input> tag is created.
* You can specify something else, or return {} to do your own thing. This is a little more complicated. You should * You can specify something else, or return {} to do your own thing. This is a little more complicated. You should
* also override _inputGroupInputTemplate() to do what you normally would in render(). * also override _inputGroupInputTemplate() to do what you normally would in render().
* *

View File

@ -9,7 +9,6 @@
import {css, CSSResultGroup, html, LitElement, nothing, TemplateResult} from "lit"; import {css, CSSResultGroup, html, LitElement, nothing, TemplateResult} from "lit";
import {cleanSelectOptions, SelectOption} from "./FindSelectOptions"; import {cleanSelectOptions, SelectOption} from "./FindSelectOptions";
import {Validator} from "@lion/form-core";
import {Et2Tag} from "./Tag/Et2Tag"; import {Et2Tag} from "./Tag/Et2Tag";
import {StaticOptions} from "./StaticOptions"; import {StaticOptions} from "./StaticOptions";
import {dedupeMixin} from "@open-wc/dedupe-mixin"; import {dedupeMixin} from "@open-wc/dedupe-mixin";
@ -17,6 +16,7 @@ import {SlOption} from "@shoelace-style/shoelace";
import {Et2Textbox} from "../Et2Textbox/Et2Textbox"; import {Et2Textbox} from "../Et2Textbox/Et2Textbox";
import {until} from "lit/directives/until.js"; import {until} from "lit/directives/until.js";
import {waitForEvent} from "../Et2Widget/event"; import {waitForEvent} from "../Et2Widget/event";
import {Validator} from "../Validators/Validator";
// Otherwise import gets stripped // Otherwise import gets stripped
let keep_import : Et2Tag; let keep_import : Et2Tag;

View File

@ -8,8 +8,7 @@
* @author Hadi Nategh * @author Hadi Nategh
*/ */
import {css, html} from "lit"; import {css, html, render} from "lit";
import {SlotMixin} from "@lion/core";
import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget} from "../Et2InputWidget/Et2InputWidget";
import '../Et2Image/Et2Image'; import '../Et2Image/Et2Image';
import {SlSwitch} from "@shoelace-style/shoelace"; import {SlSwitch} from "@shoelace-style/shoelace";
@ -21,7 +20,7 @@ import shoelace from "../Styles/shoelace";
* Add "et2SlideSwitch" class to use an alternate UI with images. Use CSS to set the images: * Add "et2SlideSwitch" class to use an alternate UI with images. Use CSS to set the images:
* *
*/ */
export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch)) export class Et2Switch extends Et2InputWidget(SlSwitch)
{ {
static get styles() static get styles()
{ {
@ -104,17 +103,6 @@ export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch))
} }
} }
get slots()
{
return {
...super.slots,
'': () =>
{
return this.labelTemplate();
}
}
}
constructor() constructor()
{ {
super(); super();
@ -125,6 +113,7 @@ export class Et2Switch extends Et2InputWidget(SlotMixin(SlSwitch))
updated(changedProperties) updated(changedProperties)
{ {
render(this.labelTemplate(), this);
if(changedProperties.has("toggleOn") || changedProperties.has("toggleOff") || changedProperties.has("label")) if(changedProperties.has("toggleOn") || changedProperties.has("toggleOff") || changedProperties.has("label"))
{ {
if(!this.toggleOn && !this.toggleOff && this._labelNode) if(!this.toggleOn && !this.toggleOff && this._labelNode)

View File

@ -69,7 +69,7 @@ export class Et2Textbox extends Et2InputWidget(SlInput)
super.connectedCallback(); super.connectedCallback();
} }
/** @param {import('@lion/core').PropertyValues } changedProperties */ /** @param changedProperties */
updated(changedProperties : PropertyValues) updated(changedProperties : PropertyValues)
{ {
super.updated(changedProperties); super.updated(changedProperties);

View File

@ -9,9 +9,9 @@
/* eslint-disable import/no-extraneous-dependencies */ /* eslint-disable import/no-extraneous-dependencies */
import {css, html, LitElement} from 'lit'; import {css, html, LitElement} from 'lit';
import {dedupeMixin, SlotMixin} from '@lion/core';
import {Et2InputWidget, Et2InputWidgetInterface} from "../Et2InputWidget/Et2InputWidget"; import {Et2InputWidget, Et2InputWidgetInterface} from "../Et2InputWidget/Et2InputWidget";
import {colorsDefStyles} from "../Styles/colorsDefStyles"; import {colorsDefStyles} from "../Styles/colorsDefStyles";
import {dedupeMixin} from "@open-wc/dedupe-mixin";
/** /**
* Invoker mixing adds an invoker button to a widget to trigger some action, e.g.: * Invoker mixing adds an invoker button to a widget to trigger some action, e.g.:
@ -25,7 +25,7 @@ import {colorsDefStyles} from "../Styles/colorsDefStyles";
type Constructor<T = Et2InputWidgetInterface> = new (...args : any[]) => T; type Constructor<T = Et2InputWidgetInterface> = new (...args : any[]) => T;
export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(superclass : T) => export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(superclass : T) =>
{ {
class Et2Invoker extends SlotMixin(Et2InputWidget(superclass)) class Et2Invoker extends Et2InputWidget(superclass)
{ {
/** @type {any} */ /** @type {any} */
static get properties() static get properties()
@ -193,7 +193,7 @@ export const Et2InvokerMixin = dedupeMixin(<T extends Constructor<LitElement>>(s
return super._oldChange(_ev); return super._oldChange(_ev);
} }
/** @param {import('@lion/core').PropertyValues } changedProperties */ /** @param changedProperties */
firstUpdated(changedProperties) firstUpdated(changedProperties)
{ {
super.firstUpdated(changedProperties); super.firstUpdated(changedProperties);

View File

@ -259,4 +259,4 @@ export class Et2VfsMime extends Et2ImageExpose
} }
customElements.define("et2-vfs-mime", Et2VfsMime as any, {extends: 'img'}); customElements.define("et2-vfs-mime", Et2VfsMime as any);

View File

@ -9,7 +9,7 @@ import type {IegwAppLocal} from "../../jsapi/egw_global";
import {egw} from "../../jsapi/egw_global"; import {egw} from "../../jsapi/egw_global";
import {ClassWithAttributes, ClassWithInterfaces} from "../et2_core_inheritance"; import {ClassWithAttributes, ClassWithInterfaces} from "../et2_core_inheritance";
import {css, LitElement, PropertyValues, unsafeCSS} from "lit"; import {css, LitElement, PropertyValues, unsafeCSS} from "lit";
import {dedupeMixin} from "@lion/core"; import {dedupeMixin} from "@open-wc/dedupe-mixin";
import type {et2_container} from "../et2_core_baseWidget"; import type {et2_container} from "../et2_core_baseWidget";
import type {et2_DOMWidget} from "../et2_core_DOMWidget"; import type {et2_DOMWidget} from "../et2_core_DOMWidget";
@ -495,7 +495,7 @@ const Et2WidgetMixin = <T extends Constructor>(superClass : T) =>
* A property has changed, and we want to make adjustments to other things * A property has changed, and we want to make adjustments to other things
* based on that * based on that
* *
* @param {import('@lion/core').PropertyValues } changedProperties * @param changedProperties
*/ */
updated(changedProperties : PropertyValues) updated(changedProperties : PropertyValues)
{ {

View File

@ -13,12 +13,10 @@ import {SlSplitPanel} from "@shoelace-style/shoelace";
import {et2_IDOMNode, et2_IResizeable} from "../../et2_core_interfaces"; import {et2_IDOMNode, et2_IResizeable} from "../../et2_core_interfaces";
import {et2_DOMWidget} from "../../et2_core_DOMWidget"; import {et2_DOMWidget} from "../../et2_core_DOMWidget";
import {css, html} from "lit"; import {css, html} from "lit";
import {SlotMixin} from "@lion/core";
import {colorsDefStyles} from "../../Styles/colorsDefStyles"; import {colorsDefStyles} from "../../Styles/colorsDefStyles";
export class Et2Split extends Et2Widget(SlotMixin(SlSplitPanel)) export class Et2Split extends Et2Widget(SlSplitPanel)
{ {
static get styles() static get styles()
{ {
return [ return [

View File

@ -0,0 +1,72 @@
import {customElement} from "lit/decorators/custom-element.js";
import {property} from "lit/decorators/property.js";
import {html, LitElement} from "lit";
/**
* @desc Takes care of accessible rendering of error messages
* Should be used in conjunction with FormControl having ValidateMixin applied
*
* Based on Lion
*/
@customElement("egw-validation-feedback")
export class EgwValidationFeedback extends LitElement
{
@property({type: Array, attribute: false})
feedbackData = [];
/**
* @overridable
* @param {Object} opts
* @param {string | Node | TemplateResult } opts.message message or feedback node or TemplateResult
* @param {string} [opts.type]
* @param {Validator} [opts.validator]
* @protected
*/
// eslint-disable-next-line class-methods-use-this
_messageTemplate({message})
{
return message;
}
/**
* @param changedProperties
*/
updated(changedProperties)
{
super.updated(changedProperties);
if(this.feedbackData && this.feedbackData[0])
{
this.setAttribute('type', this.feedbackData[0].type);
this.currentType = this.feedbackData[0].type;
window.clearTimeout(this.removeMessage);
// TODO: this logic should be in ValidateMixin, so that [show-feedback-for] is in sync,
// plus duration should be configurable
if(this.currentType === 'success')
{
this.removeMessage = window.setTimeout(() =>
{
this.removeAttribute('type');
/** @type {messageMap[]} */
this.feedbackData = [];
}, 3000);
}
}
else if(this.currentType !== 'success')
{
this.removeAttribute('type');
}
}
render()
{
return html`
${this.feedbackData &&
this.feedbackData.map(
({message, type, validator}) => html`
${this._messageTemplate({message, type, validator})}
`,
)}
`;
}
}

View File

@ -1,4 +1,4 @@
import {Pattern} from "@lion/form-core"; import {Pattern} from "./StringValidators";
export class IsEmail extends Pattern export class IsEmail extends Pattern
{ {

View File

@ -1,11 +1,11 @@
import {ResultValidator} from "@lion/form-core"; import {Validator} from "./Validator";
/** /**
* Manual validator for server-side validation messages passed * Manual validator for server-side validation messages passed
* from Etemplate. It just gives whatever message is passed in when created. * from Etemplate. It just gives whatever message is passed in when created.
* *
*/ */
export class ManualMessage extends ResultValidator export class ManualMessage extends Validator
{ {
static get validatorName() static get validatorName()
{ {

View File

@ -1,4 +1,4 @@
import {Pattern} from "@lion/form-core"; import {Pattern} from "./StringValidators"
export class Regex extends Pattern export class Regex extends Pattern
{ {

View File

@ -1,6 +1,6 @@
import {Required as LionRequired} from "@lion/form-core"; import {Validator} from "./Validator";
export class Required extends LionRequired export class Required extends Validator
{ {
/** /**
* Returns a Boolean. True if the test fails * Returns a Boolean. True if the test fails

View File

@ -0,0 +1,110 @@
import {Validator} from './Validator';
/**
* @param {?} value
*/
const isString = value => typeof value === 'string';
export class IsString extends Validator {
static get validatorName() {
return 'IsString';
}
/**
* @param {?} value
*/
// eslint-disable-next-line class-methods-use-this
execute(value) {
let hasError = false;
if (!isString(value)) {
hasError = true;
}
return hasError;
}
}
export class EqualsLength extends Validator {
static get validatorName() {
return 'EqualsLength';
}
execute(value, length = this.param) {
let hasError = false;
if (!isString(value) || value.length !== length) {
hasError = true;
}
return hasError;
}
}
export class MinLength extends Validator {
static get validatorName() {
return 'MinLength';
}
execute(value, min = this.param) {
let hasError = false;
if (!isString(value) || value.length < min) {
hasError = true;
}
return hasError;
}
}
export class MaxLength extends Validator {
static get validatorName() {
return 'MaxLength';
}
execute(value, max = this.param) {
let hasError = false;
if (!isString(value) || value.length > max) {
hasError = true;
}
return hasError;
}
}
export class MinMaxLength extends Validator {
static get validatorName() {
return 'MinMaxLength';
}
/**
* @param {?} value
*/
execute(value, { min = 0, max = 0 } = this.param) {
let hasError = false;
if (!isString(value) || value.length < min || value.length > max) {
hasError = true;
}
return hasError;
}
}
/**
* @param {?} value
* @param {RegExp} pattern
*/
const hasPattern = (value, pattern) => pattern.test(value);
export class Pattern extends Validator {
static get validatorName() {
return 'Pattern';
}
execute(value, pattern = this.param) {
if (!(pattern instanceof RegExp)) {
throw new Error(
'Psst... Pattern validator expects RegExp object as parameter e.g, new Pattern(/#LionRocks/) or new Pattern(RegExp("#LionRocks")',
);
}
let hasError = false;
if (!isString(value) || !hasPattern(value, pattern)) {
hasError = true;
}
return hasError;
}
}

View File

@ -0,0 +1,102 @@
export class Validator
{
/**
*
* @param {?} [param]
* @param {Object.<string,?>} [config]
*/
constructor(param, config)
{
/** @type {?} */
this.__param = param;
/** @type {Object.<string,?>} */
this.__config = config || {};
this.type = (config && config.type) || 'error'; // Default type supported by ValidateMixin
}
static get validatorName()
{
return '';
}
/**
* @desc The function that returns a Boolean
* @param {?} [modelValue]
* @param {?} [param]
* @param {{}} [config]
* @returns {Boolean|Promise<Boolean>}
*/
// eslint-disable-next-line no-unused-vars, class-methods-use-this
execute(modelValue, param, config) : boolean | Promise<boolean>
{
const ctor = /** @type {typeof Validator} */ (this.constructor);
if(!ctor.validatorName)
{
throw new Error(
'A validator needs to have a name! Please set it via "static get validatorName() { return \'IsCat\'; }"',
);
}
return true;
}
set param(p)
{
this.__param = p;
if(this.dispatchEvent)
{
this.dispatchEvent(new Event('param-changed'));
}
}
get param()
{
return this.__param;
}
set config(c)
{
this.__config = c;
if(this.dispatchEvent)
{
this.dispatchEvent(new Event('config-changed'));
}
}
get config()
{
return this.__config;
}
/**
* @overridable
* @param {MessageData} [data]
* @returns {Promise<string|Node>}
* @protected
*/
async _getMessage(data)
{
const ctor = /** @type {typeof Validator} */ (this.constructor);
const composedData = {
name: ctor.validatorName,
type: this.type,
params: this.param,
config: this.config,
...data,
};
if(this.config.getMessage)
{
if(typeof this.config.getMessage === 'function')
{
return this.config.getMessage(composedData);
}
throw new Error(
`You must provide a value for getMessage of type 'function', you provided a value of type: ${typeof this
.config.getMessage}`,
);
}
return ctor.getMessage(composedData);
}
}

View File

@ -102,6 +102,7 @@ import "./Et2Vfs/Et2VfsSelectButton";
import "./Et2Vfs/Et2VfsSelectDialog"; import "./Et2Vfs/Et2VfsSelectDialog";
import "./Et2Vfs/Et2VfsSelectRow"; import "./Et2Vfs/Et2VfsSelectRow";
import "./Et2Vfs/Et2VfsUid"; import "./Et2Vfs/Et2VfsUid";
import "./Validators/EgwValidationFeedback";
import "./Et2Textbox/Et2Password"; import "./Et2Textbox/Et2Password";
import './Et2Textbox/Et2Searchbox'; import './Et2Textbox/Et2Searchbox';
import "./Et2Tree/Et2Tree"; import "./Et2Tree/Et2Tree";

View File

@ -2112,7 +2112,7 @@ table.et2_grid tbody.ui-sortable:not(.ui-sortable-disabled) > tr:not(.th) {
* Message styles * Message styles
*/ */
/* Style used for a generic message (such as success messages or validation errors) */ /* Style used for a generic message (such as success messages or validation errors) */
div.message, lion-validation-feedback[type] { div.message, egw-validation-feedback[type] {
display: block; display: block;
border: 1px solid; border: 1px solid;
border-color: var(--primary-color, gray); border-color: var(--primary-color, gray);
@ -2124,7 +2124,7 @@ div.message, lion-validation-feedback[type] {
font-size: 12px; font-size: 12px;
} }
div.message.floating, lion-validation-feedback[type] { div.message.floating, egw-validation-feedback[type] {
position: absolute; position: absolute;
margin: 0px; margin: 0px;
z-index: 1; z-index: 1;
@ -2132,14 +2132,14 @@ div.message.floating, lion-validation-feedback[type] {
left: 0px; left: 0px;
} }
lion-validation-feedback[type] { egw-validation-feedback[type] {
top: initial; top: initial;
margin-top: calc(-0.2 * var(--sl-input-height-medium)); margin-top: calc(-0.2 * var(--sl-input-height-medium));
width: fit-content; width: fit-content;
white-space: nowrap; white-space: nowrap;
} }
.message.validation_error, lion-validation-feedback[type="error"] { .message.validation_error, egw-validation-feedback[type="error"] {
color: var(--error-color); color: var(--error-color);
border-color: var(--error-color); border-color: var(--error-color);
background-repeat: no-repeat; background-repeat: no-repeat;

View File

@ -1,5 +1,5 @@
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import {css} from "@lion/core"; import {css} from "lit";
import {Et2PortletFavorite} from "../../home/js/Et2PortletFavorite"; import {Et2PortletFavorite} from "../../home/js/Et2PortletFavorite";
/** /**

View File

@ -1,6 +1,7 @@
import {Et2Date, parseDate} from "../../api/js/etemplate/Et2Date/Et2Date"; import {Et2Date, parseDate} from "../../api/js/etemplate/Et2Date/Et2Date";
import {css} from "@lion/core";
import {CalendarApp} from "./app"; import {CalendarApp} from "./app";
import {css, html, render} from "lit";
import {app} from "../../api/js/jsapi/egw_global";
export class SidemenuDate extends Et2Date export class SidemenuDate extends Et2Date
{ {
@ -35,20 +36,6 @@ export class SidemenuDate extends Et2Date
]; ];
} }
get slots()
{
return {
...super.slots,
input: () =>
{
// This element gets hidden and used for value - overridden from parent
const text = document.createElement('input');
text.type = "text";
return text;
}
}
}
constructor() constructor()
{ {
super(); super();
@ -60,8 +47,10 @@ export class SidemenuDate extends Et2Date
this._handleHeaderChange = this._handleHeaderChange.bind(this); this._handleHeaderChange = this._handleHeaderChange.bind(this);
} }
async connectedCallback() async connectedCallback()
{ {
render(this._inputTemplate(), this);
super.connectedCallback(); super.connectedCallback();
this.removeEventListener("change", this._oldChange); this.removeEventListener("change", this._oldChange);
@ -360,7 +349,22 @@ export class SidemenuDate extends Et2Date
// Go directly // Go directly
app.calendar.update_state(update); app.calendar.update_state(update);
} }
/**
* The interactive (form) element.
* @protected
*/
get _inputNode()
{
return this.querySelector('input');
}
protected _inputTemplate()
{
// Plain input
return html`
<input type="text"></input>`;
}
} }
// @ts-ignore TypeScript is not recognizing that Et2Date is a LitElement
customElements.define("calendar-date", SidemenuDate); customElements.define("calendar-date", SidemenuDate);

View File

@ -1,10 +1,11 @@
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet"; import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
import {classMap, css, html} from "@lion/core";
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import {etemplate2} from "../../api/js/etemplate/etemplate2"; import {etemplate2} from "../../api/js/etemplate/etemplate2";
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
import {Et2Favorites} from "../../api/js/etemplate/Et2Favorites/Et2Favorites"; import {Et2Favorites} from "../../api/js/etemplate/Et2Favorites/Et2Favorites";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog"; import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";
import {css, html} from "lit";
import {classMap} from "lit/directives/class-map.js";
export class Et2PortletFavorite extends Et2Portlet export class Et2PortletFavorite extends Et2Portlet
{ {

View File

@ -1,6 +1,6 @@
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet"; import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import {css} from "@lion/core"; import {css} from "lit";
import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog"; import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";

View File

@ -1,6 +1,6 @@
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet"; import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
import {et2_createWidget} from "../../api/js/etemplate/et2_core_widget"; import {et2_createWidget} from "../../api/js/etemplate/et2_core_widget";
import {css, html, TemplateResult} from "@lion/core"; import {css, html, TemplateResult} from "lit";
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog"; import {Et2Dialog} from "../../api/js/etemplate/Et2Dialog/Et2Dialog";

View File

@ -1,7 +1,8 @@
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import {css, html, TemplateResult, unsafeHTML} from "@lion/core";
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet"; import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import type {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
import {css, html, TemplateResult} from "lit";
import {unsafeHTML} from "lit/directives/unsafe-html.js"
/** /**
* Home portlet to show a note * Home portlet to show a note

View File

@ -1,7 +1,9 @@
import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet"; import {Et2Portlet} from "../../api/js/etemplate/Et2Portlet/Et2Portlet";
import {classMap, css, html, nothing, repeat, TemplateResult} from "@lion/core";
import shoelace from "../../api/js/etemplate/Styles/shoelace"; import shoelace from "../../api/js/etemplate/Styles/shoelace";
import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions"; import {SelectOption} from "../../api/js/etemplate/Et2Select/FindSelectOptions";
import {css, html, nothing, TemplateResult} from "lit";
import {classMap} from "lit/directives/class-map.js";
import {repeat} from "lit/directives/repeat.js";
/** /**
* Show current and forecast weather * Show current and forecast weather

72
package-lock.json generated
View File

@ -10,8 +10,6 @@
"license": "GPL-2.0", "license": "GPL-2.0",
"dependencies": { "dependencies": {
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1", "@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
"@lion/core": "^0.21.1",
"@lion/form-core": "^0.16.0",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",
"@shoelace-style/shoelace": "2.15.0", "@shoelace-style/shoelace": "2.15.0",
"@types/jquery": "^3.5.29", "@types/jquery": "^3.5.29",
@ -2295,11 +2293,6 @@
"node": ">=6.9.0" "node": ">=6.9.0"
} }
}, },
"node_modules/@bundled-es-modules/message-format": {
"version": "6.0.4",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/message-format/-/message-format-6.0.4.tgz",
"integrity": "sha512-NGUoPxqsBzDwvRhY3A3L/AhS1hzS9OWappfyDOyCwE7G3W4ua28gau7QwvJz7QzA6ArbAdeb8c1mLjvd1WUFAA=="
},
"node_modules/@bundled-es-modules/pdfjs-dist": { "node_modules/@bundled-es-modules/pdfjs-dist": {
"version": "2.5.207-rc1", "version": "2.5.207-rc1",
"resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.5.207-rc1.tgz", "resolved": "https://registry.npmjs.org/@bundled-es-modules/pdfjs-dist/-/pdfjs-dist-2.5.207-rc1.tgz",
@ -3061,35 +3054,6 @@
"integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==", "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==",
"dev": true "dev": true
}, },
"node_modules/@lion/core": {
"version": "0.21.1",
"resolved": "https://registry.npmjs.org/@lion/core/-/core-0.21.1.tgz",
"integrity": "sha512-6lCJ7ZLHQBcsZu/XBOEePG4KxxNFI1OD+1wSA4f9KMyHJVA4+FXZEv1mYniWVsfdPXyyAgKnmfB23xD4Z3kwng==",
"dependencies": {
"@open-wc/dedupe-mixin": "^1.3.0",
"@open-wc/scoped-elements": "^2.0.1",
"lit": "^2.0.2"
}
},
"node_modules/@lion/form-core": {
"version": "0.16.0",
"resolved": "https://registry.npmjs.org/@lion/form-core/-/form-core-0.16.0.tgz",
"integrity": "sha512-b3Tw0y/5eoIkfowJUqH4JIPvleFOsN09MM6Pb8j7QIyweRk/YlSMbirAlEYmdeTo8aOgGRJhbmrOKmukpsPA/g==",
"dependencies": {
"@lion/core": "^0.21.0",
"@lion/localize": "^0.23.0"
}
},
"node_modules/@lion/localize": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/@lion/localize/-/localize-0.23.0.tgz",
"integrity": "sha512-pGN2JzEPukvgtB3+BpeT13KZnI7mCqyq7m/a+A973XFhH1PJlAyEXdkv3bVJsIpNolqXRVP0lU4vgisMsO8IkQ==",
"dependencies": {
"@bundled-es-modules/message-format": "6.0.4",
"@lion/core": "^0.21.0",
"singleton-manager": "^1.4.3"
}
},
"node_modules/@lit-labs/ssr-dom-shim": { "node_modules/@lit-labs/ssr-dom-shim": {
"version": "1.2.0", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@lit-labs/ssr-dom-shim/-/ssr-dom-shim-1.2.0.tgz",
@ -3171,12 +3135,14 @@
"node_modules/@open-wc/dedupe-mixin": { "node_modules/@open-wc/dedupe-mixin": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/@open-wc/dedupe-mixin/-/dedupe-mixin-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@open-wc/dedupe-mixin/-/dedupe-mixin-1.3.0.tgz",
"integrity": "sha512-UfdK1MPnR6T7f3svzzYBfu3qBkkZ/KsPhcpc3JYhsUY4hbpwNF9wEQtD4Z+/mRqMTJrKg++YSxIxE0FBhY3RIw==" "integrity": "sha512-UfdK1MPnR6T7f3svzzYBfu3qBkkZ/KsPhcpc3JYhsUY4hbpwNF9wEQtD4Z+/mRqMTJrKg++YSxIxE0FBhY3RIw==",
"dev": true
}, },
"node_modules/@open-wc/scoped-elements": { "node_modules/@open-wc/scoped-elements": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/@open-wc/scoped-elements/-/scoped-elements-2.0.1.tgz", "resolved": "https://registry.npmjs.org/@open-wc/scoped-elements/-/scoped-elements-2.0.1.tgz",
"integrity": "sha512-JS6ozxUFwFX3+Er91v9yQzNIaFn7OnE0iESKTbFvkkKdNwvAPtp1fpckBKIvWk8Ae9ZcoI9DYZuT2DDbMPcadA==", "integrity": "sha512-JS6ozxUFwFX3+Er91v9yQzNIaFn7OnE0iESKTbFvkkKdNwvAPtp1fpckBKIvWk8Ae9ZcoI9DYZuT2DDbMPcadA==",
"dev": true,
"dependencies": { "dependencies": {
"@lit/reactive-element": "^1.0.0", "@lit/reactive-element": "^1.0.0",
"@open-wc/dedupe-mixin": "^1.3.0", "@open-wc/dedupe-mixin": "^1.3.0",
@ -3891,12 +3857,6 @@
"integrity": "sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==", "integrity": "sha512-ARATsLdrGPUnaBvxLhUlnltcMgn7pQG312S8ccdYlnyijabrX9RN/KN/iGj9Am96CoW8e/K9628BA7Bv4XHdrA==",
"dev": true "dev": true
}, },
"node_modules/@types/prop-types": {
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
"integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q==",
"peer": true
},
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
@ -3909,16 +3869,6 @@
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true "dev": true
}, },
"node_modules/@types/react": {
"version": "18.2.72",
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.72.tgz",
"integrity": "sha512-/e7GWxGzXQF7OJAua7UAYqYi/4VpXEfbGtmYQcAQwP3SjjjAXfybTf/JK5S+SaetB/ChXl8Y2g1hCsj7jDXxcg==",
"peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/resolve": { "node_modules/@types/resolve": {
"version": "1.17.1", "version": "1.17.1",
"resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz", "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
@ -5190,7 +5140,8 @@
"node_modules/@webcomponents/scoped-custom-element-registry": { "node_modules/@webcomponents/scoped-custom-element-registry": {
"version": "0.0.3", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/@webcomponents/scoped-custom-element-registry/-/scoped-custom-element-registry-0.0.3.tgz", "resolved": "https://registry.npmjs.org/@webcomponents/scoped-custom-element-registry/-/scoped-custom-element-registry-0.0.3.tgz",
"integrity": "sha512-lpSzgDCGbM99dytb3+J3Suo4+Bk1E13MPnWB42JK8GwxSAxFz+tC7TTv2hhDSIE2IirGNKNKCf3m08ecu6eAsQ==" "integrity": "sha512-lpSzgDCGbM99dytb3+J3Suo4+Bk1E13MPnWB42JK8GwxSAxFz+tC7TTv2hhDSIE2IirGNKNKCf3m08ecu6eAsQ==",
"dev": true
}, },
"node_modules/@xtuc/ieee754": { "node_modules/@xtuc/ieee754": {
"version": "1.2.0", "version": "1.2.0",
@ -7138,12 +7089,6 @@
"node": ">=14" "node": ">=14"
} }
}, },
"node_modules/csstype": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
"peer": true
},
"node_modules/custom-element-jet-brains-integration": { "node_modules/custom-element-jet-brains-integration": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/custom-element-jet-brains-integration/-/custom-element-jet-brains-integration-1.2.1.tgz", "resolved": "https://registry.npmjs.org/custom-element-jet-brains-integration/-/custom-element-jet-brains-integration-1.2.1.tgz",
@ -12995,7 +12940,7 @@
"version": "2.79.1", "version": "2.79.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz", "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.1.tgz",
"integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==", "integrity": "sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==",
"devOptional": true, "dev": true,
"bin": { "bin": {
"rollup": "dist/bin/rollup" "rollup": "dist/bin/rollup"
}, },
@ -13459,11 +13404,6 @@
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true "dev": true
}, },
"node_modules/singleton-manager": {
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/singleton-manager/-/singleton-manager-1.4.3.tgz",
"integrity": "sha512-Jy1Ib9cO9xCQ6UZ/vyFOqqWMnSpfZ8/Sc2vme944aWsCLO+lMPiFG9kGZGpyiRT9maYeI0JyZH1CGgjmkSN8VA=="
},
"node_modules/sinon": { "node_modules/sinon": {
"version": "11.1.2", "version": "11.1.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz", "resolved": "https://registry.npmjs.org/sinon/-/sinon-11.1.2.tgz",

View File

@ -82,8 +82,6 @@
}, },
"dependencies": { "dependencies": {
"@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1", "@bundled-es-modules/pdfjs-dist": "^2.5.207-rc1",
"@lion/core": "^0.21.1",
"@lion/form-core": "^0.16.0",
"@rollup/plugin-commonjs": "^24.0.1", "@rollup/plugin-commonjs": "^24.0.1",
"@shoelace-style/shoelace": "2.15.0", "@shoelace-style/shoelace": "2.15.0",
"@types/jquery": "^3.5.29", "@types/jquery": "^3.5.29",