@optionfactory/ful
Version:
This is a minimalistic web components library built on top of [`@optionfactory/ftl`](https://github.com/optionfactory/ftl) to accelerate frontend development cycle-time. Strictly adhering to a no-build philosophy, it completely eliminates the downtime as
1 lines • 65.1 kB
JavaScript
import{ParsedElement as e,Attributes as t,registry as s,Fragments as i,Templates as r,Nodes as a,Rendering as n}from"@optionfactory/ftl";class l{static encode(e,t){const s=t||l.URL_SAFE,i=e.byteLength,r=new Uint8Array(e);let a="";for(let e=0;e<i;e+=3){a+=s[r[e]>>2]+s[(3&r[e])<<4|r[e+1]>>4]+s[(15&r[e+1])<<2|r[e+2]>>6]+s[63&r[e+2]]}return i%3==2?a=a.substring(0,a.length-1):i%3==1&&(a=a.substring(0,a.length-2)),a}static decode(e,t){const s=t||l.URL_SAFE;let i=Math.floor(.75*e.length);for(let t=0;t!==e.length&&"="===e[e.length-t-1];++t)--i;const r=new Uint8Array(i);let a=0,n=0;for(;a<.75*e.length;){const t=s.indexOf(e.charAt(n++)),i=s.indexOf(e.charAt(n++)),l=s.indexOf(e.charAt(n++)),o=s.indexOf(e.charAt(n++));r[a++]=t<<2|i>>4,r[a++]=(15&i)<<4|l>>2,r[a++]=(3&l)<<6|o}return r.buffer}}l.STANDARD="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",l.URL_SAFE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";class o{static decode(e){if(e.length%2!=0)throw new Error("invalid length");const t=e.length/2;return new Uint8Array(t).map((t,s)=>{const i=2*s,r=e.substring(i,i+2);return parseInt(r,16)})}static encode(e,t){return Array.from(e).map(e=>e.toString(16)).map(e=>t?e.toUpperCase():e).map(e=>e.padStart(2,0)).join("")}}class u extends Error{constructor(e,t,s){super(e,{cause:s}),this.name="Failure",this.problems=t}dropping(e){return new u(this.message,u.dropProblemsContext(this.problems,e),this)}static dropProblemsContext(e,t){return e.map(({type:e,context:s,reason:i,details:r})=>({type:e,context:s?.startsWith(t)?s.substring(t.length):s,reason:i,details:r}))}}class d{#e;#t;constructor(e,t){this.#e=e,this.#t=t}get normalized(){return`${this.#e}/${this.#t}`}get type(){return this.#e}get subtype(){return this.#t}static parse(e){if(!e)return new d("unknown","unknown");const[t,s]=e.split(";"),[i,r]=t.trim().split("/");return new d(i.toLowerCase(),r?.toLowerCase())}}class c extends u{constructor(e,t,s,i){super(e,s,i),this.name="HttpClientError",this.status=t}dropping(e){return new c(this.message,this.status,u.dropProblemsContext(this.problems,e),this)}static of(e,t){return new c(t.message,0,[{type:e,context:null,reason:t.message,details:null}],t)}static async fromResponse(e){switch(d.parse(e.headers.get("Content-Type")).normalized){case"application/failures+json":{const t=await e.json(),s=`${e.status} ${e.statusText}: ${t.length} failures`;return new c(s,e.status,t)}case"application/problem+json":{const t=await e.json(),s=`${e.status} ${e.statusText}: ${t.title} ${t.detail}`;return new c(s,e.status,t.problems||[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}default:{const t=await e.text(),s=`${e.status} ${e.statusText}: ${t}`;return new c(s,e.status,[{type:"GENERIC_PROBLEM",context:null,reason:s,details:null}])}}}}class h{#s;#i;constructor(){this.#s=document.querySelector("meta[name='_csrf_header']")?.getAttribute("content"),this.#i=document.querySelector("meta[name='_csrf']")?.getAttribute("content")}async intercept(e,t,s){return this.#s&&this.#i&&t.headers.set(this.#s,this.#i),await s.proceed(e,t)}}class p{#r;constructor(e){this.#r=e}async intercept(e,t,s){const i=await s.proceed(e,t);return 401===i.status&&(window.location.href=this.#r),i}}class f{#a;constructor(){this.#a=[]}withCsrfToken(){return this.#a.push(new h),this}withRedirectOnUnauthorized(e){return this.#a.push(new p(e)),this}withInterceptors(...e){return this.#a.push(...e),this}build(){return new g(this.#a)}}class m{async intercept(e,t,s){return await fetch(new Request(e,t))}}class b{#a;#n;constructor(e,t){this.#a=e,this.#n=t}async proceed(e,t){const s=this.#a[this.#n];return await s.intercept(e,t,new b(this.#a,this.#n+1))}}class g{#a;static builder(){return new f}constructor(e){this.#a=e||[]}async exchange(e,t,s){const i=[...this.#a,...s||[],new m],r=new b(i,0),a=new URL(new Request(e).url);return await r.proceed(a,t??{})}request(e,t){return y.create(this,e,t)}get(e){return y.create(this,"GET",e)}head(e){return y.create(this,"HEAD",e)}post(e){return y.create(this,"POST",e)}put(e){return y.create(this,"PUT",e)}patch(e){return y.create(this,"PATCH",e)}delete(e){return y.create(this,"DELETE",e)}}const v=async(e,t)=>{try{return await e[t]()}catch(e){throw c.of("UNMARSHALING_PROBLEM",e)}};class y{#l;#o;#u;#d;#c;#h;#p;#a;static create(e,t,s){const[i,r=""]=s.split("?");return new y(e,t,i,new URLSearchParams(r),new Headers,void 0,{},[])}constructor(e,t,s,i,r,a,n,l){this.#l=e,this.#o=t,this.#u=s,this.#d=i,this.#h=a,this.#c=r,this.#p=n,this.#a=l}headers(e){for(const[t,s]of new Headers(e).entries())null==s?this.#c.delete(t):this.#c.set(t,s);return this}header(e,t){return null==t?this.#c.delete(e):this.#c.set(e,t),this}params(e){for(const[t,s]of new URLSearchParams(e).entries())null==s?this.#d.delete(t):this.#d.set(t,s);return this}param(e,...t){if(0===t.length||null==t[0])return this.#d.delete(e),this;for(const s of t)this.#d.append(e,s);return this}body(e){return this.#h=e,this}json(e){return this.#c.set("Content-Type","application/json"),this.#h=JSON.stringify(e),this}multipart(e){const t=new FormData;return e(new w(t)),this.#h=t,this}options(e){for(const[t,s]of Object.entries(e))this.#p[t]=s;return this}option(e,t){return this.#p[e]=t,this}interceptors(e){for(const t of e)this.#a.push(t);return this}interceptor(e){return this.#a.push(e),this}async exchange(){const e=this.#d.size?`${this.#u}?${this.#d}`:this.#u,t={...this.#p,headers:this.#c,method:this.#o,body:this.#h};return await this.#l.exchange(e,t,this.#a)}async fetch(){const e=this.#d.size?`${this.#u}?${this.#d}`:this.#u,t={...this.#p,headers:this.#c,method:this.#o,body:this.#h};try{const s=await this.#l.exchange(e,t,this.#a);if(!s.ok)throw await c.fromResponse(s);return s}catch(e){if(e instanceof u)throw e;throw c.of("CONNECTION_PROBLEM",e)}}async fetchText(){const e=await this.fetch();return await v(e,"text")}async fetchJson(){const e=await this.fetch();return await v(e,"json")}async fetchBlob(){const e=await this.fetch();return await v(e,"blob")}async fetchArrayBuffer(){const e=await this.fetch();return await v(e,"arrayBuffer")}}class w{#f;constructor(e){this.#f=e}field(e,t){return this.#f.append(e,t),this}blob(e,t,s){return this.#f.append(e,t,s),this}blobs(e,t){for(let s of t)this.#f.append(e,s);return this}json(e,t,s){const i=new Blob([JSON.stringify(t)],{type:"application/json"});return this.#f.append(e,i,s),this}}class E extends Storage{static save(e,t){localStorage.setItem(e,JSON.stringify(t))}static load(e){const t=localStorage.getItem(e);return null===t?void 0:JSON.parse(t)}static remove(e){localStorage.removeItem(e)}static pop(e){const t=E.load(e);return E.remove(e),t}}class x extends Storage{static save(e,t){sessionStorage.setItem(e,JSON.stringify(t))}static load(e){const t=sessionStorage.getItem(e);return null===t?void 0:JSON.parse(t)}static remove(e){sessionStorage.removeItem(e)}static pop(e){const t=x.load(e);return x.remove(e),t}}class A{static save(e,t,s){E.save(e,{revision:t,data:s})}static load(e,t){const s=E.load(e);if(void 0!==s){if(s.revision===t)return s.data;localStorage.removeItem(e)}}}class T{static save(e,t,s){x.save(e,{revision:t,data:s})}static load(e,t){const s=x.load(e);if(void 0!==s){if(s.revision===t)return s.data;localStorage.removeItem(e)}}}class q{static forKeycloak(e,t,s,i){return new q(e,i??"openid profile",{auth:new URL("protocol/openid-connect/auth",t),token:new URL("protocol/openid-connect/token",t),logout:new URL("protocol/openid-connect/logout",t),registration:new URL("protocol/openid-connect/registrations",t),redirect:s})}constructor(e,t,{auth:s,token:i,registration:r,logout:a,redirect:n}){this.clientId=e,this.scope=t,this.uri={auth:s,token:i,registration:r,logout:a,redirect:n}}async action(e,t){const s=l.encode(crypto.getRandomValues(new Uint8Array(32)).buffer),i=l.encode(await crypto.subtle.digest("SHA-256",(new TextEncoder).encode(s))),r=this.clientId+l.encode(crypto.getRandomValues(new Uint8Array(16)).buffer);x.save(`${q.PKCE_AND_STATE_KEY}-${this.clientId}`,{state:r,verifier:s});const a=new URL(e);a.searchParams.set("client_id",this.clientId),a.searchParams.set("redirect_uri",this.uri.redirect),a.searchParams.set("response_type","code"),a.searchParams.set("scope",this.scope),a.searchParams.set("state",r),a.searchParams.set("code_challenge",i),a.searchParams.set("code_challenge_method","S256"),Object.entries(t||{}).forEach(e=>{a.searchParams.set(e[0],e[1])}),window.location.href=a.toString()}async registration(e){await this.action(this.uri.registration,e)}async applicationInitiatedAction(e,t){await this.action(this.uri.auth,{...t,kc_action:e})}async#m(e,t){window.history.replaceState("","",this.uri.redirect);const s=x.pop(`${q.PKCE_AND_STATE_KEY}-${this.clientId}`);if(s.state!==t)throw new Error("State mismatch");const i=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["code",e],["grant_type","authorization_code"],["code_verifier",s.verifier],["state",s.state],["redirect_uri",this.uri.redirect]])});if(!i.ok){const e=await i.text();throw new Error("Error:"+i.status+": "+e)}const r=await i.json();return new S(this.clientId,r,this.uri)}async ensureLoggedIn(){const e=new URL(window.location.href),t=e.searchParams.get("code");if(t&&x.load(`${q.PKCE_AND_STATE_KEY}-${this.clientId}`)){const s=e.searchParams.get("state");return await this.#m(t,s)}return await this.action(this.uri.auth,{}),null}}q.PKCE_AND_STATE_KEY="state-and-verifier";class S{static parseToken(e){const[t,s,i]=e.split("."),r=new TextDecoder("utf-8");return{header:JSON.parse(r.decode(l.decode(t,l.STANDARD))),payload:JSON.parse(r.decode(l.decode(s,l.STANDARD))),signature:i}}constructor(e,t,{token:s,logout:i,redirect:r}){this.clientId=e,this.token=t,this.idToken=S.parseToken(t.id_token),this.accessToken=S.parseToken(t.access_token),this.refreshToken=S.parseToken(t.refresh_token),this.uri={token:s,logout:i,redirect:r},this.refreshCallback=null}onRefresh(e){this.refreshCallback=e}async refresh(){const e=await fetch(this.uri.token,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams([["client_id",this.clientId],["grant_type","refresh_token"],["refresh_token",this.token.refresh_token]])});if(!e.ok){const t=await e.text();throw new Error("Error:"+e.status+": "+t)}const t=await e.json();this.token=t,this.idToken=S.parseToken(t.id_token),this.accessToken=S.parseToken(t.access_token),this.refreshToken=S.parseToken(t.refresh_token),this.refreshCallback&&this.refreshCallback(this.token,this.accessToken,this.refreshToken)}shouldBeRefreshed(e){const t=(new Date).getTime(),s=1e3*this.refreshToken.payload.exp;return!(t>s)&&t-e>s}async refreshIf(e){this.shouldBeRefreshed(e)&&await this.refresh()}logout(){const e=new URL(this.uri.logout);e.searchParams.set("post_logout_redirect_uri",this.uri.redirect),e.searchParams.set("id_token_hint",this.token.id_token),window.location.href=e.toString()}bearerToken(){return`Bearer ${this.token.access_token}`}interceptor(e,t){return new k(this,e,t)}}class k{#b;#g;#v;constructor(e,t,s){this.#b=e,this.#g=t||2e3,this.#v=s||3e4}async intercept(e,t,s){await this.#b.refreshIf(this.#g),t.headers.set("Authorization",this.#b.bearerToken());const i=await s.proceed(e,t);return await this.#b.refreshIf(this.#v),i}}class _{static async fireAsync(e,t,s){e.dispatchEvent(t);const i=t.async?.promises??[],r=s?.mode??"broadcast";if("pipeline"===r&&i.length>1)throw new Error(`[AsyncEvents] Event "${t.type}" is configured in 'pipeline' mode and expects at most one async listener, but ${i.length} listeners were triggered on this element.`);if("delegate"===r&&1!==i.length)throw new Error(`[AsyncEvents] Event "${t.type}" is configured in 'delegate' mode and requires exactly one async listener, but ${i.length} were registered.`);return"broadcast"===r?Promise.all(i):Promise.resolve(i[0])}static asyncOn(e,t,s,i){const r=async e=>{const t=e;t.async||(t.async={promises:[]});const{promise:i,resolve:r,reject:a}=Promise.withResolvers();t.async.promises.push(i);try{r(await s(t))}catch(e){a(e)}};return e.addEventListener(t,r,i),r}static asyncOff(e,t,s,i){e.removeEventListener(t,s,i)}static mixInto(...e){for(const t of e)Object.assign(t.prototype,{async fireAsync(e,t){return await _.fireAsync(this,e,t)},asyncOn(e,t,s){return _.asyncOn(this,e,t,s)},asyncOff(e,t,s){_.asyncOff(this,e,t,s)}})}}class L{static sleep(e){return new Promise(t=>setTimeout(t,e))}static DEBOUNCE_DEFAULT=0;static DEBOUNCE_IMMEDIATE=1;static debounce(e,t,s){const i=s??L.DEBOUNCE_DEFAULT;let r=null,a=[],n=0;const l=()=>{const s=(new Date).getTime()-n;e>s?r=setTimeout(l,e-s):(r=null,i!==L.DEBOUNCE_IMMEDIATE&&t(...a),null===r&&(a=[]))};return[function(){a=[...arguments],n=(new Date).getTime(),null===r&&(r=setTimeout(l,e),i===L.DEBOUNCE_IMMEDIATE&&t(...a))},()=>clearTimeout(r)]}static THROTTLE_DEFAULT=0;static THROTTLE_NO_LEADING=1;static THROTTLE_NO_TRAILING=2;static throttle(e,t,s){const i=s??L.THROTTLE_DEFAULT;let r=null,a=[],n=0;const l=()=>{n=i&L.THROTTLE_NO_LEADING?0:(new Date).getTime(),r=null,t(...a),null===r&&(a=[])};return[function(){const s=(new Date).getTime();!n&&i&L.THROTTLE_NO_LEADING&&(n=s);const o=e-(s-n);a=[...arguments],o<=0||o>e?(null!==r&&(clearTimeout(r),r=null),n=s,t(...a),null===r&&(a=[])):null!==r||i&L.THROTTLE_NO_TRAILING||(r=setTimeout(l,o))},()=>clearTimeout(r)]}}class O{static flatten(e,t,s){return Object.keys(e).reduce((i,r)=>{const a=t.length?t+"."+r:r;return s.has(a)||"object"!=typeof e[r]||null===e[r]?i[a]=e[r]:Object.assign(i,O.flatten(e[r],a,s)),i},{})}static providePath(e,t,s){const i=t.split(".").map(e=>/^[0-9]+$/.test(e)?+e:e);let r=e??{},a=null;for(let t=0;;++t){const n=i[t],l=i[t-1];if(Number.isInteger(n)&&!Array.isArray(r)&&(null!==a?a[l]=r=[]:e=r=[]),t===i.length-1)return r[n]=void 0!==s?s:n in r?r[n]:null,e;void 0===r[n]&&(r[n]={}),a=r,r=r[n]}}static extract(e){if("radio"===e.getAttribute("type")){if(!e.checked)return;return"boolean"===e.dataset.fulBindType?"true"===e.value:e.value}return"checkbox"===e.getAttribute("type")?e.checked:"boolean"===e.dataset.fulBindType?e.value?"true"===e.value:null:!("INPUT"!==e.tagName&&"SELECT"!==e.tagName||""!==e.value&&void 0!==e.value)?null:e.value}static extractFrom(e,t){let s={};for(const i of e.elements)!i.hasAttribute("name")||i.matches(":disabled")&&i!==t||(s=O.providePath(s,i.getAttribute("name"),O.extract(i)));return s}static mutate(e,t){"radio"!==e.getAttribute("type")?"checkbox"!==e.getAttribute("type")?e.value=t:e.checked=t:e.checked=e.getAttribute("value")===t}static mutateIn(e,t){const s=Array.from(e.elements).map(e=>e.getAttribute("name")).filter(e=>e);for(const[i,r]of Object.entries(O.flatten(t,"",new Set(s))))for(const t of e.querySelectorAll(`[name='${CSS.escape(i)}']`))O.mutate(t,r)}static errors(e,t,s){const i=t.filter(e=>"FIELD_ERROR"===e.type||"INVALID_FORMAT"===e.type),r=t.filter(e=>"FIELD_ERROR"!==e.type&&"INVALID_FORMAT"!==e.type);e.querySelectorAll("[name]").forEach(e=>e.setCustomValidity?.("")),e.querySelectorAll("ful-errors").forEach(e=>{e.replaceChildren(),e.setAttribute("hidden","")}),i.forEach(t=>{const s=t.context.replace("[",".").replace("].",".").replace("]","").split(".");for(let i=s.length;0!=i;--i){const r=s.slice(0,i).join("."),a=s.slice(i,s.length).join(".");e.querySelectorAll(`[name='${CSS.escape(r)}']`).forEach(e=>e.setCustomValidity?.(t.reason,a))}}),e.querySelectorAll("ful-errors").forEach(e=>{e.innerText=r.map(e=>e.reason).join("\n"),0!==r.length&&e.removeAttribute("hidden")}),0!=t.length&&s&&Array.from(e.querySelectorAll(":invalid")).sort((e,t)=>e.getBoundingClientRect().y-t.getBoundingClientRect().y)[0]?.focus()}}class R{#y;#w;#o;#E;#x;constructor(e,t,s,i,r){this.#y=e,this.#w=t,this.#o=s,this.#E=i,this.#x=r}prepare(e,t){return this.#E(e,t)}async submit(e,t){return await this.#y.request(this.#o,this.#w).json(e).fetch()}transform(e,t){return this.#x(e,t)}}class C{#E;#x;constructor(e,t){this.#E=e,this.#x=t}async prepare(e,t){return await this.#E(e,t)}async submit(e,t,s){return s}async transform(e,t){return await this.#x(e,t)}}class z{static create(e,t){const i=s.component("http-client"),r=e.hasAttribute("request-mapper")?s.component(e.getAttribute("request-mapper")):e=>e,a=e.hasAttribute("response-mapper")?s.component(e.getAttribute("response-mapper")):e=>e,n=e.getAttribute("action");if(!n)return new C(r,a);const l=e.getAttribute("method")??"POST";return new R(i,n,l,r,a)}}class I extends e{form;render(){const e=this.form=document.createElement("form");e.setAttribute("novalidate",""),t.forward("form-",this,e),e.replaceChildren(...this.childNodes),e.addEventListener("submit",async e=>{e.preventDefault(),e.stopPropagation(),await this.submit(e.submitter??void 0)}),this.hasAttribute("clear-invalid-on-change")&&this.addEventListener("change",e=>{e.target.setCustomValidity?.("")}),this.replaceChildren(e)}async submit(e){this.spinner(!0);try{const t=s.component(this.getAttribute("loader")??"loaders:form").create(this),i=O.extractFrom(this.form,e);let r=await t.prepare(i,this);try{const s=new CustomEvent("submit",{bubbles:!0,cancelable:!0,detail:{submitter:e,values:i,request:r}});if(!this.dispatchEvent(s))return;this.errors=[];const a=new CustomEvent("submit:requested",{bubbles:!0,cancelable:!1,detail:{submitter:e,values:s.detail.values,request:s.detail.request}});let n=await _.fireAsync(this,a,{mode:"pipeline"});r=a.detail.request,n=await t.submit(r,this,n);const l=await t.transform(n,this);this.dispatchEvent(new CustomEvent("submit:success",{bubbles:!0,cancelable:!1,detail:{submitter:e,values:i,request:r,response:l}}))}catch(t){this.dispatchEvent(new CustomEvent("submit:failure",{bubbles:!0,cancelable:!1,detail:{submitter:e,values:i,request:r,exception:t}})),t instanceof u&&(this.errors=t.problems),console.warn("failed to submit form",this,"reason:",t)}}finally{this.spinner(!1)}}reset(){this.form.reset()}spinner(e){this.querySelectorAll("ful-spinner").forEach(t=>{t.hidden=!e}),this.querySelectorAll("input,button").forEach(t=>{const s=t;"submit"!==s.type&&"reset"!==s.type||(s.disabled=e)})}set values(e){O.mutateIn(this.form,e)}get values(){return O.extractFrom(this.form)}set errors(e){O.errors(this.form,e,this.hasAttribute("scroll-on-error"))}}class D extends e{static observed=["value","readonly:presence","required:presence"];static slots=!0;static template='\n <div class="form-label">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </div>\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n {{{{ slots.before }}}}\n <input data-tpl-if="type != \'textarea\'" class="form-control" data-tpl-type="type" placeholder=" " form="">\n <textarea data-tpl-if="type == \'textarea\'" class="form-control" placeholder=" " form=""></textarea>\n {{{{ slots.after }}}}\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-field-error></ful-field-error>\n ';static formAssociated=!0;_input;_fieldError;constructor(){super(),this.internals=this.attachInternals(),this.internals.role="presentation"}_type(){return this.getAttribute("type")??"text"}_fragment(e,t){return this.template().withOverlay({type:e,slots:t}).render()}render({slots:e,observed:s,disabled:i,skipObservedSetup:r}){const a=this._type(),n=this._fragment(a,e);this._input=n.querySelector("input,textarea"),t.forward("input-",this,this._input),r||(this.disabled=i,this.readonly=s.readonly,this.required=s.required,this.value=s.value),this._input.addEventListener("keydown",e=>{if("Enter"!==e.key||"textarea"===this._type())return;const t=this.internals.form;if(!t)return;const s=Array.from(t.querySelectorAll("button:not(:disabled), input:not(:disabled)")).find(e=>"submit"===e.type);t.requestSubmit(s)}),this._input.addEventListener("input",e=>{const t=this.getAttribute("mask");if(!t)return;const s=e.target.value,i=s.replace(new RegExp(t,"g"),"");if(s===i)return;const r=e.target.selectionStart,a=s.length-i.length;e.target.value=i,e.target.setSelectionRange(r-a,r-a)}),this._input.addEventListener("change",e=>{e.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))});const l=n.querySelector("label");l.addEventListener("click",()=>this.focus()),this._fieldError=n.querySelector("ful-field-error"),this._input.ariaDescribedByElements=[this._fieldError],this._input.ariaLabelledByElements=[l],this.replaceChildren(n)}get value(){return""===this._input.value?null:this._input.value}set value(e){this._input.value=""===e?null:e}get readonly(){return this._input.readOnly}set readonly(e){this._input.readOnly=e,this.reflect(()=>{t.toggle(this,"readonly",e)})}get disabled(){return this._input.hasAttribute("disabled")}set disabled(e){t.toggle(this._input,"disabled",e)}get required(){return"true"===this._input.getAttribute("aria-required")}set required(e){t.set(this._input,"aria-required",e?"true":null),this.reflect(()=>{t.toggle(this,"required",e)})}focus(e){this._input.focus(e)}setCustomValidity(e){if(!e)return this.internals.setValidity({}),void(this._fieldError.innerText="");this.internals.setValidity({customError:!0}," "),this._fieldError.innerText=e}formResetCallback(){this.value=this.unmarshal("value",this.getAttribute("value"))}}class N extends e{render(){const e=this.innerHTML.trim();if(""===e)return void(this.innerHTML=this.getAttribute("default")??"");const t=this.getAttribute("locale")??Intl.DateTimeFormat().resolvedOptions().locale,s=new Intl.DateTimeFormat(t,{year:"numeric",month:"numeric",day:"numeric"}),[i,r,a]=e.split("-").map(Number);this.innerHTML=s.format(new Date(i,r-1,a))}}class M extends e{render(){const e=this.innerHTML.trim();if(""===e)return void(this.innerHTML=this.getAttribute("default")??"");const t=this.getAttribute("locale")??Intl.DateTimeFormat().resolvedOptions().locale,s=new Intl.DateTimeFormat(t,{year:"numeric",month:"numeric",day:"numeric",hour:"numeric",minute:"numeric",second:"numeric",hour12:!1});this.innerHTML=s.format(new Date(M.isoToLocal(e)))}static isoToLocal(e){const t=new Date(e),s=(e,t)=>String(t).padStart(e,"0");return`${`${t.getFullYear()}-${s(2,t.getMonth()+1)}-${s(2,t.getDate())}`}T${`${s(2,t.getHours())}:${s(2,t.getMinutes())}:${s(2,t.getSeconds())}.${s(3,t.getMilliseconds())}`}`}}class P extends D{static observed=["value","readonly:presence","required:presence","min","max","step"];_type(){return"date"}render(e){const{observed:t}=e;super.render(e),this.min=t.min,this.max=t.max,this.step=t.step}get min(){const e=this._input.min;return""===e?null:e}set min(e){this._input.min=P.#A(e)}get max(){const e=this._input.max;return""===e?null:e}set max(e){this._input.max=P.#A(e)}get step(){const e=this._input.step;return""===e?null:e}set step(e){this._input.step=e??""}static#A(e){if(!e)return"";if("now"===e)return(new Date).toISOString().split("T")[0];const t=/^([+-])(\d+)([dmy])$/.exec(e);if(!t)return e;const s="-"===t[1]?-1:1,i=+t[2],r=new Date;switch(t[3]){case"d":r.setDate(r.getDate()+i*s);break;case"m":r.setMonth(r.getMonth()+i*s);break;case"y":r.setFullYear(r.getFullYear()+i*s)}return r.toISOString().split("T")[0]}}class B extends P{_type(){return"time"}}class $ extends D{static observed=["value","readonly:presence","required:presence","min","max","step"];_type(){return"datetime-local"}render(e){const{observed:t}=e;super.render(e),this.min=t.min,this.max=t.min,this.step=t.min}get value(){const e=this._input.value;return""===e?null:new Date(e).toISOString()}set value(e){this._input.value=e?M.isoToLocal(e):""}get min(){const e=this._input.min;return""===e?null:new Date(e).toISOString()}set min(e){this._input.min=e?M.isoToLocal(e):""}get max(){const e=this._input.max;return""===e?null:new Date(e).toISOString()}set max(e){this._input.max=e?M.isoToLocal(e):""}get step(){const e=this._input.step;return""===e?null:e}set step(e){this._input.step=e??""}}class U extends D{static l10n={en:{dropzonelabel:"Click or drop your files here",unaccepptablefiletype:"Only files of type {0} are supported",maxfilesizeexceeded:"Maximum supported file size is {0}",maxtotalsizeexceeded:"Maximum supported total file size is {0}",maxfilesexceeded:"Maximum files count exceeded"},it:{dropzonelabel:"Clicca o trascina i file qui",unaccepptablefiletype:"Solo i file di tipo {0} sono supportati",maxfilesizeexceeded:"La dimensione massima di un file è di {0}",maxtotalsizeexceeded:"La dimensione massima complessiva dei file è di {0}",maxfilesexceeded:"Numero massimo di file superato"}};static observed=["value","readonly:presence","required:presence","accept:csv","multiple:presence","itemlist:presence","dropzone:presence","maxfiles:number","maxfilesize:number","maxtotalsize:number"];#T;#q;#S;#k;_type(){return"file"}static template='\n <div class="form-label">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </div>\n <div class="input-group">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n {{{{ slots.before }}}}\n <input class="form-control" data-tpl-type="type" placeholder=" " form="">\n {{{{ slots.after }}}}\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <div data-ref="dropzone" class="dropzone" data-tpl-if="slots.dropzone">\n {{{{ slots.dropzone }}}}\n </div>\n <div data-ref="dropzone" class="default-dropzone" data-tpl-if="!slots.dropzone">\n {{ #l10n:t(\'dropzonelabel\') }}\n </div>\n <ful-item-list></ful-item-list>\n <ful-field-warnings></ful-field-warnings>\n <ful-field-error></ful-field-error>\n ';static templates={items:'\n <ful-item data-tpl-each="files" data-tpl-var="file" data-tpl-data-name="file.name">\n <div>{{ file.name }}</div>\n <div>{{ #bytes:format(file.size) }}</div>\n <button type="button" class="btn btn-sm btn-outline-danger bi bi-x-lg" alt="Rimuovi"></button>\n </ful-item>\n ',warning:"<ful-field-warning>{{ #l10n:t(key, args) }}</ful-field-warning>"};render(e){const{observed:t}=e;super.render(e),this.#q=this.querySelector("ful-item-list"),this.#S=this.querySelector("[data-ref=dropzone]"),this.#k=this.querySelector("ful-field-warnings"),this.accept=t.accept,this.multiple=t.multiple,this.itemlist=t.itemlist,this.dropzone=t.dropzone,this.maxfiles=t.maxfiles,this.maxfilesize=t.maxfilesize,this.maxtotalsize=t.maxtotalsize,this.#k.addEventListener("animationend",e=>{e.target.remove()}),this.#q.addEventListener("click",e=>{if(!e.target.closest("button"))return;const t=e.target.closest("ful-item").dataset.name,s=new DataTransfer;[...this.files].filter(e=>e.name!==t).forEach(e=>s.items.add(e)),this.files=s.files,this.#_()}),this.#S.addEventListener("click",e=>{this.querySelector("input")?.click()}),this.#S.addEventListener("dragover",e=>{e.preventDefault()}),this.#S.addEventListener("drop",e=>{e.preventDefault();const t=new DataTransfer;[...e.dataTransfer.items].filter(e=>"file"===e.kind).forEach(e=>t.items.add(e.getAsFile())),this.files=t.files,this.#_()}),this._input.addEventListener("change",e=>{this.#_()})}#L(e){return e>1048576?Math.round(e/1024/1024*100)/100+"MiB":e>1024?Math.round(e/1024*100)/100+"KiB":`${e}B`}#_(){this.setCustomValidity(),this.#O(),this.#R(),this.#C(),this.#z(),this.template("items").withOverlay({files:this.files}).withModule("bytes",{format:this.#L}).renderTo(this.#q)}warning(e,t){this.template("warning").withOverlay({key:e,args:t}).renderTo(this.#k)}#O(){if(!this.#T.length)return;const e=[...this.files].filter(e=>!this.#T.some(t=>e.name.toLowerCase().endsWith(t.toLowerCase())));if(0===e.length)return;this.warning("unaccepptablefiletype",this.#T.join(", "));const t=new DataTransfer;[...this.files].filter(t=>!e.includes(t)).forEach(e=>t.items.add(e)),this.files=t.files}#z(){if(null===this.#I)return;if(this.files.length<=this.#I)return;this.warning("maxfilesexceeded");const e=new DataTransfer;this.files=e.files}#R(){if(null===this.#D)return;const e=[...this.files].filter(e=>e.size>this.#D);if(0===e.length)return;this.warning("maxfilesizeexceeded",this.#L(this.#D));const t=new DataTransfer;[...this.files].filter(t=>!e.includes(t)).forEach(e=>t.items.add(e)),this.files=t.files}#C(){if(null===this.#N)return;[...this.files].reduce((e,t)=>e+t.size,0)<=this.#N||(this.warning("maxtotalsizeexceeded",this.#L(this.#N)),this.files=(new DataTransfer).files)}get accept(){return this.#T}set accept(e){this._input.accept=e.join(","),this.#T=e,this.reflect(()=>{this.setAttribute("accept",this._input.accept)})}get multiple(){return this._input.multiple}set multiple(e){this._input.multiple=e,this.reflect(()=>{t.toggle(this,"multiple",e)})}get files(){return this._input.files}set files(e){this._input.files=e}get file(){return this.files[0]??null}set file(e){const t=new DataTransfer;t.items.add(e),this.files=t.files}get value(){const e=Array.from(this._input.files).map(e=>e.name);return this.multiple?e:e[0]??null}set value(e){}get totalsize(){return Array.from(this.files).reduce((e,t)=>e+t.size,0)}#I;get maxfiles(){return this.#I}set maxfiles(e){this.#I=e,this.reflect(()=>{t.set(this,"maxfiles",e)})}#D;get maxfilesize(){return this.#D}set maxfilesize(e){this.#D=e,this.reflect(()=>{t.set(this,"maxfilesize",e)})}#N;get maxtotalsize(){return this.#N}set maxtotalsize(e){this.#N=e,this.reflect(()=>{t.set(this,"maxtotalsize",e)})}#M;get itemlist(){return this.#M}set itemlist(e){this.#M=e,this.reflect(()=>{t.toggle(this,"itemlist",e)})}#P;get dropzone(){return this.#P}set dropzone(e){this.#P=e,this.reflect(()=>{t.toggle(this,"dropzone",e)})}}class F{#y;#w;#o;#x;#B;#$;#U;constructor({http:e,url:t,method:s,responseMapper:i,prefetch:r,revision:a}){this.#y=e,this.#w=t,this.#o=s,this.#x=i,this.#B=r,this.#$=a,this.#U=null}async prefetch(){this.#B&&await this.#F()}async exact(...e){return await this.#F(),this.#U.filter(([t,s])=>e.some(e=>e==t))}async load(e){return await this.#F(),this.#U.filter(([t,s])=>(s??"").toLowerCase().includes(e?.toLowerCase()))}async reconfigureUrl(e){this.#U=null,this.#w=e}async#F(){if(null!==this.#U)return;const e=await F.#j(this.#y,this.#o,this.#w,this.#$);this.#U=this.#x(e)}static async#j(e,t,s,i){const r=`${t}@${s}`;if(null!==i){const e=A.load(r,i);if(void 0!==e)return e}const a=await e.request(t,s).fetchJson();return null!==i&&A.save(r,i,a),a}}class j{#y;#w;#o;#x;constructor({http:e,url:t,method:s,responseMapper:i}){this.#y=e,this.#w=t,this.#o=s,this.#x=i}async exact(...e){const t=await this.#y.request(this.#o,this.#w).param("k",...e).fetchJson();return this.#x(t)}async load(e){const t=await this.#y.request(this.#o,this.#w).param("s",e).fetchJson();return this.#x(t)}}class H{#U;constructor(e){this.#U=e}update(e){this.#U=e}exact(...e){return this.#U.filter(([t,s])=>e.some(e=>e==t))}load(e){return this.#U.filter(([t,s])=>(s??"").toLowerCase().includes(e?.toLowerCase()))}}class V{static create(e,t){if(!e.hasAttribute("src")){const e=Array.from(t.options?.querySelectorAll("option")??[]).map(e=>[e.getAttribute("value")??e.innerText.trim(),e.innerText.trim()]);return new H(e)}const i=s.component("http-client"),r=V.#H(e);return"chunked"==e.getAttribute("mode")?new j({http:i,url:e.getAttribute("src"),method:e.getAttribute("method")??"POST",responseMapper:r}):new F({http:i,url:e.getAttribute("src"),method:e.getAttribute("method")??"POST",responseMapper:r,prefetch:e.hasAttribute("preload"),revision:e.getAttribute("revision")})}static#H(e){return e.hasAttribute("k-expr")&&e.hasAttribute("l-expr")?t=>s.evaluator().withOverlay(t).evaluateExpression(e.getAttribute("d-expr")??"self").map(t=>{const i=s.evaluator().withOverlay(t);return[i.evaluateExpression(e.getAttribute("k-expr")),i.evaluateExpression(e.getAttribute("l-expr")),i.evaluateExpression(e.getAttribute("m-expr")??"self")]}):e.hasAttribute("response-mapper")?s.component(e.getAttribute("response-mapper")):e=>e}}class G extends e{static slots=!0;static template='\n <ful-spinner class="centered" hidden></ful-spinner>\n <menu tabindex="-1" hidden></menu>\n ';static templates={options:'\n <li data-tpl-each="self" data-tpl-selected="index == 0" data-tpl-value="index">\n {{ label }}\n </li>\n '};#V;#G;#J;#p=new Map;render({slots:e}){const t=this.template().render();this.#J=i.isBlank(e.default)?this.template("options"):r.fromFragment(e.default),this.#V=t.querySelector("ful-spinner"),this.#G=t.querySelector("menu"),this.#G.addEventListener("click",e=>{e.stopPropagation();const t=e.target.closest("li");t?this.#W(t):this.hide()}),this.replaceChildren(t)}acceptSelection(){const e=this.#G.querySelector("[selected]")??this.#G.firstElementChild;this.#W(e)}update(e){if(void 0===e)throw new Error("null data");this.#p=new Map(e.map((e,t)=>[String(t),e]));const t=e.map(([e,t,s],i)=>({index:i,key:e,label:t,metadata:s}));this.#J.withOverlay(t).renderTo(this.#G)}#W(e){const t=e.getAttribute("value"),s=this.#p.get(t);this.hide(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{index:t,data:s}}))}hide(){this.setAttribute("hidden","")}get shown(){return!this.hasAttribute("hidden")}async show(e){this.removeAttribute("hidden"),this.#G.setAttribute("hidden",""),this.#V.removeAttribute("hidden");try{const t=await e();this.update(t)}finally{this.#V.setAttribute("hidden",""),this.#G.removeAttribute("hidden")}}async moveOrShow(e,t){if(this.shown){const t=this.#G.querySelector("[selected]")??this.#G.firstElementChild,s=t[(e?"next":"previous")+"ElementSibling"];return void(s&&(t.removeAttribute("selected"),s.setAttribute("selected",""),s.scrollIntoView({block:"nearest",behavior:"smooth"})))}await this.show(t)}}class J extends e{static observed=["value:csvm","readonly:presence","required:presence","itemlist:presence"];static slots=!0;static template='\n <div class="form-label">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </div>\n <div class="input-group flex-nowrap" tabindex="-1">\n <span data-tpl-if="slots.ibefore" class="input-group-text">{{{{ slots.ibefore }}}}</span>\n {{{{ slots.before }}}}\n <div class="ful-select-input-container">\n <div class="ful-select-input">\n <badges></badges>\n <input type="text" form="">\n </div>\n <ful-dropdown hidden popover="manual">{{{{ slots.dropdown }}}}</ful-dropdown>\n </div>\n {{{{ slots.after }}}}\n <span data-tpl-if="slots.iafter" class="input-group-text">{{{{ slots.iafter }}}}</span>\n </div>\n <ful-item-list></ful-item-list>\n <ful-field-error></ful-field-error>\n ';static templates={items:'\n <ful-item data-tpl-each="entries" data-tpl-var="entry" data-tpl-data-key="entry[0]">\n <div>{{ entry[1][0] }}</div>\n <button type="button" class="btn btn-sm btn-outline-danger bi bi-x-lg"></button>\n </ful-item>\n '};static formAssociated=!0;internals;#K;#Y;#Q;#X;#q;#Z;#ee;#te=new Map;constructor(){super(),this.internals=this.attachInternals(),this.internals.role="presentation"}async render({slots:e,observed:i,disabled:r}){const a=this.getAttribute("name");this.#K=s.component(this.getAttribute("loader")??"loaders:select").create(this,{options:e.options}),this.#Z=this.hasAttribute("multiple"),await(this.#K.prefetch?.());const n=this.template().withOverlay({slots:e,name:a}).render();this.#X=n.querySelector("input"),this.#q=n.querySelector("ful-item-list"),t.forward("input-",this,this.#X),this.#Y=n.querySelector("badges"),this.value=i.value,this.disabled=r,this.readonly=i.readonly,this.required=i.required,this.itemlist=i.itemlist,this.#Q=n.querySelector("ful-dropdown");const l=n.querySelector("label");l.addEventListener("click",()=>this.focus()),this.#ee=n.querySelector("ful-field-error"),this.#X.ariaDescribedByElements=[this.#ee],this.#X.ariaLabelledByElements=[l];const o=this,[u,d]=L.throttle(400,()=>o.#Q.show(()=>o.#K.load(o.#X.value)));this.addEventListener("click",e=>{e.target.matches("input")||this.disabled||this.readonly||(this.#Q.shown?this.#Q.hide():(this.#X.focus(),u()))}),this.#q.addEventListener("click",e=>{if(e.stopPropagation(),!e.target.closest("button"))return;if(this.disabled||this.readonly)return;const t=[...this.#q.children].indexOf(e.target.closest("ful-item"));-1!==t&&(this.#te.delete(Array.from(this.#te.keys())[t]),this.#se(),this.#ie())}),this.#Y.addEventListener("click",e=>{if(e.stopPropagation(),this.disabled||this.readonly)return;const t=[...this.#Y.children].indexOf(e.target);-1!==t&&(this.#te.delete(Array.from(this.#te.keys())[t]),this.#se(),this.#ie())}),this.#X.addEventListener("change",e=>{e.stopPropagation()}),this.#X.addEventListener("blur",e=>{e.stopPropagation(),e.relatedTarget&&this.contains(e.relatedTarget)||(d(),this.#Q.hide(),this.#X.value="")}),this.#X.addEventListener("keydown",e=>{if(!this.disabled&&!this.readonly)switch(e.code){case"ArrowUp":e.preventDefault(),this.#Q.moveOrShow(!1,()=>o.#K.load(o.#X.value));break;case"ArrowDown":e.preventDefault(),this.#Q.moveOrShow(!0,()=>o.#K.load(o.#X.value));break;case"Escape":this.#Q.hide();break;case"Enter":e.preventDefault(),this.#Q.acceptSelection(),this.#X.value="";break;case"Backspace":this.#te.size&&0===this.#X.selectionStart&&0===this.#X.selectionEnd&&(this.#te.delete(Array.from(this.#te.keys()).pop()),this.#se(),this.#ie());break;case"Tab":this.#Q.hide(),d()}}),this.#X.addEventListener("input",e=>{e.stopPropagation(),this.disabled||this.readonly||u()}),this.#Q.addEventListener("change",e=>{e.stopPropagation(),this.#Z||this.#te.clear(),this.#te.set(e.detail.data[0],e.detail.data.slice(1)),this.#se(),this.#ie(),this.#X.focus(),this.#Q.hide(),this.#X.value=""}),this.replaceChildren(n)}async withLoader(e){return await e(this.#K)}#se(){const e=[...this.#te.entries()].map(e=>({key:e[0],label:e[1][0],metadata:e[1].slice(1)})),t=this.#Z?e:e[0]??null;this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:t}}))}#ie(){const e=Array.from(this.#te.entries()).map(([e,t])=>{const s=document.createElement("badge");return s.setAttribute("role","button"),s.setAttribute("value",e),s.innerText=t[0],s});this.#Y.replaceChildren(),this.#Y.append(...e),this.#q.replaceChildren(),this.template("items").withOverlay({entries:this.#te.entries()}).renderTo(this.#q)}set value(e){if(null===e)return this.#te=new Map,void this.#ie();(async()=>{const t=await(this.#Z?this.#K.exact(...e):this.#K.exact(e));this.#te=new Map(t.map(e=>[e[0],e.slice(1)])),this.#ie()})()}get value(){return this.#Z?[...this.#te.keys()]:[...this.#te.keys()][0]??null}get entry(){return this.#Z?[...this.#te.entries()]:[...this.#te.entries()][0]??null}get disabled(){return this.#X.hasAttribute("disabled")}set disabled(e){t.toggle(this.#X,"disabled",e)}get readonly(){return this.#X.readOnly}set readonly(e){this.#X.readOnly=e,this.reflect(()=>{t.toggle(this,"readonly",e)})}get required(){return"true"===this.#X.getAttribute("aria-required")}set required(e){t.set(this.#X,"aria-required",e?"true":null),this.reflect(()=>{t.toggle(this,"required",e)})}#M;get itemlist(){return this.#M}set itemlist(e){this.#M=e,this.reflect(()=>{t.toggle(this,"itemlist",e)})}focus(e){this.#X.focus(e)}setCustomValidity(e){if(!e)return this.internals.setValidity({}),void(this.#ee.innerText="");this.internals.setValidity({customError:!0}," "),this.#ee.innerText=e}}class W extends e{static observed=["value","readonly:presence","required:presence"];static slots=!0;static template='\n <fieldset>\n <legend class="form-label">\n {{{{ slots.default }}}}\n </legend>\n <header data-tpl-if="slots.header">\n {{{{ slots.header }}}}\n </header>\n <section>\n <div class="label-wrapper" data-tpl-each="inputsAndLabels" data-tpl-var="ial">\n <label>\n {{{{ ial[0] }}}}\n <div>{{{{ ial[1] }}}}</div>\n </label>\n </div>\n </section>\n <ful-field-error></ful-field-error>\n <footer data-tpl-if="slots.footer">\n {{{{ slots.footer }}}}\n </footer>\n </fieldset>\n ';static formAssociated=!0;#re;#ee;#ae;#ne;constructor(){super(),this.internals=this.attachInternals(),this.internals.role="radiogroup"}render({slots:e,observed:s,disabled:r}){const a=this.getAttribute("name")??t.uid("ful-radiogroup"),n=Array.from(e.default.querySelectorAll("ful-radio")),l=n.map(e=>{const s=document.createElement("input");s.setAttribute("type","radio"),t.forward("input-",this,s),t.forward("",e,s),s.setAttribute("name",`${a}-ignore`),s.setAttribute("form",""),s.addEventListener("change",e=>{e.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))});return[s,i.fromChildNodes(e)]});n.forEach(e=>e.remove()),this.template().withOverlay({name:a,slots:e,inputsAndLabels:l}).renderTo(this),this.#re=this.firstElementChild,this.disabled=r,this.readonly=s.readonly,this.required=s.required,this.value=s.value,this.#ee=this.querySelector("ful-field-error"),this.ariaDescribedByElements=[this.#ee],this.#ae=this.querySelector("input[type=radio]"),this.#ne="boolean"===this.getAttribute("type")}get value(){const e=this.querySelector("input[type=radio]:checked");return e?this.#ne?"true"===e.value:e.value:null}set value(e){if(null===e)return void this.querySelectorAll("input[type=radio]").forEach(e=>{e.checked=!1});const t=this.querySelector(`input[type=radio][value=${CSS.escape(String(e))}]`);t&&(t.checked=!0)}get readonly(){return this.#re.inert}set readonly(e){this.#re.inert=e,this.reflect(()=>{t.toggle(this,"readonly",e)})}get disabled(){return this.#re.hasAttribute("disabled")}set disabled(e){t.toggle(this.#re,"disabled",e)}get required(){return"true"===this.#re.getAttribute("aria-required")}set required(e){t.set(this.#re,"aria-required",e?"true":null),this.reflect(()=>{t.toggle(this,"required",e)})}focus(e){this.#ae.focus(e)}setCustomValidity(e){if(!e)return this.internals.setValidity({}),void(this.#ee.innerText="");this.internals.setValidity({customError:!0}," "),this.#ee.innerText=e}}class K extends e{static observed=["value:bool","readonly:presence","required:presence"];static slots=!0;static template='\n <div data-tpl-class="klass">\n <div class="input-container">\n <input class="form-check-input" type="checkbox" data-tpl-role="isSwitch ? \'switch\' : false" form="" placeholder=" ">\n </div>\n <div class="form-check-label">\n <label>{{{{ slots.default }}}}</label>\n {{{{ slots.info }}}}\n </div>\n </div>\n <ful-field-error></ful-field-error>\n ';#le;#X;#ee;static formAssociated=!0;constructor(){super(),this.internals=this.attachInternals(),this.internals.role="presentation"}render({slots:e,observed:s,disabled:i}){const r="switch"==this.getAttribute("type"),a=r?"form-check form-switch":"form-check",n=this.template().withOverlay({slots:e,klass:a,isSwitch:r}).render();this.#le=n.firstElementChild,this.#X=n.querySelector("input"),t.forward("input-",this,this.#X),this.disabled=i,this.readonly=s.readonly,this.required=s.required,this.value=s.value,this.#X.addEventListener("change",e=>{e.stopPropagation(),this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}}))});const l=n.querySelector("label");l.addEventListener("click",()=>{this.focus(),this.disabled||this.readonly||(this.value=!this.value,this.dispatchEvent(new CustomEvent("change",{bubbles:!0,cancelable:!1,detail:{value:this.value}})))}),this.#ee=n.querySelector("ful-field-error"),this.#X.ariaDescribedByElements=[this.#ee],this.#X.ariaLabelledByElements=[l],this.replaceChildren(n)}get value(){return this.#X.checked}set value(e){this.#X.checked=e}get readonly(){return this.#le.inert}set readonly(e){this.#le.inert=e,this.reflect(()=>{t.toggle(this,"readonly",e)})}get disabled(){return this.#X.hasAttribute("disabled")}set disabled(e){t.toggle(this.#X,"disabled",e)}get required(){return"true"===this.#X.getAttribute("aria-required")}set required(e){t.set(this.#X,"aria-required",e?"true":null),this.reflect(()=>{t.toggle(this,"required",e)})}focus(e){this.#X.focus(e)}setCustomValidity(e){if(!e)return this.internals.setValidity({}),void(this.#ee.innerText="");this.internals.setValidity({customError:!0}," "),this.#ee.innerText=e}}class Y extends e{static slots=!0;static template='\n <div class="ful-spinner-wrapper" role="status">\n <div class="ful-spinner-text">{{{{ slots.default }}}}</div>\n <div class="ful-spinner-icon"></div>\n </div>\n ';render({slots:e}){this.template().withOverlay({slots:e}).renderTo(this)}}class Q extends e{static observed=["order"];#oe;render(){const e=this.getAttribute("sorter"),t=["asc","desc",null];this.addEventListener("click",()=>{const s=t[(t.indexOf(this.order)+1)%3];this.dispatchEvent(new CustomEvent("sort-requested",{bubbles:!0,cancelable:!0,detail:{value:{sorter:e,order:s}}}))})}get order(){return this.#oe||null}set order(e){this.#oe=e||null,this.reflect(()=>{this.#oe?this.setAttribute("order",e):this.removeAttribute("order")})}}class X extends e{static observed=["total:number","current:number"];static l10n={en:{showing:"Page {0} of {1}",navigation:"Page navigation",previous:"Previous",next:"Next"},it:{showing:"Pagina {0} di {1}",navigation:"Navigazione pagine",previous:"Precedente",next:"Successivo"}};static config={prevIcon:"bi bi-chevron-left",nextIcon:"bi bi-chevron-right",reloadIcon:"bi bi-arrow-clockwise"};static template='\n <nav data-tpl-aria-label="#l10n:t(\'navigation\')" class="user-select-none">\n <ul class="pagination">\n <li class="page-item ms-auto me-2 pagination-index"> {{ #l10n:t(\'showing\', curr.label, total) }}</li>\n <li class="page-item me-2 reload"><a role="button"><i data-tpl-class="config.reloadIcon"></i></a></li>\n <li class="page-item prev">\n <a data-tpl-class="prev.enabled?\'page-link\':\'page-link disabled\'" data-tpl-aria-label="#l10n:t(\'previous\')" role="button" data-tpl-data-page="prev.index">\n <i aria-hidden="true" data-tpl-class="config.prevIcon"></i>\n </a>\n </li>\n <li class="page-item" data-tpl-each="pages" data-tpl-var="page">\n <a data-tpl-class="curr.index != page.index ? \'page-link\': \'page-link disabled\'" role="button" data-tpl-data-page="page.index" >\n {{ page.label }}\n </a>\n </li>\n <li class="page-item next">\n <a data-tpl-class="next.enabled?\'page-link\':\'page-link disabled\'" data-tpl-aria-label="#l10n:t(\'next\')" role="button" data-tpl-data-page="next.index">\n <i aria-hidden="true" data-tpl-class="config.nextIcon"></i>\n </a>\n </li>\n </ul>\n </nav>\n ';#ue=0;#n=0;render({observed:e}){this.update(e.current??0,e.total??0),this.addEventListener("click",e=>{const t=e.target.closest("a");t&&this.dispatchEvent(new CustomEvent("page-requested",{bubbles:!0,cancelable:!0,detail:{value:Number(t.dataset.page??this.#n)}}))})}update(e,t){const s=Number(this.getAttribute("pages")??"5"),i={index:Math.max(0,e-1),enabled:e>0},r={index:e,label:e+1},a={index:Math.min(t,e+1),enabled:e+1<t},n=[{index:e,label:e+1}];for(let i=e,r=1;r!==s&&n.length!=s;++r){const e=i-r;e>=0&&n.unshift({index:e,label:e+1});const s=i+r;s<t&&n.push({index:s,label:s+1})}this.template().withOverlay({total:t,prev:i,curr:r,next:a,pages:n}).renderTo(this)}get total(){return this.#ue}set total(e){this.#ue=e,this.reflect(()=>{this.setAttribute("total",String(e)),this.update(this.#n??0,this.#ue)})}get current(){return this.#n}set current(e){this.#n=e,this.reflect(()=>{this.setAttribute("current",String(e)),this.update(this.#n,this.#ue??0)})}}class Z{static parse(e,t){const s=a.queryChildren(e,"schema");if(!s)throw new Error(`missing expected <schema> in ${e}`);const r=document.createElement("tr"),n=document.createElement("tr");n.setAttribute("data-tpl-each","rows");for(const e of s.getAttributeNames()){const t=s.getAttribute(e);r.setAttribute(e,t??""),n.setAttribute(e,t??"")}const l=a.queryChildrenAll(s,"column"),o=l.filter(e=>e.hasAttribute("order")).map(e=>({sorter:e.getAttribute("sorter"),order:e.getAttribute("order")}))[0]??null;for(var u of l){const e=a.queryChildren(u,"title"),t=u.getAttribute("sorter"),s=u.getAttribute("order"),i=e??document.createTextNode(u.getAttribute("title")??"");e?.remove(),u.removeAttribute("sorter"),u.removeAttribute("order"),u.removeAttribute("title");const l=t||s?(()=>{const e=document.createElement("ful-sorter");return t&&e.setAttribute("sorter",t),s&&e.setAttribute("order",s),e.append(i),e})():i,o=document.createElement("th"),d=document.createElement("td");for(const e of u.getAttributeNames()){const t=u.getAttribute(e);o.setAttribute(e,t??""),d.setAttribute(e,t??"")}o.append(l),d.append(...u.childNodes),r.append(o),n.append(d)}return{headersTemplate:t.withOverlay({inHeaders:!0,inRows:!1}).withFragment(i.from(r)),rowsTemplate:t.withOverlay({inHeaders:!1,inRows:!0}).withFragment(i.from(n)),sort:o,length:l.length}}}class ee{#U;constructor(e){this.#U=e}async load(e,t,s){return{page:this.#U,size:this.#U.length}}update(e){this.#U=e}}class te{#y;#w;#o;constructor(e,t,s){this