@everymatrix/general-input 1.22.1 → 1.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/checkbox-group-input_10.cjs.entry.js +18187 -27766
- package/dist/components/active-mixin.js +2 -92
- package/dist/components/checkbox-group-input2.js +273 -2801
- package/dist/components/date-input2.js +69 -2525
- package/dist/components/field-mixin.js +2321 -1307
- package/dist/components/input-field-shared-styles.js +25 -679
- package/dist/components/password-input2.js +7 -1736
- package/dist/components/vaadin-button.js +1 -1346
- package/dist/components/vaadin-combo-box.js +47 -1758
- package/dist/components/virtual-keyboard-controller.js +83 -161
- package/dist/esm/checkbox-group-input_10.entry.js +18187 -27766
- package/dist/general-input/general-input.esm.js +1 -1
- package/dist/general-input/p-bcde6ed8.entry.js +3646 -0
- package/package.json +1 -1
- package/dist/general-input/p-983d18d7.entry.js +0 -4143
|
@@ -55,26 +55,91 @@ const t$1=window,e$2=t$1.ShadowRoot&&(void 0===t$1.ShadyCSS||t$1.ShadyCSS.native
|
|
|
55
55
|
* @license
|
|
56
56
|
* Copyright 2017 Google LLC
|
|
57
57
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
58
|
-
*/var s$2;const e$1=window,r$1=e$1.trustedTypes,h$1=r$1?r$1.emptyScript:"",o$2=e$1.reactiveElementPolyfillSupport,n$2={toAttribute(t,i){switch(i){case Boolean:t=t?h$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,i){let s=t;switch(i){case Boolean:s=null!==t;break;case Number:s=null===t?null:Number(t);break;case Object:case Array:try{s=JSON.parse(t);}catch(t){s=null;}}return s}},a$1=(t,i)=>i!==t&&(i==i||t==t),l$2={attribute:!0,type:String,converter:n$2,reflect:!1,hasChanged:a$1},d$1="finalized";class u$1 extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this.
|
|
58
|
+
*/var s$2;const e$1=window,r$1=e$1.trustedTypes,h$1=r$1?r$1.emptyScript:"",o$2=e$1.reactiveElementPolyfillSupport,n$2={toAttribute(t,i){switch(i){case Boolean:t=t?h$1:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t);}return t},fromAttribute(t,i){let s=t;switch(i){case Boolean:s=null!==t;break;case Number:s=null===t?null:Number(t);break;case Object:case Array:try{s=JSON.parse(t);}catch(t){s=null;}}return s}},a$1=(t,i)=>i!==t&&(i==i||t==t),l$2={attribute:!0,type:String,converter:n$2,reflect:!1,hasChanged:a$1},d$1="finalized";class u$1 extends HTMLElement{constructor(){super(),this._$Ei=new Map,this.isUpdatePending=!1,this.hasUpdated=!1,this._$El=null,this._$Eu();}static addInitializer(t){var i;this.finalize(),(null!==(i=this.h)&&void 0!==i?i:this.h=[]).push(t);}static get observedAttributes(){this.finalize();const t=[];return this.elementProperties.forEach(((i,s)=>{const e=this._$Ep(s,i);void 0!==e&&(this._$Ev.set(e,s),t.push(e));})),t}static createProperty(t,i=l$2){if(i.state&&(i.attribute=!1),this.finalize(),this.elementProperties.set(t,i),!i.noAccessor&&!this.prototype.hasOwnProperty(t)){const s="symbol"==typeof t?Symbol():"__"+t,e=this.getPropertyDescriptor(t,s,i);void 0!==e&&Object.defineProperty(this.prototype,t,e);}}static getPropertyDescriptor(t,i,s){return {get(){return this[i]},set(e){const r=this[t];this[i]=e,this.requestUpdate(t,r,s);},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)||l$2}static finalize(){if(this.hasOwnProperty(d$1))return !1;this[d$1]=!0;const t=Object.getPrototypeOf(this);if(t.finalize(),void 0!==t.h&&(this.h=[...t.h]),this.elementProperties=new Map(t.elementProperties),this._$Ev=new Map,this.hasOwnProperty("properties")){const t=this.properties,i=[...Object.getOwnPropertyNames(t),...Object.getOwnPropertySymbols(t)];for(const s of i)this.createProperty(s,t[s]);}return this.elementStyles=this.finalizeStyles(this.styles),!0}static finalizeStyles(i){const s=[];if(Array.isArray(i)){const e=new Set(i.flat(1/0).reverse());for(const i of e)s.unshift(c$1(i));}else void 0!==i&&s.push(c$1(i));return s}static _$Ep(t,i){const s=i.attribute;return !1===s?void 0:"string"==typeof s?s:"string"==typeof t?t.toLowerCase():void 0}_$Eu(){var t;this._$E_=new Promise((t=>this.enableUpdating=t)),this._$AL=new Map,this._$Eg(),this.requestUpdate(),null===(t=this.constructor.h)||void 0===t||t.forEach((t=>t(this)));}addController(t){var i,s;(null!==(i=this._$ES)&&void 0!==i?i:this._$ES=[]).push(t),void 0!==this.renderRoot&&this.isConnected&&(null===(s=t.hostConnected)||void 0===s||s.call(t));}removeController(t){var i;null===(i=this._$ES)||void 0===i||i.splice(this._$ES.indexOf(t)>>>0,1);}_$Eg(){this.constructor.elementProperties.forEach(((t,i)=>{this.hasOwnProperty(i)&&(this._$Ei.set(i,this[i]),delete this[i]);}));}createRenderRoot(){var t;const s=null!==(t=this.shadowRoot)&&void 0!==t?t:this.attachShadow(this.constructor.shadowRootOptions);return S$1(s,this.constructor.elementStyles),s}connectedCallback(){var t;void 0===this.renderRoot&&(this.renderRoot=this.createRenderRoot()),this.enableUpdating(!0),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var i;return null===(i=t.hostConnected)||void 0===i?void 0:i.call(t)}));}enableUpdating(t){}disconnectedCallback(){var t;null===(t=this._$ES)||void 0===t||t.forEach((t=>{var i;return null===(i=t.hostDisconnected)||void 0===i?void 0:i.call(t)}));}attributeChangedCallback(t,i,s){this._$AK(t,s);}_$EO(t,i,s=l$2){var e;const r=this.constructor._$Ep(t,s);if(void 0!==r&&!0===s.reflect){const h=(void 0!==(null===(e=s.converter)||void 0===e?void 0:e.toAttribute)?s.converter:n$2).toAttribute(i,s.type);this._$El=t,null==h?this.removeAttribute(r):this.setAttribute(r,h),this._$El=null;}}_$AK(t,i){var s;const e=this.constructor,r=e._$Ev.get(t);if(void 0!==r&&this._$El!==r){const t=e.getPropertyOptions(r),h="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==(null===(s=t.converter)||void 0===s?void 0:s.fromAttribute)?t.converter:n$2;this._$El=r,this[r]=h.fromAttribute(i,t.type),this._$El=null;}}requestUpdate(t,i,s){let e=!0;void 0!==t&&(((s=s||this.constructor.getPropertyOptions(t)).hasChanged||a$1)(this[t],i)?(this._$AL.has(t)||this._$AL.set(t,i),!0===s.reflect&&this._$El!==t&&(void 0===this._$EC&&(this._$EC=new Map),this._$EC.set(t,s))):e=!1),!this.isUpdatePending&&e&&(this._$E_=this._$Ej());}async _$Ej(){this.isUpdatePending=!0;try{await this._$E_;}catch(t){Promise.reject(t);}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){var t;if(!this.isUpdatePending)return;this._$Ei&&(this._$Ei.forEach(((t,i)=>this[i]=t)),this._$Ei=void 0);let i=!1;const s=this._$AL;try{i=this.shouldUpdate(s),i?(this.willUpdate(s),null===(t=this._$ES)||void 0===t||t.forEach((t=>{var i;return null===(i=t.hostUpdate)||void 0===i?void 0:i.call(t)})),this.update(s)):this._$Ek();}catch(t){throw i=!1,this._$Ek(),t}i&&this._$AE(s);}willUpdate(t){}_$AE(t){var i;null===(i=this._$ES)||void 0===i||i.forEach((t=>{var i;return null===(i=t.hostUpdated)||void 0===i?void 0:i.call(t)})),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t);}_$Ek(){this._$AL=new Map,this.isUpdatePending=!1;}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$E_}shouldUpdate(t){return !0}update(t){void 0!==this._$EC&&(this._$EC.forEach(((t,i)=>this._$EO(i,this[i],t))),this._$EC=void 0),this._$Ek();}updated(t){}firstUpdated(t){}}u$1[d$1]=!0,u$1.elementProperties=new Map,u$1.elementStyles=[],u$1.shadowRootOptions={mode:"open"},null==o$2||o$2({ReactiveElement:u$1}),(null!==(s$2=e$1.reactiveElementVersions)&&void 0!==s$2?s$2:e$1.reactiveElementVersions=[]).push("1.6.3");
|
|
59
59
|
|
|
60
60
|
/**
|
|
61
61
|
* @license
|
|
62
62
|
* Copyright 2017 Google LLC
|
|
63
63
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
64
64
|
*/
|
|
65
|
-
var t;const i=window,s$1=i.trustedTypes,e=s$1?s$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,o$1="$lit$",n$1=`lit$${(Math.random()+"").slice(9)}$`,l$1="?"+n$1,h=`<${l$1}>`,r=document,
|
|
65
|
+
var t;const i=window,s$1=i.trustedTypes,e=s$1?s$1.createPolicy("lit-html",{createHTML:t=>t}):void 0,o$1="$lit$",n$1=`lit$${(Math.random()+"").slice(9)}$`,l$1="?"+n$1,h=`<${l$1}>`,r=document,u=()=>r.createComment(""),d=t=>null===t||"object"!=typeof t&&"function"!=typeof t,c=Array.isArray,v=t=>c(t)||"function"==typeof(null==t?void 0:t[Symbol.iterator]),a="[ \t\n\f\r]",f=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,_=/-->/g,m=/>/g,p=RegExp(`>|${a}(?:([^\\s"'>=/]+)(${a}*=${a}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),g=/'/g,$=/"/g,y=/^(?:script|style|textarea|title)$/i,T=Symbol.for("lit-noChange"),A=Symbol.for("lit-nothing"),E=new WeakMap,C=r.createTreeWalker(r,129,null,!1);function P(t,i){if(!Array.isArray(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==e?e.createHTML(i):i}const V=(t,i)=>{const s=t.length-1,e=[];let l,r=2===i?"<svg>":"",u=f;for(let i=0;i<s;i++){const s=t[i];let d,c,v=-1,a=0;for(;a<s.length&&(u.lastIndex=a,c=u.exec(s),null!==c);)a=u.lastIndex,u===f?"!--"===c[1]?u=_:void 0!==c[1]?u=m:void 0!==c[2]?(y.test(c[2])&&(l=RegExp("</"+c[2],"g")),u=p):void 0!==c[3]&&(u=p):u===p?">"===c[0]?(u=null!=l?l:f,v=-1):void 0===c[1]?v=-2:(v=u.lastIndex-c[2].length,d=c[1],u=void 0===c[3]?p:'"'===c[3]?$:g):u===$||u===g?u=p:u===_||u===m?u=f:(u=p,l=void 0);const w=u===p&&t[i+1].startsWith("/>")?" ":"";r+=u===f?s+h:v>=0?(e.push(d),s.slice(0,v)+o$1+s.slice(v)+n$1+w):s+n$1+(-2===v?(e.push(void 0),i):w);}return [P(t,r+(t[s]||"<?>")+(2===i?"</svg>":"")),e]};class N{constructor({strings:t,_$litType$:i},e){let h;this.parts=[];let r=0,d=0;const c=t.length-1,v=this.parts,[a,f]=V(t,i);if(this.el=N.createElement(a,e),C.currentNode=this.el.content,2===i){const t=this.el.content,i=t.firstChild;i.remove(),t.append(...i.childNodes);}for(;null!==(h=C.nextNode())&&v.length<c;){if(1===h.nodeType){if(h.hasAttributes()){const t=[];for(const i of h.getAttributeNames())if(i.endsWith(o$1)||i.startsWith(n$1)){const s=f[d++];if(t.push(i),void 0!==s){const t=h.getAttribute(s.toLowerCase()+o$1).split(n$1),i=/([.?@])?(.*)/.exec(s);v.push({type:1,index:r,name:i[2],strings:t,ctor:"."===i[1]?H:"?"===i[1]?L:"@"===i[1]?z:k});}else v.push({type:6,index:r});}for(const i of t)h.removeAttribute(i);}if(y.test(h.tagName)){const t=h.textContent.split(n$1),i=t.length-1;if(i>0){h.textContent=s$1?s$1.emptyScript:"";for(let s=0;s<i;s++)h.append(t[s],u()),C.nextNode(),v.push({type:2,index:++r});h.append(t[i],u());}}}else if(8===h.nodeType)if(h.data===l$1)v.push({type:2,index:r});else {let t=-1;for(;-1!==(t=h.data.indexOf(n$1,t+1));)v.push({type:7,index:r}),t+=n$1.length-1;}r++;}}static createElement(t,i){const s=r.createElement("template");return s.innerHTML=t,s}}function S(t,i,s=t,e){var o,n,l,h;if(i===T)return i;let r=void 0!==e?null===(o=s._$Co)||void 0===o?void 0:o[e]:s._$Cl;const u=d(i)?void 0:i._$litDirective$;return (null==r?void 0:r.constructor)!==u&&(null===(n=null==r?void 0:r._$AO)||void 0===n||n.call(r,!1),void 0===u?r=void 0:(r=new u(t),r._$AT(t,s,e)),void 0!==e?(null!==(l=(h=s)._$Co)&&void 0!==l?l:h._$Co=[])[e]=r:s._$Cl=r),void 0!==r&&(i=S(t,r._$AS(t,i.values),r,e)),i}class M{constructor(t,i){this._$AV=[],this._$AN=void 0,this._$AD=t,this._$AM=i;}get parentNode(){return this._$AM.parentNode}get _$AU(){return this._$AM._$AU}u(t){var i;const{el:{content:s},parts:e}=this._$AD,o=(null!==(i=null==t?void 0:t.creationScope)&&void 0!==i?i:r).importNode(s,!0);C.currentNode=o;let n=C.nextNode(),l=0,h=0,u=e[0];for(;void 0!==u;){if(l===u.index){let i;2===u.type?i=new R(n,n.nextSibling,this,t):1===u.type?i=new u.ctor(n,u.name,u.strings,this,t):6===u.type&&(i=new Z(n,this,t)),this._$AV.push(i),u=e[++h];}l!==(null==u?void 0:u.index)&&(n=C.nextNode(),l++);}return C.currentNode=r,o}v(t){let i=0;for(const s of this._$AV)void 0!==s&&(void 0!==s.strings?(s._$AI(t,s,i),i+=s.strings.length-2):s._$AI(t[i])),i++;}}class R{constructor(t,i,s,e){var o;this.type=2,this._$AH=A,this._$AN=void 0,this._$AA=t,this._$AB=i,this._$AM=s,this.options=e,this._$Cp=null===(o=null==e?void 0:e.isConnected)||void 0===o||o;}get _$AU(){var t,i;return null!==(i=null===(t=this._$AM)||void 0===t?void 0:t._$AU)&&void 0!==i?i:this._$Cp}get parentNode(){let t=this._$AA.parentNode;const i=this._$AM;return void 0!==i&&11===(null==t?void 0:t.nodeType)&&(t=i.parentNode),t}get startNode(){return this._$AA}get endNode(){return this._$AB}_$AI(t,i=this){t=S(this,t,i),d(t)?t===A||null==t||""===t?(this._$AH!==A&&this._$AR(),this._$AH=A):t!==this._$AH&&t!==T&&this._(t):void 0!==t._$litType$?this.g(t):void 0!==t.nodeType?this.$(t):v(t)?this.T(t):this._(t);}k(t){return this._$AA.parentNode.insertBefore(t,this._$AB)}$(t){this._$AH!==t&&(this._$AR(),this._$AH=this.k(t));}_(t){this._$AH!==A&&d(this._$AH)?this._$AA.nextSibling.data=t:this.$(r.createTextNode(t)),this._$AH=t;}g(t){var i;const{values:s,_$litType$:e}=t,o="number"==typeof e?this._$AC(t):(void 0===e.el&&(e.el=N.createElement(P(e.h,e.h[0]),this.options)),e);if((null===(i=this._$AH)||void 0===i?void 0:i._$AD)===o)this._$AH.v(s);else {const t=new M(o,this),i=t.u(this.options);t.v(s),this.$(i),this._$AH=t;}}_$AC(t){let i=E.get(t.strings);return void 0===i&&E.set(t.strings,i=new N(t)),i}T(t){c(this._$AH)||(this._$AH=[],this._$AR());const i=this._$AH;let s,e=0;for(const o of t)e===i.length?i.push(s=new R(this.k(u()),this.k(u()),this,this.options)):s=i[e],s._$AI(o),e++;e<i.length&&(this._$AR(s&&s._$AB.nextSibling,e),i.length=e);}_$AR(t=this._$AA.nextSibling,i){var s;for(null===(s=this._$AP)||void 0===s||s.call(this,!1,!0,i);t&&t!==this._$AB;){const i=t.nextSibling;t.remove(),t=i;}}setConnected(t){var i;void 0===this._$AM&&(this._$Cp=t,null===(i=this._$AP)||void 0===i||i.call(this,t));}}class k{constructor(t,i,s,e,o){this.type=1,this._$AH=A,this._$AN=void 0,this.element=t,this.name=i,this._$AM=e,this.options=o,s.length>2||""!==s[0]||""!==s[1]?(this._$AH=Array(s.length-1).fill(new String),this.strings=s):this._$AH=A;}get tagName(){return this.element.tagName}get _$AU(){return this._$AM._$AU}_$AI(t,i=this,s,e){const o=this.strings;let n=!1;if(void 0===o)t=S(this,t,i,0),n=!d(t)||t!==this._$AH&&t!==T,n&&(this._$AH=t);else {const e=t;let l,h;for(t=o[0],l=0;l<o.length-1;l++)h=S(this,e[s+l],i,l),h===T&&(h=this._$AH[l]),n||(n=!d(h)||h!==this._$AH[l]),h===A?t=A:t!==A&&(t+=(null!=h?h:"")+o[l+1]),this._$AH[l]=h;}n&&!e&&this.j(t);}j(t){t===A?this.element.removeAttribute(this.name):this.element.setAttribute(this.name,null!=t?t:"");}}class H extends k{constructor(){super(...arguments),this.type=3;}j(t){this.element[this.name]=t===A?void 0:t;}}const I=s$1?s$1.emptyScript:"";class L extends k{constructor(){super(...arguments),this.type=4;}j(t){t&&t!==A?this.element.setAttribute(this.name,I):this.element.removeAttribute(this.name);}}class z extends k{constructor(t,i,s,e,o){super(t,i,s,e,o),this.type=5;}_$AI(t,i=this){var s;if((t=null!==(s=S(this,t,i,0))&&void 0!==s?s:A)===T)return;const e=this._$AH,o=t===A&&e!==A||t.capture!==e.capture||t.once!==e.once||t.passive!==e.passive,n=t!==A&&(e===A||o);o&&this.element.removeEventListener(this.name,this,e),n&&this.element.addEventListener(this.name,this,t),this._$AH=t;}handleEvent(t){var i,s;"function"==typeof this._$AH?this._$AH.call(null!==(s=null===(i=this.options)||void 0===i?void 0:i.host)&&void 0!==s?s:this.element,t):this._$AH.handleEvent(t);}}class Z{constructor(t,i,s){this.element=t,this.type=6,this._$AN=void 0,this._$AM=i,this.options=s;}get _$AU(){return this._$AM._$AU}_$AI(t){S(this,t);}}const B=i.litHtmlPolyfillSupport;null==B||B(N,R),(null!==(t=i.litHtmlVersions)&&void 0!==t?t:i.litHtmlVersions=[]).push("2.8.0");const D=(t,i,s)=>{var e,o;const n=null!==(e=null==s?void 0:s.renderBefore)&&void 0!==e?e:i;let l=n._$litPart$;if(void 0===l){const t=null!==(o=null==s?void 0:s.renderBefore)&&void 0!==o?o:null;n._$litPart$=l=new R(i.insertBefore(u(),t),t,void 0,null!=s?s:{});}return l._$AI(t),l};
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* @license
|
|
69
69
|
* Copyright 2017 Google LLC
|
|
70
70
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
71
|
-
*/var l,o;class s extends u$1{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t,e;const i=super.createRenderRoot();return null!==(t=(e=this.renderOptions).renderBefore)&&void 0!==t||(e.renderBefore=i.firstChild),i}update(t){const i=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=
|
|
71
|
+
*/var l,o;class s extends u$1{constructor(){super(...arguments),this.renderOptions={host:this},this._$Do=void 0;}createRenderRoot(){var t,e;const i=super.createRenderRoot();return null!==(t=(e=this.renderOptions).renderBefore)&&void 0!==t||(e.renderBefore=i.firstChild),i}update(t){const i=this.render();this.hasUpdated||(this.renderOptions.isConnected=this.isConnected),super.update(t),this._$Do=D(i,this.renderRoot,this.renderOptions);}connectedCallback(){var t;super.connectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!0);}disconnectedCallback(){var t;super.disconnectedCallback(),null===(t=this._$Do)||void 0===t||t.setConnected(!1);}render(){return T}}s.finalized=!0,s._$litElement$=!0,null===(l=globalThis.litElementHydrateSupport)||void 0===l||l.call(globalThis,{LitElement:s});const n=globalThis.litElementPolyfillSupport;null==n||n({LitElement:s});(null!==(o=globalThis.litElementVersions)&&void 0!==o?o:globalThis.litElementVersions=[]).push("3.3.3");
|
|
72
72
|
|
|
73
73
|
/**
|
|
74
74
|
* @license
|
|
75
75
|
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
76
76
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
77
77
|
*/
|
|
78
|
+
/**
|
|
79
|
+
* @polymerMixin
|
|
80
|
+
*/
|
|
81
|
+
const ThemePropertyMixin = (superClass) =>
|
|
82
|
+
class VaadinThemePropertyMixin extends superClass {
|
|
83
|
+
static get properties() {
|
|
84
|
+
return {
|
|
85
|
+
/**
|
|
86
|
+
* Helper property with theme attribute value facilitating propagation
|
|
87
|
+
* in shadow DOM.
|
|
88
|
+
*
|
|
89
|
+
* Enables the component implementation to propagate the `theme`
|
|
90
|
+
* attribute value to the sub-components in Shadow DOM by binding
|
|
91
|
+
* the sub-component's "theme" attribute to the `theme` property of
|
|
92
|
+
* the host.
|
|
93
|
+
*
|
|
94
|
+
* **NOTE:** Extending the mixin only provides the property for binding,
|
|
95
|
+
* and does not make the propagation alone.
|
|
96
|
+
*
|
|
97
|
+
* See [Styling Components: Sub-components](https://vaadin.com/docs/latest/styling/styling-components/#sub-components).
|
|
98
|
+
* page for more information.
|
|
99
|
+
*
|
|
100
|
+
* @protected
|
|
101
|
+
*/
|
|
102
|
+
_theme: {
|
|
103
|
+
type: String,
|
|
104
|
+
readOnly: true,
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static get observedAttributes() {
|
|
110
|
+
return [...super.observedAttributes, 'theme'];
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** @protected */
|
|
114
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
115
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
116
|
+
|
|
117
|
+
if (name === 'theme') {
|
|
118
|
+
this._set_theme(newValue);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @license
|
|
125
|
+
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
126
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
127
|
+
*/
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @typedef {Object} Theme
|
|
131
|
+
* @property {string} themeFor
|
|
132
|
+
* @property {CSSResult[]} styles
|
|
133
|
+
* @property {string | string[]} [include]
|
|
134
|
+
* @property {string} [moduleId]
|
|
135
|
+
*
|
|
136
|
+
* @typedef {CSSResult[] | CSSResult} CSSResultGroup
|
|
137
|
+
*/
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @type {Theme[]}
|
|
141
|
+
*/
|
|
142
|
+
const themeRegistry = [];
|
|
78
143
|
|
|
79
144
|
/**
|
|
80
145
|
* Check if the custom element type has themes applied.
|
|
@@ -134,9 +199,170 @@ function registerStyles(themeFor, styles, options = {}) {
|
|
|
134
199
|
|
|
135
200
|
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
136
201
|
window.Vaadin.styleModules.registerStyles(themeFor, styles, options);
|
|
202
|
+
} else {
|
|
203
|
+
themeRegistry.push({
|
|
204
|
+
themeFor,
|
|
205
|
+
styles,
|
|
206
|
+
include: options.include,
|
|
207
|
+
moduleId: options.moduleId,
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Returns all registered themes. By default the themeRegistry is returned as is.
|
|
214
|
+
* In case the style-modules adapter is imported, the themes are obtained from there instead
|
|
215
|
+
* @returns {Theme[]}
|
|
216
|
+
*/
|
|
217
|
+
function getAllThemes() {
|
|
218
|
+
if (window.Vaadin && window.Vaadin.styleModules) {
|
|
219
|
+
return window.Vaadin.styleModules.getAllThemes();
|
|
220
|
+
}
|
|
221
|
+
return themeRegistry;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Returns true if the themeFor string matches the tag name
|
|
226
|
+
* @param {string} themeFor
|
|
227
|
+
* @param {string} tagName
|
|
228
|
+
* @returns {boolean}
|
|
229
|
+
*/
|
|
230
|
+
function matchesThemeFor(themeFor, tagName) {
|
|
231
|
+
return (themeFor || '').split(' ').some((themeForToken) => {
|
|
232
|
+
return new RegExp(`^${themeForToken.split('*').join('.*')}$`, 'u').test(tagName);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Maps the moduleName to an include priority number which is used for
|
|
238
|
+
* determining the order in which styles are applied.
|
|
239
|
+
* @param {string} moduleName
|
|
240
|
+
* @returns {number}
|
|
241
|
+
*/
|
|
242
|
+
function getIncludePriority(moduleName = '') {
|
|
243
|
+
let includePriority = 0;
|
|
244
|
+
if (moduleName.startsWith('lumo-') || moduleName.startsWith('material-')) {
|
|
245
|
+
includePriority = 1;
|
|
246
|
+
} else if (moduleName.startsWith('vaadin-')) {
|
|
247
|
+
includePriority = 2;
|
|
248
|
+
}
|
|
249
|
+
return includePriority;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Gets an array of CSSResults matching the include property of the theme.
|
|
254
|
+
* @param {Theme} theme
|
|
255
|
+
* @returns {CSSResult[]}
|
|
256
|
+
*/
|
|
257
|
+
function getIncludedStyles(theme) {
|
|
258
|
+
const includedStyles = [];
|
|
259
|
+
if (theme.include) {
|
|
260
|
+
[].concat(theme.include).forEach((includeModuleId) => {
|
|
261
|
+
const includedTheme = getAllThemes().find((s) => s.moduleId === includeModuleId);
|
|
262
|
+
if (includedTheme) {
|
|
263
|
+
includedStyles.push(...getIncludedStyles(includedTheme), ...includedTheme.styles);
|
|
264
|
+
} else {
|
|
265
|
+
console.warn(`Included moduleId ${includeModuleId} not found in style registry`);
|
|
266
|
+
}
|
|
267
|
+
}, theme.styles);
|
|
137
268
|
}
|
|
269
|
+
return includedStyles;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Includes the styles to the template.
|
|
274
|
+
* @param {CSSResult[]} styles
|
|
275
|
+
* @param {HTMLTemplateElement} template
|
|
276
|
+
*/
|
|
277
|
+
function addStylesToTemplate(styles, template) {
|
|
278
|
+
const styleEl = document.createElement('style');
|
|
279
|
+
styleEl.innerHTML = styles.map((style) => style.cssText).join('\n');
|
|
280
|
+
template.content.appendChild(styleEl);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Returns an array of themes that should be used for styling a component matching
|
|
285
|
+
* the tag name. The array is sorted by the include order.
|
|
286
|
+
* @param {string} tagName
|
|
287
|
+
* @returns {Theme[]}
|
|
288
|
+
*/
|
|
289
|
+
function getThemes(tagName) {
|
|
290
|
+
const defaultModuleName = `${tagName}-default-theme`;
|
|
291
|
+
|
|
292
|
+
const themes = getAllThemes()
|
|
293
|
+
// Filter by matching themeFor properties
|
|
294
|
+
.filter((theme) => theme.moduleId !== defaultModuleName && matchesThemeFor(theme.themeFor, tagName))
|
|
295
|
+
.map((theme) => ({
|
|
296
|
+
...theme,
|
|
297
|
+
// Prepend styles from included themes
|
|
298
|
+
styles: [...getIncludedStyles(theme), ...theme.styles],
|
|
299
|
+
// Map moduleId to includePriority
|
|
300
|
+
includePriority: getIncludePriority(theme.moduleId),
|
|
301
|
+
}))
|
|
302
|
+
// Sort by includePriority
|
|
303
|
+
.sort((themeA, themeB) => themeB.includePriority - themeA.includePriority);
|
|
304
|
+
|
|
305
|
+
if (themes.length > 0) {
|
|
306
|
+
return themes;
|
|
307
|
+
}
|
|
308
|
+
// No theme modules found, return the default module if it exists
|
|
309
|
+
return getAllThemes().filter((theme) => theme.moduleId === defaultModuleName);
|
|
138
310
|
}
|
|
139
311
|
|
|
312
|
+
/**
|
|
313
|
+
* @polymerMixin
|
|
314
|
+
* @mixes ThemePropertyMixin
|
|
315
|
+
*/
|
|
316
|
+
const ThemableMixin = (superClass) =>
|
|
317
|
+
class VaadinThemableMixin extends ThemePropertyMixin(superClass) {
|
|
318
|
+
/**
|
|
319
|
+
* Covers PolymerElement based component styling
|
|
320
|
+
* @protected
|
|
321
|
+
*/
|
|
322
|
+
static finalize() {
|
|
323
|
+
super.finalize();
|
|
324
|
+
|
|
325
|
+
// Make sure not to run the logic intended for PolymerElement when LitElement is used.
|
|
326
|
+
if (this.elementStyles) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const template = this.prototype._template;
|
|
331
|
+
if (!template || classHasThemes(this)) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
addStylesToTemplate(this.getStylesForThis(), template);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Covers LitElement based component styling
|
|
340
|
+
*
|
|
341
|
+
* @protected
|
|
342
|
+
*/
|
|
343
|
+
static finalizeStyles(styles) {
|
|
344
|
+
// The "styles" object originates from the "static get styles()" function of
|
|
345
|
+
// a LitElement based component. The theme styles are added after it
|
|
346
|
+
// so that they can override the component styles.
|
|
347
|
+
const themeStyles = this.getStylesForThis();
|
|
348
|
+
return styles ? [...super.finalizeStyles(styles), ...themeStyles] : themeStyles;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Get styles for the component type
|
|
353
|
+
*
|
|
354
|
+
* @private
|
|
355
|
+
*/
|
|
356
|
+
static getStylesForThis() {
|
|
357
|
+
const parent = Object.getPrototypeOf(this.prototype);
|
|
358
|
+
const inheritedThemes = (parent ? parent.constructor.__themes : []) || [];
|
|
359
|
+
this.__themes = [...inheritedThemes, ...getThemes(this.is)];
|
|
360
|
+
const themeStyles = this.__themes.flatMap((theme) => theme.styles);
|
|
361
|
+
// Remove duplicates
|
|
362
|
+
return themeStyles.filter((style, index) => index === themeStyles.lastIndexOf(style));
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
|
|
140
366
|
/**
|
|
141
367
|
* @license
|
|
142
368
|
* Copyright (c) 2017 - 2023 Vaadin Ltd.
|
|
@@ -1620,19 +1846,19 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|
|
1620
1846
|
*/
|
|
1621
1847
|
|
|
1622
1848
|
// Microtask implemented using Mutation Observer
|
|
1623
|
-
let microtaskCurrHandle = 0;
|
|
1624
|
-
let microtaskLastHandle = 0;
|
|
1625
|
-
let microtaskCallbacks = [];
|
|
1849
|
+
let microtaskCurrHandle$1 = 0;
|
|
1850
|
+
let microtaskLastHandle$1 = 0;
|
|
1851
|
+
let microtaskCallbacks$1 = [];
|
|
1626
1852
|
let microtaskNodeContent = 0;
|
|
1627
|
-
let microtaskScheduled = false;
|
|
1853
|
+
let microtaskScheduled$1 = false;
|
|
1628
1854
|
let microtaskNode = document.createTextNode('');
|
|
1629
|
-
new window.MutationObserver(microtaskFlush).observe(microtaskNode, {characterData: true});
|
|
1855
|
+
new window.MutationObserver(microtaskFlush$1).observe(microtaskNode, {characterData: true});
|
|
1630
1856
|
|
|
1631
|
-
function microtaskFlush() {
|
|
1632
|
-
microtaskScheduled = false;
|
|
1633
|
-
const len = microtaskCallbacks.length;
|
|
1857
|
+
function microtaskFlush$1() {
|
|
1858
|
+
microtaskScheduled$1 = false;
|
|
1859
|
+
const len = microtaskCallbacks$1.length;
|
|
1634
1860
|
for (let i = 0; i < len; i++) {
|
|
1635
|
-
let cb = microtaskCallbacks[i];
|
|
1861
|
+
let cb = microtaskCallbacks$1[i];
|
|
1636
1862
|
if (cb) {
|
|
1637
1863
|
try {
|
|
1638
1864
|
cb();
|
|
@@ -1641,8 +1867,8 @@ function microtaskFlush() {
|
|
|
1641
1867
|
}
|
|
1642
1868
|
}
|
|
1643
1869
|
}
|
|
1644
|
-
microtaskCallbacks.splice(0, len);
|
|
1645
|
-
microtaskLastHandle += len;
|
|
1870
|
+
microtaskCallbacks$1.splice(0, len);
|
|
1871
|
+
microtaskLastHandle$1 += len;
|
|
1646
1872
|
}
|
|
1647
1873
|
|
|
1648
1874
|
/**
|
|
@@ -1651,7 +1877,7 @@ function microtaskFlush() {
|
|
|
1651
1877
|
* @namespace
|
|
1652
1878
|
* @summary Async interface wrapper around `setTimeout`.
|
|
1653
1879
|
*/
|
|
1654
|
-
const timeOut = {
|
|
1880
|
+
const timeOut$1 = {
|
|
1655
1881
|
/**
|
|
1656
1882
|
* Returns a sub-module with the async interface providing the provided
|
|
1657
1883
|
* delay.
|
|
@@ -1704,7 +1930,7 @@ const timeOut = {
|
|
|
1704
1930
|
* @summary Async interface for enqueuing callbacks that run at microtask
|
|
1705
1931
|
* timing.
|
|
1706
1932
|
*/
|
|
1707
|
-
const microTask = {
|
|
1933
|
+
const microTask$1 = {
|
|
1708
1934
|
|
|
1709
1935
|
/**
|
|
1710
1936
|
* Enqueues a function called at microtask timing.
|
|
@@ -1714,12 +1940,12 @@ const microTask = {
|
|
|
1714
1940
|
* @return {number} Handle used for canceling task
|
|
1715
1941
|
*/
|
|
1716
1942
|
run(callback) {
|
|
1717
|
-
if (!microtaskScheduled) {
|
|
1718
|
-
microtaskScheduled = true;
|
|
1943
|
+
if (!microtaskScheduled$1) {
|
|
1944
|
+
microtaskScheduled$1 = true;
|
|
1719
1945
|
microtaskNode.textContent = microtaskNodeContent++;
|
|
1720
1946
|
}
|
|
1721
|
-
microtaskCallbacks.push(callback);
|
|
1722
|
-
return microtaskCurrHandle++;
|
|
1947
|
+
microtaskCallbacks$1.push(callback);
|
|
1948
|
+
return microtaskCurrHandle$1++;
|
|
1723
1949
|
},
|
|
1724
1950
|
|
|
1725
1951
|
/**
|
|
@@ -1730,12 +1956,12 @@ const microTask = {
|
|
|
1730
1956
|
* @return {void}
|
|
1731
1957
|
*/
|
|
1732
1958
|
cancel(handle) {
|
|
1733
|
-
const idx = handle - microtaskLastHandle;
|
|
1959
|
+
const idx = handle - microtaskLastHandle$1;
|
|
1734
1960
|
if (idx >= 0) {
|
|
1735
|
-
if (!microtaskCallbacks[idx]) {
|
|
1961
|
+
if (!microtaskCallbacks$1[idx]) {
|
|
1736
1962
|
throw new Error('invalid async handle: ' + handle);
|
|
1737
1963
|
}
|
|
1738
|
-
microtaskCallbacks[idx] = null;
|
|
1964
|
+
microtaskCallbacks$1[idx] = null;
|
|
1739
1965
|
}
|
|
1740
1966
|
}
|
|
1741
1967
|
|
|
@@ -1752,7 +1978,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|
|
1752
1978
|
*/
|
|
1753
1979
|
|
|
1754
1980
|
/** @const {!AsyncInterface} */
|
|
1755
|
-
const microtask = microTask;
|
|
1981
|
+
const microtask = microTask$1;
|
|
1756
1982
|
|
|
1757
1983
|
/**
|
|
1758
1984
|
* Element class mixin that provides basic meta-programming for creating one
|
|
@@ -6750,7 +6976,7 @@ const builtCSS = window.ShadyCSS && window.ShadyCSS['cssBuild'];
|
|
|
6750
6976
|
* @param {function(new:T)} superClass Class to apply mixin to.
|
|
6751
6977
|
* @return {function(new:T)} superClass with mixin applied.
|
|
6752
6978
|
*/
|
|
6753
|
-
const ElementMixin = dedupingMixin(base => {
|
|
6979
|
+
const ElementMixin$1 = dedupingMixin(base => {
|
|
6754
6980
|
/**
|
|
6755
6981
|
* @constructor
|
|
6756
6982
|
* @implements {Polymer_PropertyEffects}
|
|
@@ -7688,7 +7914,7 @@ subject to an additional IP rights grant found at http://polymer.github.io/PATEN
|
|
|
7688
7914
|
* key meta-programming features including template stamping, data-binding,
|
|
7689
7915
|
* attribute deserialization, and property change observation
|
|
7690
7916
|
*/
|
|
7691
|
-
const PolymerElement = ElementMixin(HTMLElement);
|
|
7917
|
+
const PolymerElement = ElementMixin$1(HTMLElement);
|
|
7692
7918
|
|
|
7693
7919
|
const DEV_MODE_CODE_REGEXP =
|
|
7694
7920
|
/\/\*[\*!]\s+vaadin-dev-mode:start([\s\S]*)vaadin-dev-mode:end\s+\*\*\//i;
|
|
@@ -8283,572 +8509,808 @@ const usageStatistics = function() {
|
|
|
8283
8509
|
|
|
8284
8510
|
/**
|
|
8285
8511
|
* @license
|
|
8286
|
-
* Copyright (c)
|
|
8287
|
-
* This
|
|
8512
|
+
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
8513
|
+
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
8514
|
+
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
8515
|
+
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
8516
|
+
* Code distributed by Google as part of the polymer project is also
|
|
8517
|
+
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
8288
8518
|
*/
|
|
8289
8519
|
|
|
8290
8520
|
/**
|
|
8291
|
-
*
|
|
8521
|
+
* @fileoverview
|
|
8292
8522
|
*
|
|
8293
|
-
*
|
|
8523
|
+
* This module provides a number of strategies for enqueuing asynchronous
|
|
8524
|
+
* tasks. Each sub-module provides a standard `run(fn)` interface that returns a
|
|
8525
|
+
* handle, and a `cancel(handle)` interface for canceling async tasks before
|
|
8526
|
+
* they run.
|
|
8527
|
+
*
|
|
8528
|
+
* @summary Module that provides a number of strategies for enqueuing
|
|
8529
|
+
* asynchronous tasks.
|
|
8294
8530
|
*/
|
|
8295
|
-
const DisabledMixin = dedupingMixin(
|
|
8296
|
-
(superclass) =>
|
|
8297
|
-
class DisabledMixinClass extends superclass {
|
|
8298
|
-
static get properties() {
|
|
8299
|
-
return {
|
|
8300
|
-
/**
|
|
8301
|
-
* If true, the user cannot interact with this element.
|
|
8302
|
-
*/
|
|
8303
|
-
disabled: {
|
|
8304
|
-
type: Boolean,
|
|
8305
|
-
value: false,
|
|
8306
|
-
observer: '_disabledChanged',
|
|
8307
|
-
reflectToAttribute: true,
|
|
8308
|
-
},
|
|
8309
|
-
};
|
|
8310
|
-
}
|
|
8311
8531
|
|
|
8312
|
-
|
|
8313
|
-
|
|
8314
|
-
|
|
8315
|
-
|
|
8316
|
-
_disabledChanged(disabled) {
|
|
8317
|
-
this._setAriaDisabled(disabled);
|
|
8318
|
-
}
|
|
8532
|
+
let microtaskCurrHandle = 0;
|
|
8533
|
+
let microtaskLastHandle = 0;
|
|
8534
|
+
const microtaskCallbacks = [];
|
|
8535
|
+
let microtaskScheduled = false;
|
|
8319
8536
|
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
|
|
8324
|
-
|
|
8325
|
-
|
|
8326
|
-
|
|
8327
|
-
|
|
8328
|
-
|
|
8329
|
-
|
|
8537
|
+
function microtaskFlush() {
|
|
8538
|
+
microtaskScheduled = false;
|
|
8539
|
+
const len = microtaskCallbacks.length;
|
|
8540
|
+
for (let i = 0; i < len; i++) {
|
|
8541
|
+
const cb = microtaskCallbacks[i];
|
|
8542
|
+
if (cb) {
|
|
8543
|
+
try {
|
|
8544
|
+
cb();
|
|
8545
|
+
} catch (e) {
|
|
8546
|
+
setTimeout(() => {
|
|
8547
|
+
throw e;
|
|
8548
|
+
});
|
|
8330
8549
|
}
|
|
8550
|
+
}
|
|
8551
|
+
}
|
|
8552
|
+
microtaskCallbacks.splice(0, len);
|
|
8553
|
+
microtaskLastHandle += len;
|
|
8554
|
+
}
|
|
8331
8555
|
|
|
8332
|
-
|
|
8333
|
-
|
|
8334
|
-
|
|
8335
|
-
|
|
8336
|
-
|
|
8337
|
-
|
|
8338
|
-
|
|
8339
|
-
|
|
8340
|
-
|
|
8341
|
-
|
|
8342
|
-
|
|
8343
|
-
|
|
8344
|
-
|
|
8556
|
+
/**
|
|
8557
|
+
* Async interface wrapper around `setTimeout`.
|
|
8558
|
+
*
|
|
8559
|
+
* @namespace
|
|
8560
|
+
* @summary Async interface wrapper around `setTimeout`.
|
|
8561
|
+
*/
|
|
8562
|
+
const timeOut = {
|
|
8563
|
+
/**
|
|
8564
|
+
* Returns a sub-module with the async interface providing the provided
|
|
8565
|
+
* delay.
|
|
8566
|
+
*
|
|
8567
|
+
* @memberof timeOut
|
|
8568
|
+
* @param {number=} delay Time to wait before calling callbacks in ms
|
|
8569
|
+
* @return {!AsyncInterface} An async timeout interface
|
|
8570
|
+
*/
|
|
8571
|
+
after(delay) {
|
|
8572
|
+
return {
|
|
8573
|
+
run(fn) {
|
|
8574
|
+
return window.setTimeout(fn, delay);
|
|
8575
|
+
},
|
|
8576
|
+
cancel(handle) {
|
|
8577
|
+
window.clearTimeout(handle);
|
|
8578
|
+
},
|
|
8579
|
+
};
|
|
8580
|
+
},
|
|
8581
|
+
/**
|
|
8582
|
+
* Enqueues a function called in the next task.
|
|
8583
|
+
*
|
|
8584
|
+
* @memberof timeOut
|
|
8585
|
+
* @param {!Function} fn Callback to run
|
|
8586
|
+
* @param {number=} delay Delay in milliseconds
|
|
8587
|
+
* @return {number} Handle used for canceling task
|
|
8588
|
+
*/
|
|
8589
|
+
run(fn, delay) {
|
|
8590
|
+
return window.setTimeout(fn, delay);
|
|
8591
|
+
},
|
|
8592
|
+
/**
|
|
8593
|
+
* Cancels a previously enqueued `timeOut` callback.
|
|
8594
|
+
*
|
|
8595
|
+
* @memberof timeOut
|
|
8596
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
8597
|
+
* @return {void}
|
|
8598
|
+
*/
|
|
8599
|
+
cancel(handle) {
|
|
8600
|
+
window.clearTimeout(handle);
|
|
8601
|
+
},
|
|
8602
|
+
};
|
|
8345
8603
|
|
|
8346
8604
|
/**
|
|
8347
|
-
*
|
|
8348
|
-
*
|
|
8349
|
-
*
|
|
8605
|
+
* Async interface wrapper around `requestAnimationFrame`.
|
|
8606
|
+
*
|
|
8607
|
+
* @namespace
|
|
8608
|
+
* @summary Async interface wrapper around `requestAnimationFrame`.
|
|
8350
8609
|
*/
|
|
8610
|
+
const animationFrame = {
|
|
8611
|
+
/**
|
|
8612
|
+
* Enqueues a function called at `requestAnimationFrame` timing.
|
|
8613
|
+
*
|
|
8614
|
+
* @memberof animationFrame
|
|
8615
|
+
* @param {function(number):void} fn Callback to run
|
|
8616
|
+
* @return {number} Handle used for canceling task
|
|
8617
|
+
*/
|
|
8618
|
+
run(fn) {
|
|
8619
|
+
return window.requestAnimationFrame(fn);
|
|
8620
|
+
},
|
|
8621
|
+
/**
|
|
8622
|
+
* Cancels a previously enqueued `animationFrame` callback.
|
|
8623
|
+
*
|
|
8624
|
+
* @memberof animationFrame
|
|
8625
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
8626
|
+
* @return {void}
|
|
8627
|
+
*/
|
|
8628
|
+
cancel(handle) {
|
|
8629
|
+
window.cancelAnimationFrame(handle);
|
|
8630
|
+
},
|
|
8631
|
+
};
|
|
8351
8632
|
|
|
8352
8633
|
/**
|
|
8353
|
-
*
|
|
8354
|
-
*
|
|
8355
|
-
* for the event handlers is left to the client (a component or another mixin).
|
|
8634
|
+
* Async interface wrapper around `requestIdleCallback`. Falls back to
|
|
8635
|
+
* `setTimeout` on browsers that do not support `requestIdleCallback`.
|
|
8356
8636
|
*
|
|
8357
|
-
* @
|
|
8637
|
+
* @namespace
|
|
8638
|
+
* @summary Async interface wrapper around `requestIdleCallback`.
|
|
8358
8639
|
*/
|
|
8359
|
-
const
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
|
|
8364
|
-
|
|
8365
|
-
|
|
8366
|
-
|
|
8367
|
-
|
|
8368
|
-
|
|
8369
|
-
|
|
8370
|
-
|
|
8371
|
-
|
|
8372
|
-
|
|
8373
|
-
|
|
8640
|
+
const idlePeriod = {
|
|
8641
|
+
/**
|
|
8642
|
+
* Enqueues a function called at `requestIdleCallback` timing.
|
|
8643
|
+
*
|
|
8644
|
+
* @memberof idlePeriod
|
|
8645
|
+
* @param {function(!IdleDeadline):void} fn Callback to run
|
|
8646
|
+
* @return {number} Handle used for canceling task
|
|
8647
|
+
*/
|
|
8648
|
+
run(fn) {
|
|
8649
|
+
return window.requestIdleCallback ? window.requestIdleCallback(fn) : window.setTimeout(fn, 16);
|
|
8650
|
+
},
|
|
8651
|
+
/**
|
|
8652
|
+
* Cancels a previously enqueued `idlePeriod` callback.
|
|
8653
|
+
*
|
|
8654
|
+
* @memberof idlePeriod
|
|
8655
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
8656
|
+
* @return {void}
|
|
8657
|
+
*/
|
|
8658
|
+
cancel(handle) {
|
|
8659
|
+
if (window.cancelIdleCallback) {
|
|
8660
|
+
window.cancelIdleCallback(handle);
|
|
8661
|
+
} else {
|
|
8662
|
+
window.clearTimeout(handle);
|
|
8663
|
+
}
|
|
8664
|
+
},
|
|
8665
|
+
};
|
|
8374
8666
|
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8380
|
-
|
|
8381
|
-
|
|
8382
|
-
|
|
8383
|
-
|
|
8384
|
-
|
|
8385
|
-
|
|
8386
|
-
|
|
8387
|
-
|
|
8388
|
-
|
|
8389
|
-
|
|
8390
|
-
|
|
8391
|
-
|
|
8392
|
-
|
|
8667
|
+
/**
|
|
8668
|
+
* Async interface for enqueuing callbacks that run at microtask timing.
|
|
8669
|
+
*
|
|
8670
|
+
* @namespace
|
|
8671
|
+
* @summary Async interface for enqueuing callbacks that run at microtask
|
|
8672
|
+
* timing.
|
|
8673
|
+
*/
|
|
8674
|
+
const microTask = {
|
|
8675
|
+
/**
|
|
8676
|
+
* Enqueues a function called at microtask timing.
|
|
8677
|
+
*
|
|
8678
|
+
* @memberof microTask
|
|
8679
|
+
* @param {!Function=} callback Callback to run
|
|
8680
|
+
* @return {number} Handle used for canceling task
|
|
8681
|
+
*/
|
|
8682
|
+
run(callback) {
|
|
8683
|
+
if (!microtaskScheduled) {
|
|
8684
|
+
microtaskScheduled = true;
|
|
8685
|
+
queueMicrotask(() => microtaskFlush());
|
|
8686
|
+
}
|
|
8687
|
+
microtaskCallbacks.push(callback);
|
|
8688
|
+
const result = microtaskCurrHandle;
|
|
8689
|
+
microtaskCurrHandle += 1;
|
|
8690
|
+
return result;
|
|
8691
|
+
},
|
|
8393
8692
|
|
|
8394
|
-
|
|
8395
|
-
|
|
8396
|
-
|
|
8397
|
-
|
|
8398
|
-
|
|
8399
|
-
|
|
8400
|
-
|
|
8401
|
-
|
|
8402
|
-
|
|
8693
|
+
/**
|
|
8694
|
+
* Cancels a previously enqueued `microTask` callback.
|
|
8695
|
+
*
|
|
8696
|
+
* @memberof microTask
|
|
8697
|
+
* @param {number} handle Handle returned from `run` of callback to cancel
|
|
8698
|
+
* @return {void}
|
|
8699
|
+
*/
|
|
8700
|
+
cancel(handle) {
|
|
8701
|
+
const idx = handle - microtaskLastHandle;
|
|
8702
|
+
if (idx >= 0) {
|
|
8703
|
+
if (!microtaskCallbacks[idx]) {
|
|
8704
|
+
throw new Error(`invalid async handle: ${handle}`);
|
|
8403
8705
|
}
|
|
8706
|
+
microtaskCallbacks[idx] = null;
|
|
8707
|
+
}
|
|
8708
|
+
},
|
|
8709
|
+
};
|
|
8404
8710
|
|
|
8405
|
-
|
|
8406
|
-
|
|
8407
|
-
|
|
8408
|
-
|
|
8409
|
-
|
|
8410
|
-
|
|
8411
|
-
|
|
8412
|
-
|
|
8413
|
-
|
|
8414
|
-
}
|
|
8711
|
+
/**
|
|
8712
|
+
@license
|
|
8713
|
+
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
|
8714
|
+
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
8715
|
+
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
8716
|
+
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
8717
|
+
Code distributed by Google as part of the polymer project is also
|
|
8718
|
+
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
8719
|
+
*/
|
|
8415
8720
|
|
|
8416
|
-
|
|
8417
|
-
* A handler for the "Escape" key. By default, it does nothing.
|
|
8418
|
-
* Override the method to implement your own behavior.
|
|
8419
|
-
*
|
|
8420
|
-
* @param {KeyboardEvent} _event
|
|
8421
|
-
* @protected
|
|
8422
|
-
*/
|
|
8423
|
-
_onEscape(_event) {
|
|
8424
|
-
// To be implemented.
|
|
8425
|
-
}
|
|
8426
|
-
},
|
|
8427
|
-
);
|
|
8721
|
+
const debouncerQueue = new Set();
|
|
8428
8722
|
|
|
8429
8723
|
/**
|
|
8430
|
-
* @
|
|
8431
|
-
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
8432
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8724
|
+
* @summary Collapse multiple callbacks into one invocation after a timer.
|
|
8433
8725
|
*/
|
|
8726
|
+
class Debouncer {
|
|
8727
|
+
/**
|
|
8728
|
+
* Creates a debouncer if no debouncer is passed as a parameter
|
|
8729
|
+
* or it cancels an active debouncer otherwise. The following
|
|
8730
|
+
* example shows how a debouncer can be called multiple times within a
|
|
8731
|
+
* microtask and "debounced" such that the provided callback function is
|
|
8732
|
+
* called once. Add this method to a custom element:
|
|
8733
|
+
*
|
|
8734
|
+
* ```js
|
|
8735
|
+
* import {microTask} from '@vaadin/component-base/src/async.js';
|
|
8736
|
+
* import {Debouncer} from '@vaadin/component-base/src/debounce.js';
|
|
8737
|
+
* // ...
|
|
8738
|
+
*
|
|
8739
|
+
* _debounceWork() {
|
|
8740
|
+
* this._debounceJob = Debouncer.debounce(this._debounceJob,
|
|
8741
|
+
* microTask, () => this._doWork());
|
|
8742
|
+
* }
|
|
8743
|
+
* ```
|
|
8744
|
+
*
|
|
8745
|
+
* If the `_debounceWork` method is called multiple times within the same
|
|
8746
|
+
* microtask, the `_doWork` function will be called only once at the next
|
|
8747
|
+
* microtask checkpoint.
|
|
8748
|
+
*
|
|
8749
|
+
* Note: In testing it is often convenient to avoid asynchrony. To accomplish
|
|
8750
|
+
* this with a debouncer, you can use `enqueueDebouncer` and
|
|
8751
|
+
* `flush`. For example, extend the above example by adding
|
|
8752
|
+
* `enqueueDebouncer(this._debounceJob)` at the end of the
|
|
8753
|
+
* `_debounceWork` method. Then in a test, call `flush` to ensure
|
|
8754
|
+
* the debouncer has completed.
|
|
8755
|
+
*
|
|
8756
|
+
* @param {Debouncer?} debouncer Debouncer object.
|
|
8757
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface
|
|
8758
|
+
* @param {function()} callback Callback to run.
|
|
8759
|
+
* @return {!Debouncer} Returns a debouncer object.
|
|
8760
|
+
*/
|
|
8761
|
+
static debounce(debouncer, asyncModule, callback) {
|
|
8762
|
+
if (debouncer instanceof Debouncer) {
|
|
8763
|
+
// Cancel the async callback, but leave in debouncerQueue if it was
|
|
8764
|
+
// enqueued, to maintain 1.x flush order
|
|
8765
|
+
debouncer._cancelAsync();
|
|
8766
|
+
} else {
|
|
8767
|
+
debouncer = new Debouncer();
|
|
8768
|
+
}
|
|
8769
|
+
debouncer.setConfig(asyncModule, callback);
|
|
8770
|
+
return debouncer;
|
|
8771
|
+
}
|
|
8434
8772
|
|
|
8435
|
-
|
|
8436
|
-
|
|
8437
|
-
|
|
8773
|
+
constructor() {
|
|
8774
|
+
this._asyncModule = null;
|
|
8775
|
+
this._callback = null;
|
|
8776
|
+
this._timer = null;
|
|
8777
|
+
}
|
|
8438
8778
|
|
|
8439
|
-
|
|
8440
|
-
|
|
8441
|
-
|
|
8442
|
-
|
|
8443
|
-
|
|
8444
|
-
|
|
8445
|
-
|
|
8446
|
-
|
|
8447
|
-
|
|
8779
|
+
/**
|
|
8780
|
+
* Sets the scheduler; that is, a module with the Async interface,
|
|
8781
|
+
* a callback and optional arguments to be passed to the run function
|
|
8782
|
+
* from the async module.
|
|
8783
|
+
*
|
|
8784
|
+
* @param {!AsyncInterface} asyncModule Object with Async interface.
|
|
8785
|
+
* @param {function()} callback Callback to run.
|
|
8786
|
+
* @return {void}
|
|
8787
|
+
*/
|
|
8788
|
+
setConfig(asyncModule, callback) {
|
|
8789
|
+
this._asyncModule = asyncModule;
|
|
8790
|
+
this._callback = callback;
|
|
8791
|
+
this._timer = this._asyncModule.run(() => {
|
|
8792
|
+
this._timer = null;
|
|
8793
|
+
debouncerQueue.delete(this);
|
|
8794
|
+
this._callback();
|
|
8795
|
+
});
|
|
8796
|
+
}
|
|
8448
8797
|
|
|
8449
|
-
|
|
8450
|
-
|
|
8451
|
-
|
|
8452
|
-
|
|
8453
|
-
|
|
8454
|
-
{
|
|
8455
|
-
)
|
|
8798
|
+
/**
|
|
8799
|
+
* Cancels an active debouncer and returns a reference to itself.
|
|
8800
|
+
*
|
|
8801
|
+
* @return {void}
|
|
8802
|
+
*/
|
|
8803
|
+
cancel() {
|
|
8804
|
+
if (this.isActive()) {
|
|
8805
|
+
this._cancelAsync();
|
|
8806
|
+
// Canceling a debouncer removes its spot from the flush queue,
|
|
8807
|
+
// so if a debouncer is manually canceled and re-debounced, it
|
|
8808
|
+
// will reset its flush order (this is a very minor difference from 1.x)
|
|
8809
|
+
// Re-debouncing via the `debounce` API retains the 1.x FIFO flush order
|
|
8810
|
+
debouncerQueue.delete(this);
|
|
8811
|
+
}
|
|
8812
|
+
}
|
|
8813
|
+
|
|
8814
|
+
/**
|
|
8815
|
+
* Cancels a debouncer's async callback.
|
|
8816
|
+
*
|
|
8817
|
+
* @return {void}
|
|
8818
|
+
*/
|
|
8819
|
+
_cancelAsync() {
|
|
8820
|
+
if (this.isActive()) {
|
|
8821
|
+
this._asyncModule.cancel(/** @type {number} */ (this._timer));
|
|
8822
|
+
this._timer = null;
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
|
|
8826
|
+
/**
|
|
8827
|
+
* Flushes an active debouncer and returns a reference to itself.
|
|
8828
|
+
*
|
|
8829
|
+
* @return {void}
|
|
8830
|
+
*/
|
|
8831
|
+
flush() {
|
|
8832
|
+
if (this.isActive()) {
|
|
8833
|
+
this.cancel();
|
|
8834
|
+
this._callback();
|
|
8835
|
+
}
|
|
8836
|
+
}
|
|
8837
|
+
|
|
8838
|
+
/**
|
|
8839
|
+
* Returns true if the debouncer is active.
|
|
8840
|
+
*
|
|
8841
|
+
* @return {boolean} True if active.
|
|
8842
|
+
*/
|
|
8843
|
+
isActive() {
|
|
8844
|
+
return this._timer != null;
|
|
8845
|
+
}
|
|
8846
|
+
}
|
|
8456
8847
|
|
|
8457
8848
|
/**
|
|
8458
|
-
*
|
|
8459
|
-
* trees recursively to ensure it's the leaf element.
|
|
8849
|
+
* Adds a `Debouncer` to a list of globally flushable tasks.
|
|
8460
8850
|
*
|
|
8461
|
-
* @
|
|
8851
|
+
* @param {!Debouncer} debouncer Debouncer to enqueue
|
|
8852
|
+
* @return {void}
|
|
8462
8853
|
*/
|
|
8463
|
-
function
|
|
8464
|
-
|
|
8465
|
-
while (host.shadowRoot && host.shadowRoot.activeElement) {
|
|
8466
|
-
host = host.shadowRoot.activeElement;
|
|
8467
|
-
}
|
|
8468
|
-
return host;
|
|
8854
|
+
function enqueueDebouncer(debouncer) {
|
|
8855
|
+
debouncerQueue.add(debouncer);
|
|
8469
8856
|
}
|
|
8470
8857
|
|
|
8471
8858
|
/**
|
|
8472
|
-
*
|
|
8473
|
-
* event since the last mousedown event.
|
|
8859
|
+
* Flushes any enqueued debouncers
|
|
8474
8860
|
*
|
|
8475
|
-
* @return {boolean}
|
|
8861
|
+
* @return {boolean} Returns whether any debouncers were flushed
|
|
8476
8862
|
*/
|
|
8477
|
-
function
|
|
8478
|
-
|
|
8863
|
+
function flushDebouncers() {
|
|
8864
|
+
const didFlush = Boolean(debouncerQueue.size);
|
|
8865
|
+
// If new debouncers are added while flushing, Set.forEach will ensure
|
|
8866
|
+
// newly added ones are also flushed
|
|
8867
|
+
debouncerQueue.forEach((debouncer) => {
|
|
8868
|
+
try {
|
|
8869
|
+
debouncer.flush();
|
|
8870
|
+
} catch (e) {
|
|
8871
|
+
setTimeout(() => {
|
|
8872
|
+
throw e;
|
|
8873
|
+
});
|
|
8874
|
+
}
|
|
8875
|
+
});
|
|
8876
|
+
return didFlush;
|
|
8479
8877
|
}
|
|
8480
8878
|
|
|
8879
|
+
const flush = () => {
|
|
8880
|
+
let debouncers;
|
|
8881
|
+
do {
|
|
8882
|
+
debouncers = flushDebouncers();
|
|
8883
|
+
} while (debouncers);
|
|
8884
|
+
};
|
|
8885
|
+
|
|
8481
8886
|
/**
|
|
8482
|
-
*
|
|
8483
|
-
*
|
|
8484
|
-
*
|
|
8485
|
-
* The method doesn't traverse the element's ancestors, it only checks for the CSS properties
|
|
8486
|
-
* set directly to or inherited by the element.
|
|
8487
|
-
*
|
|
8488
|
-
* @param {HTMLElement} element
|
|
8489
|
-
* @return {boolean}
|
|
8887
|
+
* @license
|
|
8888
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
8889
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8490
8890
|
*/
|
|
8491
|
-
function isElementHiddenDirectly(element) {
|
|
8492
|
-
// Check inline style first to save a re-flow.
|
|
8493
|
-
const style = element.style;
|
|
8494
|
-
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
8495
|
-
return true;
|
|
8496
|
-
}
|
|
8497
8891
|
|
|
8498
|
-
|
|
8499
|
-
|
|
8500
|
-
|
|
8892
|
+
/**
|
|
8893
|
+
* Array of Vaadin custom element classes that have been subscribed to the dir changes.
|
|
8894
|
+
*/
|
|
8895
|
+
const directionSubscribers = [];
|
|
8896
|
+
|
|
8897
|
+
function alignDirs(element, documentDir, elementDir = element.getAttribute('dir')) {
|
|
8898
|
+
if (documentDir) {
|
|
8899
|
+
element.setAttribute('dir', documentDir);
|
|
8900
|
+
} else if (elementDir != null) {
|
|
8901
|
+
element.removeAttribute('dir');
|
|
8501
8902
|
}
|
|
8903
|
+
}
|
|
8502
8904
|
|
|
8503
|
-
|
|
8905
|
+
function getDocumentDir() {
|
|
8906
|
+
return document.documentElement.getAttribute('dir');
|
|
8504
8907
|
}
|
|
8505
8908
|
|
|
8506
|
-
|
|
8507
|
-
|
|
8508
|
-
|
|
8509
|
-
|
|
8510
|
-
|
|
8511
|
-
* If both have same tabindex, it returns false.
|
|
8512
|
-
*
|
|
8513
|
-
* @param {HTMLElement} a
|
|
8514
|
-
* @param {HTMLElement} b
|
|
8515
|
-
* @return {boolean}
|
|
8516
|
-
*/
|
|
8517
|
-
function hasLowerTabOrder(a, b) {
|
|
8518
|
-
// Normalize tabIndexes
|
|
8519
|
-
// e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
|
|
8520
|
-
const ati = Math.max(a.tabIndex, 0);
|
|
8521
|
-
const bti = Math.max(b.tabIndex, 0);
|
|
8522
|
-
return ati === 0 || bti === 0 ? bti > ati : ati > bti;
|
|
8909
|
+
function directionUpdater() {
|
|
8910
|
+
const documentDir = getDocumentDir();
|
|
8911
|
+
directionSubscribers.forEach((element) => {
|
|
8912
|
+
alignDirs(element, documentDir);
|
|
8913
|
+
});
|
|
8523
8914
|
}
|
|
8524
8915
|
|
|
8916
|
+
const directionObserver = new MutationObserver(directionUpdater);
|
|
8917
|
+
directionObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['dir'] });
|
|
8918
|
+
|
|
8525
8919
|
/**
|
|
8526
|
-
*
|
|
8920
|
+
* A mixin to handle `dir` attribute based on the one set on the `<html>` element.
|
|
8527
8921
|
*
|
|
8528
|
-
* @
|
|
8529
|
-
* @param {HTMLElement[]} right
|
|
8530
|
-
* @return {HTMLElement[]}
|
|
8922
|
+
* @polymerMixin
|
|
8531
8923
|
*/
|
|
8532
|
-
|
|
8533
|
-
|
|
8534
|
-
|
|
8535
|
-
|
|
8536
|
-
|
|
8537
|
-
|
|
8538
|
-
|
|
8924
|
+
const DirMixin = (superClass) =>
|
|
8925
|
+
class VaadinDirMixin extends superClass {
|
|
8926
|
+
static get properties() {
|
|
8927
|
+
return {
|
|
8928
|
+
/**
|
|
8929
|
+
* @protected
|
|
8930
|
+
*/
|
|
8931
|
+
dir: {
|
|
8932
|
+
type: String,
|
|
8933
|
+
value: '',
|
|
8934
|
+
reflectToAttribute: true,
|
|
8935
|
+
converter: {
|
|
8936
|
+
fromAttribute: (attr) => {
|
|
8937
|
+
return !attr ? '' : attr;
|
|
8938
|
+
},
|
|
8939
|
+
toAttribute: (prop) => {
|
|
8940
|
+
return prop === '' ? null : prop;
|
|
8941
|
+
},
|
|
8942
|
+
},
|
|
8943
|
+
},
|
|
8944
|
+
};
|
|
8539
8945
|
}
|
|
8540
|
-
}
|
|
8541
8946
|
|
|
8542
|
-
|
|
8947
|
+
/**
|
|
8948
|
+
* @return {boolean}
|
|
8949
|
+
* @protected
|
|
8950
|
+
*/
|
|
8951
|
+
get __isRTL() {
|
|
8952
|
+
return this.getAttribute('dir') === 'rtl';
|
|
8953
|
+
}
|
|
8954
|
+
|
|
8955
|
+
/** @protected */
|
|
8956
|
+
connectedCallback() {
|
|
8957
|
+
super.connectedCallback();
|
|
8958
|
+
|
|
8959
|
+
if (!this.hasAttribute('dir') || this.__restoreSubscription) {
|
|
8960
|
+
this.__subscribe();
|
|
8961
|
+
alignDirs(this, getDocumentDir(), null);
|
|
8962
|
+
}
|
|
8963
|
+
}
|
|
8964
|
+
|
|
8965
|
+
/** @protected */
|
|
8966
|
+
attributeChangedCallback(name, oldValue, newValue) {
|
|
8967
|
+
super.attributeChangedCallback(name, oldValue, newValue);
|
|
8968
|
+
if (name !== 'dir') {
|
|
8969
|
+
return;
|
|
8970
|
+
}
|
|
8971
|
+
|
|
8972
|
+
const documentDir = getDocumentDir();
|
|
8973
|
+
|
|
8974
|
+
// New value equals to the document direction and the element is not subscribed to the changes
|
|
8975
|
+
const newValueEqlDocDir = newValue === documentDir && directionSubscribers.indexOf(this) === -1;
|
|
8976
|
+
// Value was emptied and the element is not subscribed to the changes
|
|
8977
|
+
const newValueEmptied = !newValue && oldValue && directionSubscribers.indexOf(this) === -1;
|
|
8978
|
+
// New value is different and the old equals to document direction and the element is not subscribed to the changes
|
|
8979
|
+
const newDiffValue = newValue !== documentDir && oldValue === documentDir;
|
|
8980
|
+
|
|
8981
|
+
if (newValueEqlDocDir || newValueEmptied) {
|
|
8982
|
+
this.__subscribe();
|
|
8983
|
+
alignDirs(this, documentDir, newValue);
|
|
8984
|
+
} else if (newDiffValue) {
|
|
8985
|
+
this.__unsubscribe();
|
|
8986
|
+
}
|
|
8987
|
+
}
|
|
8988
|
+
|
|
8989
|
+
/** @protected */
|
|
8990
|
+
disconnectedCallback() {
|
|
8991
|
+
super.disconnectedCallback();
|
|
8992
|
+
this.__restoreSubscription = directionSubscribers.includes(this);
|
|
8993
|
+
this.__unsubscribe();
|
|
8994
|
+
}
|
|
8995
|
+
|
|
8996
|
+
/** @protected */
|
|
8997
|
+
_valueToNodeAttribute(node, value, attribute) {
|
|
8998
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
8999
|
+
// If the property contains an empty string then it should not create an empty attribute
|
|
9000
|
+
if (attribute === 'dir' && value === '' && !node.hasAttribute('dir')) {
|
|
9001
|
+
return;
|
|
9002
|
+
}
|
|
9003
|
+
super._valueToNodeAttribute(node, value, attribute);
|
|
9004
|
+
}
|
|
9005
|
+
|
|
9006
|
+
/** @protected */
|
|
9007
|
+
_attributeToProperty(attribute, value, type) {
|
|
9008
|
+
// Override default Polymer attribute reflection to match native behavior of HTMLElement.dir property
|
|
9009
|
+
// If the attribute is removed, then the dir property should contain an empty string instead of null
|
|
9010
|
+
if (attribute === 'dir' && !value) {
|
|
9011
|
+
this.dir = '';
|
|
9012
|
+
} else {
|
|
9013
|
+
super._attributeToProperty(attribute, value, type);
|
|
9014
|
+
}
|
|
9015
|
+
}
|
|
9016
|
+
|
|
9017
|
+
/** @private */
|
|
9018
|
+
__subscribe() {
|
|
9019
|
+
if (!directionSubscribers.includes(this)) {
|
|
9020
|
+
directionSubscribers.push(this);
|
|
9021
|
+
}
|
|
9022
|
+
}
|
|
9023
|
+
|
|
9024
|
+
/** @private */
|
|
9025
|
+
__unsubscribe() {
|
|
9026
|
+
if (directionSubscribers.includes(this)) {
|
|
9027
|
+
directionSubscribers.splice(directionSubscribers.indexOf(this), 1);
|
|
9028
|
+
}
|
|
9029
|
+
}
|
|
9030
|
+
};
|
|
9031
|
+
|
|
9032
|
+
/**
|
|
9033
|
+
* @license
|
|
9034
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9035
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9036
|
+
*/
|
|
9037
|
+
|
|
9038
|
+
if (!window.Vaadin) {
|
|
9039
|
+
window.Vaadin = {};
|
|
8543
9040
|
}
|
|
8544
9041
|
|
|
8545
9042
|
/**
|
|
8546
|
-
*
|
|
8547
|
-
*
|
|
8548
|
-
* @param {HTMLElement[]} elements
|
|
8549
|
-
* @return {HTMLElement[]}
|
|
9043
|
+
* Array of Vaadin custom element classes that have been finalized.
|
|
8550
9044
|
*/
|
|
8551
|
-
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
const len = elements.length;
|
|
8555
|
-
if (len < 2) {
|
|
8556
|
-
return elements;
|
|
8557
|
-
}
|
|
8558
|
-
const pivot = Math.ceil(len / 2);
|
|
8559
|
-
const left = sortElementsByTabIndex(elements.slice(0, pivot));
|
|
8560
|
-
const right = sortElementsByTabIndex(elements.slice(pivot));
|
|
9045
|
+
if (!window.Vaadin.registrations) {
|
|
9046
|
+
window.Vaadin.registrations = [];
|
|
9047
|
+
}
|
|
8561
9048
|
|
|
8562
|
-
|
|
9049
|
+
if (!window.Vaadin.developmentModeCallback) {
|
|
9050
|
+
window.Vaadin.developmentModeCallback = {};
|
|
8563
9051
|
}
|
|
8564
9052
|
|
|
9053
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics'] = function () {
|
|
9054
|
+
usageStatistics();
|
|
9055
|
+
};
|
|
9056
|
+
|
|
9057
|
+
let statsJob;
|
|
9058
|
+
|
|
9059
|
+
const registered = new Set();
|
|
9060
|
+
|
|
8565
9061
|
/**
|
|
8566
|
-
*
|
|
8567
|
-
*
|
|
8568
|
-
* The list of focusable elements is taken from http://stackoverflow.com/a/1600194/4228703.
|
|
8569
|
-
* However, there isn't a definite list, it's up to the browser.
|
|
8570
|
-
* The only standard we have is DOM Level 2 HTML https://www.w3.org/TR/DOM-Level-2-HTML/html.html,
|
|
8571
|
-
* according to which the only elements that have a `focus()` method are:
|
|
8572
|
-
* - HTMLInputElement
|
|
8573
|
-
* - HTMLSelectElement
|
|
8574
|
-
* - HTMLTextAreaElement
|
|
8575
|
-
* - HTMLAnchorElement
|
|
8576
|
-
*
|
|
8577
|
-
* This notably omits HTMLButtonElement and HTMLAreaElement.
|
|
8578
|
-
* Referring to these tests with tabbables in different browsers
|
|
8579
|
-
* http://allyjs.io/data-tables/focusable.html
|
|
8580
|
-
*
|
|
8581
|
-
* @param {HTMLElement} element
|
|
8582
|
-
* @return {boolean}
|
|
9062
|
+
* @polymerMixin
|
|
9063
|
+
* @mixes DirMixin
|
|
8583
9064
|
*/
|
|
8584
|
-
|
|
8585
|
-
|
|
8586
|
-
|
|
8587
|
-
|
|
8588
|
-
|
|
9065
|
+
const ElementMixin = (superClass) =>
|
|
9066
|
+
class VaadinElementMixin extends DirMixin(superClass) {
|
|
9067
|
+
static get version() {
|
|
9068
|
+
return '24.2.3';
|
|
9069
|
+
}
|
|
8589
9070
|
|
|
8590
|
-
|
|
8591
|
-
|
|
8592
|
-
|
|
8593
|
-
}
|
|
9071
|
+
/** @protected */
|
|
9072
|
+
static finalize() {
|
|
9073
|
+
super.finalize();
|
|
8594
9074
|
|
|
8595
|
-
|
|
8596
|
-
|
|
8597
|
-
|
|
9075
|
+
const { is } = this;
|
|
9076
|
+
|
|
9077
|
+
// Registers a class prototype for telemetry purposes.
|
|
9078
|
+
if (is && !registered.has(is)) {
|
|
9079
|
+
window.Vaadin.registrations.push(this);
|
|
9080
|
+
registered.add(is);
|
|
9081
|
+
|
|
9082
|
+
if (window.Vaadin.developmentModeCallback) {
|
|
9083
|
+
statsJob = Debouncer.debounce(statsJob, idlePeriod, () => {
|
|
9084
|
+
window.Vaadin.developmentModeCallback['vaadin-usage-statistics']();
|
|
9085
|
+
});
|
|
9086
|
+
enqueueDebouncer(statsJob);
|
|
9087
|
+
}
|
|
9088
|
+
}
|
|
9089
|
+
}
|
|
9090
|
+
|
|
9091
|
+
constructor() {
|
|
9092
|
+
super();
|
|
9093
|
+
|
|
9094
|
+
if (document.doctype === null) {
|
|
9095
|
+
console.warn(
|
|
9096
|
+
'Vaadin components require the "standards mode" declaration. Please add <!DOCTYPE html> to the HTML document.',
|
|
9097
|
+
);
|
|
9098
|
+
}
|
|
9099
|
+
}
|
|
9100
|
+
};
|
|
8598
9101
|
|
|
8599
9102
|
/**
|
|
8600
|
-
*
|
|
8601
|
-
*
|
|
8602
|
-
*
|
|
8603
|
-
* @return {boolean}
|
|
9103
|
+
* @license
|
|
9104
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9105
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8604
9106
|
*/
|
|
8605
|
-
function isElementFocused(element) {
|
|
8606
|
-
return element.getRootNode().activeElement === element;
|
|
8607
|
-
}
|
|
8608
9107
|
|
|
8609
9108
|
/**
|
|
8610
|
-
* Returns
|
|
8611
|
-
* It checks for the attribute "tabindex" instead of the element property
|
|
8612
|
-
* `tabIndex` since browsers assign different values to it.
|
|
8613
|
-
* e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
|
|
9109
|
+
* Returns an array of ancestor root nodes for the given node.
|
|
8614
9110
|
*
|
|
8615
|
-
*
|
|
8616
|
-
*
|
|
9111
|
+
* A root node is either a document node or a document fragment node (Shadow Root).
|
|
9112
|
+
* The array is collected by a bottom-up DOM traversing that starts with the given node
|
|
9113
|
+
* and involves both the light DOM and ancestor shadow DOM trees.
|
|
9114
|
+
*
|
|
9115
|
+
* @param {Node} node
|
|
9116
|
+
* @return {Node[]}
|
|
8617
9117
|
*/
|
|
8618
|
-
function
|
|
8619
|
-
|
|
8620
|
-
|
|
9118
|
+
function getAncestorRootNodes(node) {
|
|
9119
|
+
const result = [];
|
|
9120
|
+
|
|
9121
|
+
while (node) {
|
|
9122
|
+
if (node.nodeType === Node.DOCUMENT_NODE) {
|
|
9123
|
+
result.push(node);
|
|
9124
|
+
break;
|
|
9125
|
+
}
|
|
9126
|
+
|
|
9127
|
+
if (node.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
|
|
9128
|
+
result.push(node);
|
|
9129
|
+
node = node.host;
|
|
9130
|
+
continue;
|
|
9131
|
+
}
|
|
9132
|
+
|
|
9133
|
+
if (node.assignedSlot) {
|
|
9134
|
+
node = node.assignedSlot;
|
|
9135
|
+
continue;
|
|
9136
|
+
}
|
|
9137
|
+
|
|
9138
|
+
node = node.parentNode;
|
|
8621
9139
|
}
|
|
8622
9140
|
|
|
8623
|
-
|
|
8624
|
-
return Number(tabIndex);
|
|
9141
|
+
return result;
|
|
8625
9142
|
}
|
|
8626
9143
|
|
|
8627
9144
|
/**
|
|
8628
|
-
*
|
|
8629
|
-
* Returns if the `result` array needs to be sorted by tabindex.
|
|
9145
|
+
* Takes a string with values separated by space and returns a set the values
|
|
8630
9146
|
*
|
|
8631
|
-
* @param {
|
|
8632
|
-
* @
|
|
8633
|
-
* @return {boolean}
|
|
8634
|
-
* @private
|
|
9147
|
+
* @param {string} value
|
|
9148
|
+
* @return {Set<string>}
|
|
8635
9149
|
*/
|
|
8636
|
-
function
|
|
8637
|
-
if (
|
|
8638
|
-
|
|
8639
|
-
return false;
|
|
8640
|
-
}
|
|
8641
|
-
|
|
8642
|
-
const element = /** @type {HTMLElement} */ (node);
|
|
8643
|
-
const tabIndex = normalizeTabIndex(element);
|
|
8644
|
-
let needsSort = tabIndex > 0;
|
|
8645
|
-
if (tabIndex >= 0) {
|
|
8646
|
-
result.push(element);
|
|
9150
|
+
function deserializeAttributeValue(value) {
|
|
9151
|
+
if (!value) {
|
|
9152
|
+
return new Set();
|
|
8647
9153
|
}
|
|
8648
9154
|
|
|
8649
|
-
|
|
8650
|
-
if (element.localName === 'slot') {
|
|
8651
|
-
children = element.assignedNodes({ flatten: true });
|
|
8652
|
-
} else {
|
|
8653
|
-
// Use shadow root if possible, will check for distributed nodes.
|
|
8654
|
-
children = (element.shadowRoot || element).children;
|
|
8655
|
-
}
|
|
8656
|
-
[...children].forEach((child) => {
|
|
8657
|
-
// Ensure method is always invoked to collect focusable children.
|
|
8658
|
-
needsSort = collectFocusableNodes(child, result) || needsSort;
|
|
8659
|
-
});
|
|
8660
|
-
return needsSort;
|
|
9155
|
+
return new Set(value.split(' '));
|
|
8661
9156
|
}
|
|
8662
9157
|
|
|
8663
9158
|
/**
|
|
8664
|
-
*
|
|
8665
|
-
* The resulting array will include the root element if it is focusable.
|
|
8666
|
-
*
|
|
8667
|
-
* The method traverses nodes in shadow DOM trees too if any.
|
|
9159
|
+
* Takes a set of string values and returns a string with values separated by space
|
|
8668
9160
|
*
|
|
8669
|
-
* @param {
|
|
8670
|
-
* @return {
|
|
9161
|
+
* @param {Set<string>} values
|
|
9162
|
+
* @return {string}
|
|
8671
9163
|
*/
|
|
8672
|
-
function
|
|
8673
|
-
|
|
8674
|
-
const needsSortByTabIndex = collectFocusableNodes(element, focusableElements);
|
|
8675
|
-
// If there is at least one element with tabindex > 0,
|
|
8676
|
-
// we need to sort the final array by tabindex.
|
|
8677
|
-
if (needsSortByTabIndex) {
|
|
8678
|
-
return sortElementsByTabIndex(focusableElements);
|
|
8679
|
-
}
|
|
8680
|
-
return focusableElements;
|
|
9164
|
+
function serializeAttributeValue(values) {
|
|
9165
|
+
return values ? [...values].join(' ') : '';
|
|
8681
9166
|
}
|
|
8682
9167
|
|
|
8683
9168
|
/**
|
|
8684
|
-
*
|
|
8685
|
-
*
|
|
8686
|
-
*
|
|
9169
|
+
* Adds a value to an attribute containing space-delimited values.
|
|
9170
|
+
*
|
|
9171
|
+
* @param {HTMLElement} element
|
|
9172
|
+
* @param {string} attr
|
|
9173
|
+
* @param {string} value
|
|
8687
9174
|
*/
|
|
9175
|
+
function addValueToAttribute(element, attr, value) {
|
|
9176
|
+
const values = deserializeAttributeValue(element.getAttribute(attr));
|
|
9177
|
+
values.add(value);
|
|
9178
|
+
element.setAttribute(attr, serializeAttributeValue(values));
|
|
9179
|
+
}
|
|
8688
9180
|
|
|
8689
9181
|
/**
|
|
8690
|
-
*
|
|
9182
|
+
* Removes a value from an attribute containing space-delimited values.
|
|
9183
|
+
* If the value is the last one, the whole attribute is removed.
|
|
8691
9184
|
*
|
|
8692
|
-
* @
|
|
9185
|
+
* @param {HTMLElement} element
|
|
9186
|
+
* @param {string} attr
|
|
9187
|
+
* @param {string} value
|
|
8693
9188
|
*/
|
|
8694
|
-
|
|
8695
|
-
(
|
|
8696
|
-
|
|
8697
|
-
|
|
8698
|
-
|
|
8699
|
-
|
|
8700
|
-
|
|
8701
|
-
|
|
8702
|
-
|
|
8703
|
-
}
|
|
9189
|
+
function removeValueFromAttribute(element, attr, value) {
|
|
9190
|
+
const values = deserializeAttributeValue(element.getAttribute(attr));
|
|
9191
|
+
values.delete(value);
|
|
9192
|
+
if (values.size === 0) {
|
|
9193
|
+
element.removeAttribute(attr);
|
|
9194
|
+
return;
|
|
9195
|
+
}
|
|
9196
|
+
element.setAttribute(attr, serializeAttributeValue(values));
|
|
9197
|
+
}
|
|
8704
9198
|
|
|
8705
|
-
|
|
8706
|
-
|
|
8707
|
-
|
|
8708
|
-
|
|
8709
|
-
|
|
8710
|
-
|
|
8711
|
-
|
|
9199
|
+
/**
|
|
9200
|
+
* Returns true if the given node is an empty text node, false otherwise.
|
|
9201
|
+
*
|
|
9202
|
+
* @param {Node} node
|
|
9203
|
+
* @return {boolean}
|
|
9204
|
+
*/
|
|
9205
|
+
function isEmptyTextNode(node) {
|
|
9206
|
+
return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '';
|
|
9207
|
+
}
|
|
8712
9208
|
|
|
8713
|
-
|
|
8714
|
-
|
|
8715
|
-
|
|
8716
|
-
|
|
8717
|
-
|
|
9209
|
+
/**
|
|
9210
|
+
* @license
|
|
9211
|
+
* Copyright (c) 2023 Vaadin Ltd.
|
|
9212
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9213
|
+
*/
|
|
8718
9214
|
|
|
8719
|
-
|
|
8720
|
-
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
9215
|
+
/**
|
|
9216
|
+
* A helper for observing slot changes.
|
|
9217
|
+
*/
|
|
9218
|
+
class SlotObserver {
|
|
9219
|
+
constructor(slot, callback) {
|
|
9220
|
+
/** @type HTMLSlotElement */
|
|
9221
|
+
this.slot = slot;
|
|
8725
9222
|
|
|
8726
|
-
|
|
8727
|
-
|
|
8728
|
-
super.disconnectedCallback();
|
|
9223
|
+
/** @type Function */
|
|
9224
|
+
this.callback = callback;
|
|
8729
9225
|
|
|
8730
|
-
|
|
8731
|
-
|
|
8732
|
-
if (this.hasAttribute('focused')) {
|
|
8733
|
-
this._setFocused(false);
|
|
8734
|
-
}
|
|
8735
|
-
}
|
|
9226
|
+
/** @type {Node[]} */
|
|
9227
|
+
this._storedNodes = [];
|
|
8736
9228
|
|
|
8737
|
-
|
|
8738
|
-
|
|
8739
|
-
*
|
|
8740
|
-
* @param {boolean} focused
|
|
8741
|
-
* @protected
|
|
8742
|
-
*/
|
|
8743
|
-
_setFocused(focused) {
|
|
8744
|
-
this.toggleAttribute('focused', focused);
|
|
9229
|
+
this._connected = false;
|
|
9230
|
+
this._scheduled = false;
|
|
8745
9231
|
|
|
8746
|
-
|
|
8747
|
-
|
|
8748
|
-
|
|
8749
|
-
}
|
|
9232
|
+
this._boundSchedule = () => {
|
|
9233
|
+
this._schedule();
|
|
9234
|
+
};
|
|
8750
9235
|
|
|
8751
|
-
|
|
8752
|
-
|
|
8753
|
-
|
|
8754
|
-
* @param {FocusEvent} _event
|
|
8755
|
-
* @return {boolean}
|
|
8756
|
-
* @protected
|
|
8757
|
-
*/
|
|
8758
|
-
_shouldSetFocus(_event) {
|
|
8759
|
-
return true;
|
|
8760
|
-
}
|
|
9236
|
+
this.connect();
|
|
9237
|
+
this._schedule();
|
|
9238
|
+
}
|
|
8761
9239
|
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
8771
|
-
}
|
|
8772
|
-
},
|
|
8773
|
-
);
|
|
9240
|
+
/**
|
|
9241
|
+
* Activates an observer. This method is automatically called when
|
|
9242
|
+
* a `SlotObserver` is created. It should only be called to re-activate
|
|
9243
|
+
* an observer that has been deactivated via the `disconnect` method.
|
|
9244
|
+
*/
|
|
9245
|
+
connect() {
|
|
9246
|
+
this.slot.addEventListener('slotchange', this._boundSchedule);
|
|
9247
|
+
this._connected = true;
|
|
9248
|
+
}
|
|
8774
9249
|
|
|
8775
|
-
/**
|
|
8776
|
-
|
|
8777
|
-
|
|
8778
|
-
|
|
8779
|
-
|
|
9250
|
+
/**
|
|
9251
|
+
* Deactivates the observer. After calling this method the observer callback
|
|
9252
|
+
* will not be called when changes to slotted nodes occur. The `connect` method
|
|
9253
|
+
* may be subsequently called to reactivate the observer.
|
|
9254
|
+
*/
|
|
9255
|
+
disconnect() {
|
|
9256
|
+
this.slot.removeEventListener('slotchange', this._boundSchedule);
|
|
9257
|
+
this._connected = false;
|
|
9258
|
+
}
|
|
8780
9259
|
|
|
8781
|
-
/**
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
|
|
8785
|
-
* and restored with the last known value once the element is enabled.
|
|
8786
|
-
*
|
|
8787
|
-
* @polymerMixin
|
|
8788
|
-
* @mixes DisabledMixin
|
|
8789
|
-
*/
|
|
8790
|
-
const TabindexMixin = (superclass) =>
|
|
8791
|
-
class TabindexMixinClass extends DisabledMixin(superclass) {
|
|
8792
|
-
static get properties() {
|
|
8793
|
-
return {
|
|
8794
|
-
/**
|
|
8795
|
-
* Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
|
|
8796
|
-
*
|
|
8797
|
-
* @protected
|
|
8798
|
-
*/
|
|
8799
|
-
tabindex: {
|
|
8800
|
-
type: Number,
|
|
8801
|
-
reflectToAttribute: true,
|
|
8802
|
-
observer: '_tabindexChanged',
|
|
8803
|
-
},
|
|
9260
|
+
/** @private */
|
|
9261
|
+
_schedule() {
|
|
9262
|
+
if (!this._scheduled) {
|
|
9263
|
+
this._scheduled = true;
|
|
8804
9264
|
|
|
8805
|
-
|
|
8806
|
-
|
|
8807
|
-
|
|
8808
|
-
* @protected
|
|
8809
|
-
*/
|
|
8810
|
-
_lastTabIndex: {
|
|
8811
|
-
type: Number,
|
|
8812
|
-
},
|
|
8813
|
-
};
|
|
9265
|
+
queueMicrotask(() => {
|
|
9266
|
+
this.flush();
|
|
9267
|
+
});
|
|
8814
9268
|
}
|
|
9269
|
+
}
|
|
8815
9270
|
|
|
8816
|
-
|
|
8817
|
-
|
|
8818
|
-
|
|
8819
|
-
|
|
8820
|
-
|
|
8821
|
-
|
|
8822
|
-
|
|
8823
|
-
* @override
|
|
8824
|
-
*/
|
|
8825
|
-
_disabledChanged(disabled, oldDisabled) {
|
|
8826
|
-
super._disabledChanged(disabled, oldDisabled);
|
|
9271
|
+
/**
|
|
9272
|
+
* Run the observer callback synchronously.
|
|
9273
|
+
*/
|
|
9274
|
+
flush() {
|
|
9275
|
+
if (!this._connected) {
|
|
9276
|
+
return;
|
|
9277
|
+
}
|
|
8827
9278
|
|
|
8828
|
-
|
|
8829
|
-
|
|
8830
|
-
|
|
9279
|
+
this._scheduled = false;
|
|
9280
|
+
|
|
9281
|
+
this._processNodes();
|
|
9282
|
+
}
|
|
9283
|
+
|
|
9284
|
+
/** @private */
|
|
9285
|
+
_processNodes() {
|
|
9286
|
+
const currentNodes = this.slot.assignedNodes({ flatten: true });
|
|
9287
|
+
|
|
9288
|
+
let addedNodes = [];
|
|
9289
|
+
const removedNodes = [];
|
|
9290
|
+
const movedNodes = [];
|
|
9291
|
+
|
|
9292
|
+
if (currentNodes.length) {
|
|
9293
|
+
addedNodes = currentNodes.filter((node) => !this._storedNodes.includes(node));
|
|
9294
|
+
}
|
|
9295
|
+
|
|
9296
|
+
if (this._storedNodes.length) {
|
|
9297
|
+
this._storedNodes.forEach((node, index) => {
|
|
9298
|
+
const idx = currentNodes.indexOf(node);
|
|
9299
|
+
if (idx === -1) {
|
|
9300
|
+
removedNodes.push(node);
|
|
9301
|
+
} else if (idx !== index) {
|
|
9302
|
+
movedNodes.push(node);
|
|
8831
9303
|
}
|
|
8832
|
-
|
|
8833
|
-
} else if (oldDisabled) {
|
|
8834
|
-
this.tabindex = this._lastTabIndex;
|
|
8835
|
-
}
|
|
9304
|
+
});
|
|
8836
9305
|
}
|
|
8837
9306
|
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
* the observer reverts tabindex to -1 and rather saves the new tabindex value to apply it later.
|
|
8841
|
-
* The new value will be applied as soon as the element becomes enabled.
|
|
8842
|
-
*
|
|
8843
|
-
* @protected
|
|
8844
|
-
*/
|
|
8845
|
-
_tabindexChanged(tabindex) {
|
|
8846
|
-
if (this.disabled && tabindex !== -1) {
|
|
8847
|
-
this._lastTabIndex = tabindex;
|
|
8848
|
-
this.tabindex = -1;
|
|
8849
|
-
}
|
|
9307
|
+
if (addedNodes.length || removedNodes.length || movedNodes.length) {
|
|
9308
|
+
this.callback({ addedNodes, movedNodes, removedNodes });
|
|
8850
9309
|
}
|
|
8851
|
-
|
|
9310
|
+
|
|
9311
|
+
this._storedNodes = currentNodes;
|
|
9312
|
+
}
|
|
9313
|
+
}
|
|
8852
9314
|
|
|
8853
9315
|
/**
|
|
8854
9316
|
* @license
|
|
@@ -8856,230 +9318,818 @@ const TabindexMixin = (superclass) =>
|
|
|
8856
9318
|
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
8857
9319
|
*/
|
|
8858
9320
|
|
|
9321
|
+
let uniqueId = 0;
|
|
9322
|
+
|
|
8859
9323
|
/**
|
|
8860
|
-
*
|
|
9324
|
+
* Returns a unique integer id.
|
|
8861
9325
|
*
|
|
8862
|
-
* @
|
|
8863
|
-
* @mixes FocusMixin
|
|
8864
|
-
* @mixes TabindexMixin
|
|
9326
|
+
* @return {number}
|
|
8865
9327
|
*/
|
|
8866
|
-
|
|
8867
|
-
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
return {
|
|
8871
|
-
/**
|
|
8872
|
-
* Specify that this control should have input focus when the page loads.
|
|
8873
|
-
*/
|
|
8874
|
-
autofocus: {
|
|
8875
|
-
type: Boolean,
|
|
8876
|
-
},
|
|
8877
|
-
|
|
8878
|
-
/**
|
|
8879
|
-
* A reference to the focusable element controlled by the mixin.
|
|
8880
|
-
* It can be an input, textarea, button or any element with tabindex > -1.
|
|
8881
|
-
*
|
|
8882
|
-
* Any component implementing this mixin is expected to provide it
|
|
8883
|
-
* by using `this._setFocusElement(input)` Polymer API.
|
|
8884
|
-
*
|
|
8885
|
-
* Toggling `tabindex` attribute on the host element propagates its value to `focusElement`.
|
|
8886
|
-
*
|
|
8887
|
-
* @protected
|
|
8888
|
-
* @type {!HTMLElement}
|
|
8889
|
-
*/
|
|
8890
|
-
focusElement: {
|
|
8891
|
-
type: Object,
|
|
8892
|
-
readOnly: true,
|
|
8893
|
-
observer: '_focusElementChanged',
|
|
8894
|
-
},
|
|
8895
|
-
|
|
8896
|
-
/**
|
|
8897
|
-
* Override the property from `TabIndexMixin`
|
|
8898
|
-
* to ensure the `tabindex` attribute of the focus element
|
|
8899
|
-
* will be restored to `0` after re-enabling the element.
|
|
8900
|
-
*
|
|
8901
|
-
* @protected
|
|
8902
|
-
* @override
|
|
8903
|
-
*/
|
|
8904
|
-
_lastTabIndex: {
|
|
8905
|
-
value: 0,
|
|
8906
|
-
},
|
|
8907
|
-
};
|
|
8908
|
-
}
|
|
9328
|
+
function generateUniqueId() {
|
|
9329
|
+
// eslint-disable-next-line no-plusplus
|
|
9330
|
+
return uniqueId++;
|
|
9331
|
+
}
|
|
8909
9332
|
|
|
8910
|
-
|
|
8911
|
-
|
|
9333
|
+
/**
|
|
9334
|
+
* @license
|
|
9335
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9336
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9337
|
+
*/
|
|
8912
9338
|
|
|
8913
|
-
|
|
8914
|
-
|
|
8915
|
-
|
|
9339
|
+
/**
|
|
9340
|
+
* A controller for providing content to slot element and observing changes.
|
|
9341
|
+
*/
|
|
9342
|
+
class SlotController extends EventTarget {
|
|
9343
|
+
/**
|
|
9344
|
+
* Ensure that every instance has unique ID.
|
|
9345
|
+
*
|
|
9346
|
+
* @param {HTMLElement} host
|
|
9347
|
+
* @param {string} slotName
|
|
9348
|
+
* @return {string}
|
|
9349
|
+
* @protected
|
|
9350
|
+
*/
|
|
9351
|
+
static generateId(host, slotName) {
|
|
9352
|
+
const prefix = slotName || 'default';
|
|
9353
|
+
return `${prefix}-${host.localName}-${generateUniqueId()}`;
|
|
9354
|
+
}
|
|
8916
9355
|
|
|
8917
|
-
|
|
8918
|
-
|
|
8919
|
-
super.ready();
|
|
9356
|
+
constructor(host, slotName, tagName, config = {}) {
|
|
9357
|
+
super();
|
|
8920
9358
|
|
|
8921
|
-
|
|
8922
|
-
requestAnimationFrame(() => {
|
|
8923
|
-
this.focus();
|
|
8924
|
-
this.setAttribute('focus-ring', '');
|
|
8925
|
-
});
|
|
8926
|
-
}
|
|
8927
|
-
}
|
|
9359
|
+
const { initializer, multiple, observe, useUniqueId } = config;
|
|
8928
9360
|
|
|
8929
|
-
|
|
8930
|
-
|
|
8931
|
-
|
|
8932
|
-
|
|
8933
|
-
|
|
8934
|
-
|
|
8935
|
-
this.focusElement.focus();
|
|
8936
|
-
}
|
|
8937
|
-
}
|
|
9361
|
+
this.host = host;
|
|
9362
|
+
this.slotName = slotName;
|
|
9363
|
+
this.tagName = tagName;
|
|
9364
|
+
this.observe = typeof observe === 'boolean' ? observe : true;
|
|
9365
|
+
this.multiple = typeof multiple === 'boolean' ? multiple : false;
|
|
9366
|
+
this.slotInitializer = initializer;
|
|
8938
9367
|
|
|
8939
|
-
|
|
8940
|
-
|
|
8941
|
-
|
|
8942
|
-
*/
|
|
8943
|
-
blur() {
|
|
8944
|
-
if (this.focusElement) {
|
|
8945
|
-
this.focusElement.blur();
|
|
8946
|
-
}
|
|
8947
|
-
}
|
|
9368
|
+
if (multiple) {
|
|
9369
|
+
this.nodes = [];
|
|
9370
|
+
}
|
|
8948
9371
|
|
|
8949
|
-
|
|
8950
|
-
|
|
8951
|
-
|
|
8952
|
-
|
|
8953
|
-
|
|
8954
|
-
if (this.focusElement && !this.disabled) {
|
|
8955
|
-
this.focusElement.click();
|
|
8956
|
-
}
|
|
8957
|
-
}
|
|
9372
|
+
// Only generate the default ID if requested by the controller.
|
|
9373
|
+
if (useUniqueId) {
|
|
9374
|
+
this.defaultId = this.constructor.generateId(host, slotName);
|
|
9375
|
+
}
|
|
9376
|
+
}
|
|
8958
9377
|
|
|
8959
|
-
|
|
8960
|
-
|
|
8961
|
-
|
|
8962
|
-
|
|
8963
|
-
|
|
8964
|
-
|
|
8965
|
-
} else if (oldElement) {
|
|
8966
|
-
this._removeFocusListeners(oldElement);
|
|
8967
|
-
}
|
|
9378
|
+
hostConnected() {
|
|
9379
|
+
if (!this.initialized) {
|
|
9380
|
+
if (this.multiple) {
|
|
9381
|
+
this.initMultiple();
|
|
9382
|
+
} else {
|
|
9383
|
+
this.initSingle();
|
|
8968
9384
|
}
|
|
8969
9385
|
|
|
8970
|
-
|
|
8971
|
-
|
|
8972
|
-
* @protected
|
|
8973
|
-
*/
|
|
8974
|
-
_addFocusListeners(element) {
|
|
8975
|
-
element.addEventListener('blur', this._boundOnBlur);
|
|
8976
|
-
element.addEventListener('focus', this._boundOnFocus);
|
|
9386
|
+
if (this.observe) {
|
|
9387
|
+
this.observeSlot();
|
|
8977
9388
|
}
|
|
8978
9389
|
|
|
8979
|
-
|
|
8980
|
-
|
|
8981
|
-
|
|
8982
|
-
*/
|
|
8983
|
-
_removeFocusListeners(element) {
|
|
8984
|
-
element.removeEventListener('blur', this._boundOnBlur);
|
|
8985
|
-
element.removeEventListener('focus', this._boundOnFocus);
|
|
8986
|
-
}
|
|
9390
|
+
this.initialized = true;
|
|
9391
|
+
}
|
|
9392
|
+
}
|
|
8987
9393
|
|
|
8988
|
-
|
|
8989
|
-
|
|
8990
|
-
|
|
8991
|
-
* when the focusable element is placed in light DOM.
|
|
8992
|
-
* @param {FocusEvent} event
|
|
8993
|
-
* @protected
|
|
8994
|
-
*/
|
|
8995
|
-
_onFocus(event) {
|
|
8996
|
-
event.stopPropagation();
|
|
8997
|
-
this.dispatchEvent(new Event('focus'));
|
|
8998
|
-
}
|
|
9394
|
+
/** @protected */
|
|
9395
|
+
initSingle() {
|
|
9396
|
+
let node = this.getSlotChild();
|
|
8999
9397
|
|
|
9000
|
-
|
|
9001
|
-
|
|
9002
|
-
|
|
9003
|
-
|
|
9004
|
-
|
|
9005
|
-
|
|
9006
|
-
|
|
9007
|
-
|
|
9008
|
-
event.stopPropagation();
|
|
9009
|
-
this.dispatchEvent(new Event('blur'));
|
|
9010
|
-
}
|
|
9398
|
+
if (!node) {
|
|
9399
|
+
node = this.attachDefaultNode();
|
|
9400
|
+
this.initNode(node);
|
|
9401
|
+
} else {
|
|
9402
|
+
this.node = node;
|
|
9403
|
+
this.initAddedNode(node);
|
|
9404
|
+
}
|
|
9405
|
+
}
|
|
9011
9406
|
|
|
9012
|
-
|
|
9013
|
-
|
|
9014
|
-
|
|
9015
|
-
* @protected
|
|
9016
|
-
* @override
|
|
9017
|
-
*/
|
|
9018
|
-
_shouldSetFocus(event) {
|
|
9019
|
-
return event.target === this.focusElement;
|
|
9020
|
-
}
|
|
9407
|
+
/** @protected */
|
|
9408
|
+
initMultiple() {
|
|
9409
|
+
const children = this.getSlotChildren();
|
|
9021
9410
|
|
|
9022
|
-
|
|
9023
|
-
|
|
9024
|
-
|
|
9025
|
-
|
|
9026
|
-
|
|
9027
|
-
*/
|
|
9028
|
-
_shouldRemoveFocus(event) {
|
|
9029
|
-
return event.target === this.focusElement;
|
|
9411
|
+
if (children.length === 0) {
|
|
9412
|
+
const defaultNode = this.attachDefaultNode();
|
|
9413
|
+
if (defaultNode) {
|
|
9414
|
+
this.nodes = [defaultNode];
|
|
9415
|
+
this.initNode(defaultNode);
|
|
9030
9416
|
}
|
|
9417
|
+
} else {
|
|
9418
|
+
this.nodes = children;
|
|
9419
|
+
children.forEach((node) => {
|
|
9420
|
+
this.initAddedNode(node);
|
|
9421
|
+
});
|
|
9422
|
+
}
|
|
9423
|
+
}
|
|
9031
9424
|
|
|
9032
|
-
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
super._disabledChanged(disabled, oldDisabled);
|
|
9425
|
+
/**
|
|
9426
|
+
* Create and attach default node using the provided tag name, if any.
|
|
9427
|
+
* @return {Node | undefined}
|
|
9428
|
+
* @protected
|
|
9429
|
+
*/
|
|
9430
|
+
attachDefaultNode() {
|
|
9431
|
+
const { host, slotName, tagName } = this;
|
|
9040
9432
|
|
|
9041
|
-
|
|
9042
|
-
|
|
9043
|
-
}
|
|
9433
|
+
// Check if the node was created previously and if so, reuse it.
|
|
9434
|
+
let node = this.defaultNode;
|
|
9044
9435
|
|
|
9045
|
-
|
|
9046
|
-
|
|
9436
|
+
// Tag name is optional, sometimes we don't init default content.
|
|
9437
|
+
if (!node && tagName) {
|
|
9438
|
+
node = document.createElement(tagName);
|
|
9439
|
+
if (node instanceof Element) {
|
|
9440
|
+
if (slotName !== '') {
|
|
9441
|
+
node.setAttribute('slot', slotName);
|
|
9047
9442
|
}
|
|
9443
|
+
this.node = node;
|
|
9444
|
+
this.defaultNode = node;
|
|
9048
9445
|
}
|
|
9446
|
+
}
|
|
9049
9447
|
|
|
9050
|
-
|
|
9051
|
-
|
|
9052
|
-
|
|
9053
|
-
|
|
9054
|
-
|
|
9055
|
-
|
|
9056
|
-
|
|
9448
|
+
if (node) {
|
|
9449
|
+
host.appendChild(node);
|
|
9450
|
+
}
|
|
9451
|
+
|
|
9452
|
+
return node;
|
|
9453
|
+
}
|
|
9454
|
+
|
|
9455
|
+
/**
|
|
9456
|
+
* Return the list of nodes matching the slot managed by the controller.
|
|
9457
|
+
* @return {Node}
|
|
9458
|
+
*/
|
|
9459
|
+
getSlotChildren() {
|
|
9460
|
+
const { slotName } = this;
|
|
9461
|
+
return Array.from(this.host.childNodes).filter((node) => {
|
|
9462
|
+
// Either an element (any slot) or a text node (only un-named slot).
|
|
9463
|
+
return (
|
|
9464
|
+
(node.nodeType === Node.ELEMENT_NODE && node.slot === slotName) ||
|
|
9465
|
+
(node.nodeType === Node.TEXT_NODE && node.textContent.trim() && slotName === '')
|
|
9466
|
+
);
|
|
9467
|
+
});
|
|
9468
|
+
}
|
|
9469
|
+
|
|
9470
|
+
/**
|
|
9471
|
+
* Return a reference to the node managed by the controller.
|
|
9472
|
+
* @return {Node}
|
|
9473
|
+
*/
|
|
9474
|
+
getSlotChild() {
|
|
9475
|
+
return this.getSlotChildren()[0];
|
|
9476
|
+
}
|
|
9477
|
+
|
|
9478
|
+
/**
|
|
9479
|
+
* Run `slotInitializer` for the node managed by the controller.
|
|
9480
|
+
*
|
|
9481
|
+
* @param {Node} node
|
|
9482
|
+
* @protected
|
|
9483
|
+
*/
|
|
9484
|
+
initNode(node) {
|
|
9485
|
+
const { slotInitializer } = this;
|
|
9486
|
+
// Don't try to bind `this` to initializer (normally it's arrow function).
|
|
9487
|
+
// Instead, pass the host as a first argument to access component's state.
|
|
9488
|
+
if (slotInitializer) {
|
|
9489
|
+
slotInitializer(node, this.host);
|
|
9490
|
+
}
|
|
9491
|
+
}
|
|
9492
|
+
|
|
9493
|
+
/**
|
|
9494
|
+
* Override to initialize the newly added custom node.
|
|
9495
|
+
*
|
|
9496
|
+
* @param {Node} _node
|
|
9497
|
+
* @protected
|
|
9498
|
+
*/
|
|
9499
|
+
initCustomNode(_node) {}
|
|
9500
|
+
|
|
9501
|
+
/**
|
|
9502
|
+
* Override to teardown slotted node when it's removed.
|
|
9503
|
+
*
|
|
9504
|
+
* @param {Node} _node
|
|
9505
|
+
* @protected
|
|
9506
|
+
*/
|
|
9507
|
+
teardownNode(_node) {}
|
|
9508
|
+
|
|
9509
|
+
/**
|
|
9510
|
+
* Run both `initCustomNode` and `initNode` for a custom slotted node.
|
|
9511
|
+
*
|
|
9512
|
+
* @param {Node} node
|
|
9513
|
+
* @protected
|
|
9514
|
+
*/
|
|
9515
|
+
initAddedNode(node) {
|
|
9516
|
+
if (node !== this.defaultNode) {
|
|
9517
|
+
this.initCustomNode(node);
|
|
9518
|
+
this.initNode(node);
|
|
9519
|
+
}
|
|
9520
|
+
}
|
|
9521
|
+
|
|
9522
|
+
/**
|
|
9523
|
+
* Setup the observer to manage slot content changes.
|
|
9524
|
+
* @protected
|
|
9525
|
+
*/
|
|
9526
|
+
observeSlot() {
|
|
9527
|
+
const { slotName } = this;
|
|
9528
|
+
const selector = slotName === '' ? 'slot:not([name])' : `slot[name=${slotName}]`;
|
|
9529
|
+
const slot = this.host.shadowRoot.querySelector(selector);
|
|
9530
|
+
|
|
9531
|
+
this.__slotObserver = new SlotObserver(slot, ({ addedNodes, removedNodes }) => {
|
|
9532
|
+
const current = this.multiple ? this.nodes : [this.node];
|
|
9533
|
+
|
|
9534
|
+
// Calling `slot.assignedNodes()` includes whitespace text nodes in case of default slot:
|
|
9535
|
+
// unlike comment nodes, they are not filtered out. So we need to manually ignore them.
|
|
9536
|
+
const newNodes = addedNodes.filter((node) => !isEmptyTextNode(node) && !current.includes(node));
|
|
9537
|
+
|
|
9538
|
+
if (removedNodes.length) {
|
|
9539
|
+
this.nodes = current.filter((node) => !removedNodes.includes(node));
|
|
9540
|
+
|
|
9541
|
+
removedNodes.forEach((node) => {
|
|
9542
|
+
this.teardownNode(node);
|
|
9543
|
+
});
|
|
9544
|
+
}
|
|
9545
|
+
|
|
9546
|
+
if (newNodes && newNodes.length > 0) {
|
|
9547
|
+
if (this.multiple) {
|
|
9548
|
+
// Remove default node if exists
|
|
9549
|
+
if (this.defaultNode) {
|
|
9550
|
+
this.defaultNode.remove();
|
|
9551
|
+
}
|
|
9552
|
+
this.nodes = [...current, ...newNodes].filter((node) => node !== this.defaultNode);
|
|
9553
|
+
newNodes.forEach((node) => {
|
|
9554
|
+
this.initAddedNode(node);
|
|
9555
|
+
});
|
|
9556
|
+
} else {
|
|
9557
|
+
// Remove previous node if exists
|
|
9558
|
+
if (this.node) {
|
|
9559
|
+
this.node.remove();
|
|
9560
|
+
}
|
|
9561
|
+
this.node = newNodes[0];
|
|
9562
|
+
this.initAddedNode(this.node);
|
|
9563
|
+
}
|
|
9564
|
+
}
|
|
9565
|
+
});
|
|
9566
|
+
}
|
|
9567
|
+
}
|
|
9568
|
+
|
|
9569
|
+
/**
|
|
9570
|
+
* @license
|
|
9571
|
+
* Copyright (c) 2022 - 2023 Vaadin Ltd.
|
|
9572
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9573
|
+
*/
|
|
9574
|
+
|
|
9575
|
+
/**
|
|
9576
|
+
* A controller that manages the slotted tooltip element.
|
|
9577
|
+
*/
|
|
9578
|
+
class TooltipController extends SlotController {
|
|
9579
|
+
constructor(host) {
|
|
9580
|
+
// Do not provide slot factory to create tooltip lazily.
|
|
9581
|
+
super(host, 'tooltip');
|
|
9582
|
+
|
|
9583
|
+
this.setTarget(host);
|
|
9584
|
+
}
|
|
9585
|
+
|
|
9586
|
+
/**
|
|
9587
|
+
* Override to initialize the newly added custom tooltip.
|
|
9588
|
+
*
|
|
9589
|
+
* @param {Node} tooltipNode
|
|
9590
|
+
* @protected
|
|
9591
|
+
* @override
|
|
9592
|
+
*/
|
|
9593
|
+
initCustomNode(tooltipNode) {
|
|
9594
|
+
tooltipNode.target = this.target;
|
|
9595
|
+
|
|
9596
|
+
if (this.ariaTarget !== undefined) {
|
|
9597
|
+
tooltipNode.ariaTarget = this.ariaTarget;
|
|
9598
|
+
}
|
|
9599
|
+
|
|
9600
|
+
if (this.context !== undefined) {
|
|
9601
|
+
tooltipNode.context = this.context;
|
|
9602
|
+
}
|
|
9603
|
+
|
|
9604
|
+
if (this.manual !== undefined) {
|
|
9605
|
+
tooltipNode.manual = this.manual;
|
|
9606
|
+
}
|
|
9607
|
+
|
|
9608
|
+
if (this.opened !== undefined) {
|
|
9609
|
+
tooltipNode.opened = this.opened;
|
|
9610
|
+
}
|
|
9611
|
+
|
|
9612
|
+
if (this.position !== undefined) {
|
|
9613
|
+
tooltipNode._position = this.position;
|
|
9614
|
+
}
|
|
9615
|
+
|
|
9616
|
+
if (this.shouldShow !== undefined) {
|
|
9617
|
+
tooltipNode.shouldShow = this.shouldShow;
|
|
9618
|
+
}
|
|
9619
|
+
|
|
9620
|
+
this.__notifyChange();
|
|
9621
|
+
}
|
|
9622
|
+
|
|
9623
|
+
/**
|
|
9624
|
+
* Override to notify the host when the tooltip is removed.
|
|
9625
|
+
*
|
|
9626
|
+
* @param {Node} tooltipNode
|
|
9627
|
+
* @protected
|
|
9628
|
+
* @override
|
|
9629
|
+
*/
|
|
9630
|
+
teardownNode() {
|
|
9631
|
+
this.__notifyChange();
|
|
9632
|
+
}
|
|
9633
|
+
|
|
9634
|
+
/**
|
|
9635
|
+
* Set an HTML element for linking with the tooltip overlay
|
|
9636
|
+
* via `aria-describedby` attribute used by screen readers.
|
|
9637
|
+
* @param {HTMLElement} ariaTarget
|
|
9638
|
+
*/
|
|
9639
|
+
setAriaTarget(ariaTarget) {
|
|
9640
|
+
this.ariaTarget = ariaTarget;
|
|
9641
|
+
|
|
9642
|
+
const tooltipNode = this.node;
|
|
9643
|
+
if (tooltipNode) {
|
|
9644
|
+
tooltipNode.ariaTarget = ariaTarget;
|
|
9645
|
+
}
|
|
9646
|
+
}
|
|
9647
|
+
|
|
9648
|
+
/**
|
|
9649
|
+
* Set a context object to be used by generator.
|
|
9650
|
+
* @param {object} context
|
|
9651
|
+
*/
|
|
9652
|
+
setContext(context) {
|
|
9653
|
+
this.context = context;
|
|
9654
|
+
|
|
9655
|
+
const tooltipNode = this.node;
|
|
9656
|
+
if (tooltipNode) {
|
|
9657
|
+
tooltipNode.context = context;
|
|
9658
|
+
}
|
|
9659
|
+
}
|
|
9660
|
+
|
|
9661
|
+
/**
|
|
9662
|
+
* Toggle manual state on the slotted tooltip.
|
|
9663
|
+
* @param {boolean} manual
|
|
9664
|
+
*/
|
|
9665
|
+
setManual(manual) {
|
|
9666
|
+
this.manual = manual;
|
|
9667
|
+
|
|
9668
|
+
const tooltipNode = this.node;
|
|
9669
|
+
if (tooltipNode) {
|
|
9670
|
+
tooltipNode.manual = manual;
|
|
9671
|
+
}
|
|
9672
|
+
}
|
|
9673
|
+
|
|
9674
|
+
/**
|
|
9675
|
+
* Toggle opened state on the slotted tooltip.
|
|
9676
|
+
* @param {boolean} opened
|
|
9677
|
+
*/
|
|
9678
|
+
setOpened(opened) {
|
|
9679
|
+
this.opened = opened;
|
|
9680
|
+
|
|
9681
|
+
const tooltipNode = this.node;
|
|
9682
|
+
if (tooltipNode) {
|
|
9683
|
+
tooltipNode.opened = opened;
|
|
9684
|
+
}
|
|
9685
|
+
}
|
|
9686
|
+
|
|
9687
|
+
/**
|
|
9688
|
+
* Set default position for the slotted tooltip.
|
|
9689
|
+
* This can be overridden by setting the position
|
|
9690
|
+
* using corresponding property or attribute.
|
|
9691
|
+
* @param {string} position
|
|
9692
|
+
*/
|
|
9693
|
+
setPosition(position) {
|
|
9694
|
+
this.position = position;
|
|
9695
|
+
|
|
9696
|
+
const tooltipNode = this.node;
|
|
9697
|
+
if (tooltipNode) {
|
|
9698
|
+
tooltipNode._position = position;
|
|
9699
|
+
}
|
|
9700
|
+
}
|
|
9701
|
+
|
|
9702
|
+
/**
|
|
9703
|
+
* Set function used to detect whether to show
|
|
9704
|
+
* the tooltip based on a condition.
|
|
9705
|
+
* @param {Function} shouldShow
|
|
9706
|
+
*/
|
|
9707
|
+
setShouldShow(shouldShow) {
|
|
9708
|
+
this.shouldShow = shouldShow;
|
|
9709
|
+
|
|
9710
|
+
const tooltipNode = this.node;
|
|
9711
|
+
if (tooltipNode) {
|
|
9712
|
+
tooltipNode.shouldShow = shouldShow;
|
|
9713
|
+
}
|
|
9714
|
+
}
|
|
9715
|
+
|
|
9716
|
+
/**
|
|
9717
|
+
* Set an HTML element to attach the tooltip to.
|
|
9718
|
+
* @param {HTMLElement} target
|
|
9719
|
+
*/
|
|
9720
|
+
setTarget(target) {
|
|
9721
|
+
this.target = target;
|
|
9722
|
+
|
|
9723
|
+
const tooltipNode = this.node;
|
|
9724
|
+
if (tooltipNode) {
|
|
9725
|
+
tooltipNode.target = target;
|
|
9726
|
+
}
|
|
9727
|
+
}
|
|
9728
|
+
|
|
9729
|
+
/** @private */
|
|
9730
|
+
__notifyChange() {
|
|
9731
|
+
this.dispatchEvent(new CustomEvent('tooltip-changed', { detail: { node: this.node } }));
|
|
9732
|
+
}
|
|
9733
|
+
}
|
|
9734
|
+
|
|
9735
|
+
/**
|
|
9736
|
+
* @license
|
|
9737
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9738
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9739
|
+
*/
|
|
9740
|
+
|
|
9741
|
+
/**
|
|
9742
|
+
* A mixin to provide disabled property for field components.
|
|
9743
|
+
*
|
|
9744
|
+
* @polymerMixin
|
|
9745
|
+
*/
|
|
9746
|
+
const DisabledMixin = dedupingMixin(
|
|
9747
|
+
(superclass) =>
|
|
9748
|
+
class DisabledMixinClass extends superclass {
|
|
9749
|
+
static get properties() {
|
|
9750
|
+
return {
|
|
9751
|
+
/**
|
|
9752
|
+
* If true, the user cannot interact with this element.
|
|
9753
|
+
*/
|
|
9754
|
+
disabled: {
|
|
9755
|
+
type: Boolean,
|
|
9756
|
+
value: false,
|
|
9757
|
+
observer: '_disabledChanged',
|
|
9758
|
+
reflectToAttribute: true,
|
|
9759
|
+
},
|
|
9760
|
+
};
|
|
9761
|
+
}
|
|
9762
|
+
|
|
9763
|
+
/**
|
|
9764
|
+
* @param {boolean} disabled
|
|
9765
|
+
* @protected
|
|
9766
|
+
*/
|
|
9767
|
+
_disabledChanged(disabled) {
|
|
9768
|
+
this._setAriaDisabled(disabled);
|
|
9769
|
+
}
|
|
9770
|
+
|
|
9771
|
+
/**
|
|
9772
|
+
* @param {boolean} disabled
|
|
9773
|
+
* @protected
|
|
9774
|
+
*/
|
|
9775
|
+
_setAriaDisabled(disabled) {
|
|
9776
|
+
if (disabled) {
|
|
9777
|
+
this.setAttribute('aria-disabled', 'true');
|
|
9778
|
+
} else {
|
|
9779
|
+
this.removeAttribute('aria-disabled');
|
|
9780
|
+
}
|
|
9781
|
+
}
|
|
9782
|
+
|
|
9783
|
+
/**
|
|
9784
|
+
* Overrides the default element `click` method in order to prevent
|
|
9785
|
+
* firing the `click` event when the element is disabled.
|
|
9786
|
+
* @protected
|
|
9787
|
+
* @override
|
|
9788
|
+
*/
|
|
9789
|
+
click() {
|
|
9790
|
+
if (!this.disabled) {
|
|
9791
|
+
super.click();
|
|
9792
|
+
}
|
|
9793
|
+
}
|
|
9794
|
+
},
|
|
9795
|
+
);
|
|
9796
|
+
|
|
9797
|
+
/**
|
|
9798
|
+
* @license
|
|
9799
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9800
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9801
|
+
*/
|
|
9802
|
+
|
|
9803
|
+
/**
|
|
9804
|
+
* A mixin that manages keyboard handling.
|
|
9805
|
+
* The mixin subscribes to the keyboard events while an actual implementation
|
|
9806
|
+
* for the event handlers is left to the client (a component or another mixin).
|
|
9807
|
+
*
|
|
9808
|
+
* @polymerMixin
|
|
9809
|
+
*/
|
|
9810
|
+
const KeyboardMixin = dedupingMixin(
|
|
9811
|
+
(superclass) =>
|
|
9812
|
+
class KeyboardMixinClass extends superclass {
|
|
9813
|
+
/** @protected */
|
|
9814
|
+
ready() {
|
|
9815
|
+
super.ready();
|
|
9816
|
+
|
|
9817
|
+
this.addEventListener('keydown', (event) => {
|
|
9818
|
+
this._onKeyDown(event);
|
|
9819
|
+
});
|
|
9820
|
+
|
|
9821
|
+
this.addEventListener('keyup', (event) => {
|
|
9822
|
+
this._onKeyUp(event);
|
|
9823
|
+
});
|
|
9824
|
+
}
|
|
9825
|
+
|
|
9826
|
+
/**
|
|
9827
|
+
* A handler for the `keydown` event. By default, it calls
|
|
9828
|
+
* separate methods for handling "Enter" and "Escape" keys.
|
|
9829
|
+
* Override the method to implement your own behavior.
|
|
9830
|
+
*
|
|
9831
|
+
* @param {KeyboardEvent} event
|
|
9832
|
+
* @protected
|
|
9833
|
+
*/
|
|
9834
|
+
_onKeyDown(event) {
|
|
9835
|
+
switch (event.key) {
|
|
9836
|
+
case 'Enter':
|
|
9837
|
+
this._onEnter(event);
|
|
9838
|
+
break;
|
|
9839
|
+
case 'Escape':
|
|
9840
|
+
this._onEscape(event);
|
|
9841
|
+
break;
|
|
9842
|
+
}
|
|
9843
|
+
}
|
|
9844
|
+
|
|
9845
|
+
/**
|
|
9846
|
+
* A handler for the `keyup` event. By default, it does nothing.
|
|
9847
|
+
* Override the method to implement your own behavior.
|
|
9848
|
+
*
|
|
9849
|
+
* @param {KeyboardEvent} _event
|
|
9850
|
+
* @protected
|
|
9057
9851
|
*/
|
|
9058
|
-
|
|
9059
|
-
|
|
9852
|
+
_onKeyUp(_event) {
|
|
9853
|
+
// To be implemented.
|
|
9060
9854
|
}
|
|
9061
9855
|
|
|
9062
|
-
/**
|
|
9063
|
-
|
|
9064
|
-
|
|
9065
|
-
|
|
9856
|
+
/**
|
|
9857
|
+
* A handler for the "Enter" key. By default, it does nothing.
|
|
9858
|
+
* Override the method to implement your own behavior.
|
|
9859
|
+
*
|
|
9860
|
+
* @param {KeyboardEvent} _event
|
|
9861
|
+
* @protected
|
|
9862
|
+
*/
|
|
9863
|
+
_onEnter(_event) {
|
|
9864
|
+
// To be implemented.
|
|
9865
|
+
}
|
|
9866
|
+
|
|
9867
|
+
/**
|
|
9868
|
+
* A handler for the "Escape" key. By default, it does nothing.
|
|
9869
|
+
* Override the method to implement your own behavior.
|
|
9870
|
+
*
|
|
9871
|
+
* @param {KeyboardEvent} _event
|
|
9872
|
+
* @protected
|
|
9873
|
+
*/
|
|
9874
|
+
_onEscape(_event) {
|
|
9875
|
+
// To be implemented.
|
|
9876
|
+
}
|
|
9877
|
+
},
|
|
9878
|
+
);
|
|
9879
|
+
|
|
9880
|
+
/**
|
|
9881
|
+
* @license
|
|
9882
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
9883
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9884
|
+
*/
|
|
9885
|
+
|
|
9886
|
+
// We consider the keyboard to be active if the window has received a keydown
|
|
9887
|
+
// event since the last mousedown event.
|
|
9888
|
+
let keyboardActive = false;
|
|
9889
|
+
|
|
9890
|
+
// Listen for top-level keydown and mousedown events.
|
|
9891
|
+
// Use capture phase so we detect events even if they're handled.
|
|
9892
|
+
window.addEventListener(
|
|
9893
|
+
'keydown',
|
|
9894
|
+
() => {
|
|
9895
|
+
keyboardActive = true;
|
|
9896
|
+
},
|
|
9897
|
+
{ capture: true },
|
|
9898
|
+
);
|
|
9899
|
+
|
|
9900
|
+
window.addEventListener(
|
|
9901
|
+
'mousedown',
|
|
9902
|
+
() => {
|
|
9903
|
+
keyboardActive = false;
|
|
9904
|
+
},
|
|
9905
|
+
{ capture: true },
|
|
9906
|
+
);
|
|
9907
|
+
|
|
9908
|
+
/**
|
|
9909
|
+
* Returns the actually focused element by traversing shadow
|
|
9910
|
+
* trees recursively to ensure it's the leaf element.
|
|
9911
|
+
*
|
|
9912
|
+
* @return {Element}
|
|
9913
|
+
*/
|
|
9914
|
+
function getDeepActiveElement() {
|
|
9915
|
+
let host = document.activeElement || document.body;
|
|
9916
|
+
while (host.shadowRoot && host.shadowRoot.activeElement) {
|
|
9917
|
+
host = host.shadowRoot.activeElement;
|
|
9918
|
+
}
|
|
9919
|
+
return host;
|
|
9920
|
+
}
|
|
9921
|
+
|
|
9922
|
+
/**
|
|
9923
|
+
* Returns true if the window has received a keydown
|
|
9924
|
+
* event since the last mousedown event.
|
|
9925
|
+
*
|
|
9926
|
+
* @return {boolean}
|
|
9927
|
+
*/
|
|
9928
|
+
function isKeyboardActive() {
|
|
9929
|
+
return keyboardActive;
|
|
9930
|
+
}
|
|
9931
|
+
|
|
9932
|
+
/**
|
|
9933
|
+
* Returns true if the element is hidden directly with `display: none` or `visibility: hidden`,
|
|
9934
|
+
* false otherwise.
|
|
9935
|
+
*
|
|
9936
|
+
* The method doesn't traverse the element's ancestors, it only checks for the CSS properties
|
|
9937
|
+
* set directly to or inherited by the element.
|
|
9938
|
+
*
|
|
9939
|
+
* @param {HTMLElement} element
|
|
9940
|
+
* @return {boolean}
|
|
9941
|
+
*/
|
|
9942
|
+
function isElementHiddenDirectly(element) {
|
|
9943
|
+
// Check inline style first to save a re-flow.
|
|
9944
|
+
const style = element.style;
|
|
9945
|
+
if (style.visibility === 'hidden' || style.display === 'none') {
|
|
9946
|
+
return true;
|
|
9947
|
+
}
|
|
9948
|
+
|
|
9949
|
+
const computedStyle = window.getComputedStyle(element);
|
|
9950
|
+
if (computedStyle.visibility === 'hidden' || computedStyle.display === 'none') {
|
|
9951
|
+
return true;
|
|
9952
|
+
}
|
|
9953
|
+
|
|
9954
|
+
return false;
|
|
9955
|
+
}
|
|
9956
|
+
|
|
9957
|
+
/**
|
|
9958
|
+
* Returns if element `a` has lower tab order compared to element `b`
|
|
9959
|
+
* (both elements are assumed to be focusable and tabbable).
|
|
9960
|
+
* Elements with tabindex = 0 have lower tab order compared to elements
|
|
9961
|
+
* with tabindex > 0.
|
|
9962
|
+
* If both have same tabindex, it returns false.
|
|
9963
|
+
*
|
|
9964
|
+
* @param {HTMLElement} a
|
|
9965
|
+
* @param {HTMLElement} b
|
|
9966
|
+
* @return {boolean}
|
|
9967
|
+
*/
|
|
9968
|
+
function hasLowerTabOrder(a, b) {
|
|
9969
|
+
// Normalize tabIndexes
|
|
9970
|
+
// e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
|
|
9971
|
+
const ati = Math.max(a.tabIndex, 0);
|
|
9972
|
+
const bti = Math.max(b.tabIndex, 0);
|
|
9973
|
+
return ati === 0 || bti === 0 ? bti > ati : ati > bti;
|
|
9974
|
+
}
|
|
9975
|
+
|
|
9976
|
+
/**
|
|
9977
|
+
* Merge sort iterator, merges the two arrays into one, sorted by tabindex.
|
|
9978
|
+
*
|
|
9979
|
+
* @param {HTMLElement[]} left
|
|
9980
|
+
* @param {HTMLElement[]} right
|
|
9981
|
+
* @return {HTMLElement[]}
|
|
9982
|
+
*/
|
|
9983
|
+
function mergeSortByTabIndex(left, right) {
|
|
9984
|
+
const result = [];
|
|
9985
|
+
while (left.length > 0 && right.length > 0) {
|
|
9986
|
+
if (hasLowerTabOrder(left[0], right[0])) {
|
|
9987
|
+
result.push(right.shift());
|
|
9988
|
+
} else {
|
|
9989
|
+
result.push(left.shift());
|
|
9990
|
+
}
|
|
9991
|
+
}
|
|
9992
|
+
|
|
9993
|
+
return result.concat(left, right);
|
|
9994
|
+
}
|
|
9995
|
+
|
|
9996
|
+
/**
|
|
9997
|
+
* Sorts an array of elements by tabindex. Returns a new array.
|
|
9998
|
+
*
|
|
9999
|
+
* @param {HTMLElement[]} elements
|
|
10000
|
+
* @return {HTMLElement[]}
|
|
10001
|
+
*/
|
|
10002
|
+
function sortElementsByTabIndex(elements) {
|
|
10003
|
+
// Implement a merge sort as Array.prototype.sort does a non-stable sort
|
|
10004
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
|
|
10005
|
+
const len = elements.length;
|
|
10006
|
+
if (len < 2) {
|
|
10007
|
+
return elements;
|
|
10008
|
+
}
|
|
10009
|
+
const pivot = Math.ceil(len / 2);
|
|
10010
|
+
const left = sortElementsByTabIndex(elements.slice(0, pivot));
|
|
10011
|
+
const right = sortElementsByTabIndex(elements.slice(pivot));
|
|
10012
|
+
|
|
10013
|
+
return mergeSortByTabIndex(left, right);
|
|
10014
|
+
}
|
|
10015
|
+
|
|
10016
|
+
/**
|
|
10017
|
+
* Returns true if the element is focusable, otherwise false.
|
|
10018
|
+
*
|
|
10019
|
+
* The list of focusable elements is taken from http://stackoverflow.com/a/1600194/4228703.
|
|
10020
|
+
* However, there isn't a definite list, it's up to the browser.
|
|
10021
|
+
* The only standard we have is DOM Level 2 HTML https://www.w3.org/TR/DOM-Level-2-HTML/html.html,
|
|
10022
|
+
* according to which the only elements that have a `focus()` method are:
|
|
10023
|
+
* - HTMLInputElement
|
|
10024
|
+
* - HTMLSelectElement
|
|
10025
|
+
* - HTMLTextAreaElement
|
|
10026
|
+
* - HTMLAnchorElement
|
|
10027
|
+
*
|
|
10028
|
+
* This notably omits HTMLButtonElement and HTMLAreaElement.
|
|
10029
|
+
* Referring to these tests with tabbables in different browsers
|
|
10030
|
+
* http://allyjs.io/data-tables/focusable.html
|
|
10031
|
+
*
|
|
10032
|
+
* @param {HTMLElement} element
|
|
10033
|
+
* @return {boolean}
|
|
10034
|
+
*/
|
|
10035
|
+
function isElementFocusable(element) {
|
|
10036
|
+
// The element cannot be focused if its `tabindex` attribute is set to `-1`.
|
|
10037
|
+
if (element.matches('[tabindex="-1"]')) {
|
|
10038
|
+
return false;
|
|
10039
|
+
}
|
|
10040
|
+
|
|
10041
|
+
// Elements that cannot be focused if they have a `disabled` attribute.
|
|
10042
|
+
if (element.matches('input, select, textarea, button, object')) {
|
|
10043
|
+
return element.matches(':not([disabled])');
|
|
10044
|
+
}
|
|
10045
|
+
|
|
10046
|
+
// Elements that can be focused even if they have a `disabled` attribute.
|
|
10047
|
+
return element.matches('a[href], area[href], iframe, [tabindex], [contentEditable]');
|
|
10048
|
+
}
|
|
10049
|
+
|
|
10050
|
+
/**
|
|
10051
|
+
* Returns true if the element is focused, false otherwise.
|
|
10052
|
+
*
|
|
10053
|
+
* @param {HTMLElement} element
|
|
10054
|
+
* @return {boolean}
|
|
10055
|
+
*/
|
|
10056
|
+
function isElementFocused(element) {
|
|
10057
|
+
return element.getRootNode().activeElement === element;
|
|
10058
|
+
}
|
|
10059
|
+
|
|
10060
|
+
/**
|
|
10061
|
+
* Returns the normalized element tabindex. If not focusable, returns -1.
|
|
10062
|
+
* It checks for the attribute "tabindex" instead of the element property
|
|
10063
|
+
* `tabIndex` since browsers assign different values to it.
|
|
10064
|
+
* e.g. in Firefox `<div contenteditable>` has `tabIndex = -1`
|
|
10065
|
+
*
|
|
10066
|
+
* @param {HTMLElement} element
|
|
10067
|
+
* @return {number}
|
|
10068
|
+
*/
|
|
10069
|
+
function normalizeTabIndex(element) {
|
|
10070
|
+
if (!isElementFocusable(element)) {
|
|
10071
|
+
return -1;
|
|
10072
|
+
}
|
|
10073
|
+
|
|
10074
|
+
const tabIndex = element.getAttribute('tabindex') || 0;
|
|
10075
|
+
return Number(tabIndex);
|
|
10076
|
+
}
|
|
10077
|
+
|
|
10078
|
+
/**
|
|
10079
|
+
* Searches for nodes that are tabbable and adds them to the `result` array.
|
|
10080
|
+
* Returns if the `result` array needs to be sorted by tabindex.
|
|
10081
|
+
*
|
|
10082
|
+
* @param {Node} node The starting point for the search; added to `result` if tabbable.
|
|
10083
|
+
* @param {HTMLElement[]} result
|
|
10084
|
+
* @return {boolean}
|
|
10085
|
+
* @private
|
|
10086
|
+
*/
|
|
10087
|
+
function collectFocusableNodes(node, result) {
|
|
10088
|
+
if (node.nodeType !== Node.ELEMENT_NODE || isElementHiddenDirectly(node)) {
|
|
10089
|
+
// Don't traverse children if the node is not an HTML element or not visible.
|
|
10090
|
+
return false;
|
|
10091
|
+
}
|
|
10092
|
+
|
|
10093
|
+
const element = /** @type {HTMLElement} */ (node);
|
|
10094
|
+
const tabIndex = normalizeTabIndex(element);
|
|
10095
|
+
let needsSort = tabIndex > 0;
|
|
10096
|
+
if (tabIndex >= 0) {
|
|
10097
|
+
result.push(element);
|
|
10098
|
+
}
|
|
9066
10099
|
|
|
9067
|
-
|
|
9068
|
-
|
|
9069
|
-
|
|
9070
|
-
|
|
9071
|
-
|
|
10100
|
+
let children = [];
|
|
10101
|
+
if (element.localName === 'slot') {
|
|
10102
|
+
children = element.assignedNodes({ flatten: true });
|
|
10103
|
+
} else {
|
|
10104
|
+
// Use shadow root if possible, will check for distributed nodes.
|
|
10105
|
+
children = (element.shadowRoot || element).children;
|
|
10106
|
+
}
|
|
10107
|
+
[...children].forEach((child) => {
|
|
10108
|
+
// Ensure method is always invoked to collect focusable children.
|
|
10109
|
+
needsSort = collectFocusableNodes(child, result) || needsSort;
|
|
10110
|
+
});
|
|
10111
|
+
return needsSort;
|
|
10112
|
+
}
|
|
9072
10113
|
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9078
|
-
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
)
|
|
10114
|
+
/**
|
|
10115
|
+
* Returns a tab-ordered array of focusable elements for a root element.
|
|
10116
|
+
* The resulting array will include the root element if it is focusable.
|
|
10117
|
+
*
|
|
10118
|
+
* The method traverses nodes in shadow DOM trees too if any.
|
|
10119
|
+
*
|
|
10120
|
+
* @param {HTMLElement} element
|
|
10121
|
+
* @return {HTMLElement[]}
|
|
10122
|
+
*/
|
|
10123
|
+
function getFocusableElements(element) {
|
|
10124
|
+
const focusableElements = [];
|
|
10125
|
+
const needsSortByTabIndex = collectFocusableNodes(element, focusableElements);
|
|
10126
|
+
// If there is at least one element with tabindex > 0,
|
|
10127
|
+
// we need to sort the final array by tabindex.
|
|
10128
|
+
if (needsSortByTabIndex) {
|
|
10129
|
+
return sortElementsByTabIndex(focusableElements);
|
|
10130
|
+
}
|
|
10131
|
+
return focusableElements;
|
|
10132
|
+
}
|
|
9083
10133
|
|
|
9084
10134
|
/**
|
|
9085
10135
|
* @license
|
|
@@ -9088,123 +10138,168 @@ const DelegateFocusMixin = dedupingMixin(
|
|
|
9088
10138
|
*/
|
|
9089
10139
|
|
|
9090
10140
|
/**
|
|
9091
|
-
* A mixin to
|
|
10141
|
+
* A mixin to handle `focused` and `focus-ring` attributes based on focus.
|
|
9092
10142
|
*
|
|
9093
10143
|
* @polymerMixin
|
|
9094
10144
|
*/
|
|
9095
|
-
const
|
|
10145
|
+
const FocusMixin = dedupingMixin(
|
|
9096
10146
|
(superclass) =>
|
|
9097
|
-
class
|
|
9098
|
-
static get properties() {
|
|
9099
|
-
return {
|
|
9100
|
-
/**
|
|
9101
|
-
* A target element to which attributes and properties are delegated.
|
|
9102
|
-
* @protected
|
|
9103
|
-
*/
|
|
9104
|
-
stateTarget: {
|
|
9105
|
-
type: Object,
|
|
9106
|
-
observer: '_stateTargetChanged',
|
|
9107
|
-
},
|
|
9108
|
-
};
|
|
9109
|
-
}
|
|
9110
|
-
|
|
9111
|
-
/**
|
|
9112
|
-
* An array of the host attributes to delegate to the target element.
|
|
9113
|
-
*/
|
|
9114
|
-
static get delegateAttrs() {
|
|
9115
|
-
return [];
|
|
9116
|
-
}
|
|
9117
|
-
|
|
10147
|
+
class FocusMixinClass extends superclass {
|
|
9118
10148
|
/**
|
|
9119
|
-
*
|
|
10149
|
+
* @protected
|
|
10150
|
+
* @return {boolean}
|
|
9120
10151
|
*/
|
|
9121
|
-
|
|
9122
|
-
return
|
|
10152
|
+
get _keyboardActive() {
|
|
10153
|
+
return isKeyboardActive();
|
|
9123
10154
|
}
|
|
9124
10155
|
|
|
9125
10156
|
/** @protected */
|
|
9126
10157
|
ready() {
|
|
9127
|
-
|
|
10158
|
+
this.addEventListener('focusin', (e) => {
|
|
10159
|
+
if (this._shouldSetFocus(e)) {
|
|
10160
|
+
this._setFocused(true);
|
|
10161
|
+
}
|
|
10162
|
+
});
|
|
9128
10163
|
|
|
9129
|
-
this.
|
|
9130
|
-
|
|
10164
|
+
this.addEventListener('focusout', (e) => {
|
|
10165
|
+
if (this._shouldRemoveFocus(e)) {
|
|
10166
|
+
this._setFocused(false);
|
|
10167
|
+
}
|
|
10168
|
+
});
|
|
10169
|
+
|
|
10170
|
+
// In super.ready() other 'focusin' and 'focusout' listeners might be
|
|
10171
|
+
// added, so we call it after our own ones to ensure they execute first.
|
|
10172
|
+
// Issue to watch out: when incorrect, <vaadin-combo-box> refocuses the
|
|
10173
|
+
// input field on iOS after "Done" is pressed.
|
|
10174
|
+
super.ready();
|
|
9131
10175
|
}
|
|
9132
10176
|
|
|
9133
10177
|
/** @protected */
|
|
9134
|
-
|
|
9135
|
-
|
|
9136
|
-
|
|
9137
|
-
|
|
10178
|
+
disconnectedCallback() {
|
|
10179
|
+
super.disconnectedCallback();
|
|
10180
|
+
|
|
10181
|
+
// In non-Chrome browsers, blur does not fire on the element when it is disconnected.
|
|
10182
|
+
// reproducible in `<vaadin-date-picker>` when closing on `Cancel` or `Today` click.
|
|
10183
|
+
if (this.hasAttribute('focused')) {
|
|
10184
|
+
this._setFocused(false);
|
|
9138
10185
|
}
|
|
9139
10186
|
}
|
|
9140
10187
|
|
|
9141
|
-
/**
|
|
9142
|
-
|
|
9143
|
-
|
|
9144
|
-
|
|
10188
|
+
/**
|
|
10189
|
+
* Override to change how focused and focus-ring attributes are set.
|
|
10190
|
+
*
|
|
10191
|
+
* @param {boolean} focused
|
|
10192
|
+
* @protected
|
|
10193
|
+
*/
|
|
10194
|
+
_setFocused(focused) {
|
|
10195
|
+
this.toggleAttribute('focused', focused);
|
|
9145
10196
|
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
this.
|
|
10197
|
+
// Focus-ring is true when the element was focused from the keyboard.
|
|
10198
|
+
// Focus Ring [A11ycasts]: https://youtu.be/ilj2P5-5CjI
|
|
10199
|
+
this.toggleAttribute('focus-ring', focused && this._keyboardActive);
|
|
9149
10200
|
}
|
|
9150
10201
|
|
|
9151
|
-
/**
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
10202
|
+
/**
|
|
10203
|
+
* Override to define if the field receives focus based on the event.
|
|
10204
|
+
*
|
|
10205
|
+
* @param {FocusEvent} _event
|
|
10206
|
+
* @return {boolean}
|
|
10207
|
+
* @protected
|
|
10208
|
+
*/
|
|
10209
|
+
_shouldSetFocus(_event) {
|
|
10210
|
+
return true;
|
|
9156
10211
|
}
|
|
9157
10212
|
|
|
9158
|
-
/**
|
|
9159
|
-
|
|
9160
|
-
|
|
9161
|
-
|
|
9162
|
-
|
|
10213
|
+
/**
|
|
10214
|
+
* Override to define if the field loses focus based on the event.
|
|
10215
|
+
*
|
|
10216
|
+
* @param {FocusEvent} _event
|
|
10217
|
+
* @return {boolean}
|
|
10218
|
+
* @protected
|
|
10219
|
+
*/
|
|
10220
|
+
_shouldRemoveFocus(_event) {
|
|
10221
|
+
return true;
|
|
9163
10222
|
}
|
|
10223
|
+
},
|
|
10224
|
+
);
|
|
9164
10225
|
|
|
9165
|
-
|
|
9166
|
-
|
|
9167
|
-
|
|
9168
|
-
|
|
9169
|
-
|
|
9170
|
-
}
|
|
10226
|
+
/**
|
|
10227
|
+
* @license
|
|
10228
|
+
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
10229
|
+
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
10230
|
+
*/
|
|
9171
10231
|
|
|
9172
|
-
|
|
9173
|
-
|
|
9174
|
-
|
|
9175
|
-
|
|
9176
|
-
|
|
9177
|
-
|
|
10232
|
+
/**
|
|
10233
|
+
* A mixin to toggle the `tabindex` attribute.
|
|
10234
|
+
*
|
|
10235
|
+
* The attribute is set to -1 whenever the user disables the element
|
|
10236
|
+
* and restored with the last known value once the element is enabled.
|
|
10237
|
+
*
|
|
10238
|
+
* @polymerMixin
|
|
10239
|
+
* @mixes DisabledMixin
|
|
10240
|
+
*/
|
|
10241
|
+
const TabindexMixin = (superclass) =>
|
|
10242
|
+
class TabindexMixinClass extends DisabledMixin(superclass) {
|
|
10243
|
+
static get properties() {
|
|
10244
|
+
return {
|
|
10245
|
+
/**
|
|
10246
|
+
* Indicates whether the element can be focused and where it participates in sequential keyboard navigation.
|
|
10247
|
+
*
|
|
10248
|
+
* @protected
|
|
10249
|
+
*/
|
|
10250
|
+
tabindex: {
|
|
10251
|
+
type: Number,
|
|
10252
|
+
reflectToAttribute: true,
|
|
10253
|
+
observer: '_tabindexChanged',
|
|
10254
|
+
},
|
|
9178
10255
|
|
|
9179
|
-
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
10256
|
+
/**
|
|
10257
|
+
* Stores the last known tabindex since the element has been disabled.
|
|
10258
|
+
*
|
|
10259
|
+
* @protected
|
|
10260
|
+
*/
|
|
10261
|
+
_lastTabIndex: {
|
|
10262
|
+
type: Number,
|
|
10263
|
+
},
|
|
10264
|
+
};
|
|
10265
|
+
}
|
|
9184
10266
|
|
|
9185
|
-
|
|
9186
|
-
|
|
9187
|
-
|
|
10267
|
+
/**
|
|
10268
|
+
* When the element gets disabled, the observer saves the last known tabindex
|
|
10269
|
+
* and makes the element not focusable by setting tabindex to -1.
|
|
10270
|
+
* As soon as the element gets enabled, the observer restores the last known tabindex
|
|
10271
|
+
* so that the element can be focusable again.
|
|
10272
|
+
*
|
|
10273
|
+
* @protected
|
|
10274
|
+
* @override
|
|
10275
|
+
*/
|
|
10276
|
+
_disabledChanged(disabled, oldDisabled) {
|
|
10277
|
+
super._disabledChanged(disabled, oldDisabled);
|
|
9188
10278
|
|
|
9189
|
-
|
|
9190
|
-
|
|
9191
|
-
|
|
9192
|
-
this.stateTarget.setAttribute(name, value);
|
|
9193
|
-
} else {
|
|
9194
|
-
this.stateTarget.removeAttribute(name);
|
|
10279
|
+
if (disabled) {
|
|
10280
|
+
if (this.tabindex !== undefined) {
|
|
10281
|
+
this._lastTabIndex = this.tabindex;
|
|
9195
10282
|
}
|
|
10283
|
+
this.tabindex = -1;
|
|
10284
|
+
} else if (oldDisabled) {
|
|
10285
|
+
this.tabindex = this._lastTabIndex;
|
|
9196
10286
|
}
|
|
10287
|
+
}
|
|
9197
10288
|
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9201
|
-
|
|
9202
|
-
|
|
9203
|
-
|
|
9204
|
-
|
|
10289
|
+
/**
|
|
10290
|
+
* When the user has changed tabindex while the element is disabled,
|
|
10291
|
+
* the observer reverts tabindex to -1 and rather saves the new tabindex value to apply it later.
|
|
10292
|
+
* The new value will be applied as soon as the element becomes enabled.
|
|
10293
|
+
*
|
|
10294
|
+
* @protected
|
|
10295
|
+
*/
|
|
10296
|
+
_tabindexChanged(tabindex) {
|
|
10297
|
+
if (this.disabled && tabindex !== -1) {
|
|
10298
|
+
this._lastTabIndex = tabindex;
|
|
10299
|
+
this.tabindex = -1;
|
|
9205
10300
|
}
|
|
9206
|
-
}
|
|
9207
|
-
|
|
10301
|
+
}
|
|
10302
|
+
};
|
|
9208
10303
|
|
|
9209
10304
|
/**
|
|
9210
10305
|
* @license
|
|
@@ -9213,63 +10308,52 @@ const DelegateStateMixin = dedupingMixin(
|
|
|
9213
10308
|
*/
|
|
9214
10309
|
|
|
9215
10310
|
/**
|
|
9216
|
-
* A mixin to
|
|
9217
|
-
* and add input and change event listeners to it.
|
|
10311
|
+
* A mixin to forward focus to an element in the light DOM.
|
|
9218
10312
|
*
|
|
9219
10313
|
* @polymerMixin
|
|
10314
|
+
* @mixes FocusMixin
|
|
10315
|
+
* @mixes TabindexMixin
|
|
9220
10316
|
*/
|
|
9221
|
-
const
|
|
10317
|
+
const DelegateFocusMixin = dedupingMixin(
|
|
9222
10318
|
(superclass) =>
|
|
9223
|
-
class
|
|
10319
|
+
class DelegateFocusMixinClass extends FocusMixin(TabindexMixin(superclass)) {
|
|
9224
10320
|
static get properties() {
|
|
9225
10321
|
return {
|
|
9226
10322
|
/**
|
|
9227
|
-
*
|
|
10323
|
+
* Specify that this control should have input focus when the page loads.
|
|
10324
|
+
*/
|
|
10325
|
+
autofocus: {
|
|
10326
|
+
type: Boolean,
|
|
10327
|
+
},
|
|
10328
|
+
|
|
10329
|
+
/**
|
|
10330
|
+
* A reference to the focusable element controlled by the mixin.
|
|
10331
|
+
* It can be an input, textarea, button or any element with tabindex > -1.
|
|
10332
|
+
*
|
|
9228
10333
|
* Any component implementing this mixin is expected to provide it
|
|
9229
|
-
* by using `this.
|
|
10334
|
+
* by using `this._setFocusElement(input)` Polymer API.
|
|
9230
10335
|
*
|
|
9231
|
-
*
|
|
9232
|
-
* However, the input element does not have to always be native <input>:
|
|
9233
|
-
* as an example, <vaadin-combo-box-light> accepts other components.
|
|
10336
|
+
* Toggling `tabindex` attribute on the host element propagates its value to `focusElement`.
|
|
9234
10337
|
*
|
|
9235
10338
|
* @protected
|
|
9236
10339
|
* @type {!HTMLElement}
|
|
9237
10340
|
*/
|
|
9238
|
-
|
|
10341
|
+
focusElement: {
|
|
9239
10342
|
type: Object,
|
|
9240
10343
|
readOnly: true,
|
|
9241
|
-
observer: '
|
|
9242
|
-
},
|
|
9243
|
-
|
|
9244
|
-
/**
|
|
9245
|
-
* String used to define input type.
|
|
9246
|
-
* @protected
|
|
9247
|
-
*/
|
|
9248
|
-
type: {
|
|
9249
|
-
type: String,
|
|
9250
|
-
readOnly: true,
|
|
9251
|
-
},
|
|
9252
|
-
|
|
9253
|
-
/**
|
|
9254
|
-
* The value of the field.
|
|
9255
|
-
*/
|
|
9256
|
-
value: {
|
|
9257
|
-
type: String,
|
|
9258
|
-
value: '',
|
|
9259
|
-
observer: '_valueChanged',
|
|
9260
|
-
notify: true,
|
|
9261
|
-
sync: true,
|
|
10344
|
+
observer: '_focusElementChanged',
|
|
9262
10345
|
},
|
|
9263
10346
|
|
|
9264
10347
|
/**
|
|
9265
|
-
*
|
|
10348
|
+
* Override the property from `TabIndexMixin`
|
|
10349
|
+
* to ensure the `tabindex` attribute of the focus element
|
|
10350
|
+
* will be restored to `0` after re-enabling the element.
|
|
9266
10351
|
*
|
|
9267
10352
|
* @protected
|
|
10353
|
+
* @override
|
|
9268
10354
|
*/
|
|
9269
|
-
|
|
9270
|
-
|
|
9271
|
-
value: false,
|
|
9272
|
-
observer: '_hasInputValueChanged',
|
|
10355
|
+
_lastTabIndex: {
|
|
10356
|
+
value: 0,
|
|
9273
10357
|
},
|
|
9274
10358
|
};
|
|
9275
10359
|
}
|
|
@@ -9277,212 +10361,173 @@ const InputMixin = dedupingMixin(
|
|
|
9277
10361
|
constructor() {
|
|
9278
10362
|
super();
|
|
9279
10363
|
|
|
9280
|
-
this.
|
|
9281
|
-
this.
|
|
10364
|
+
this._boundOnBlur = this._onBlur.bind(this);
|
|
10365
|
+
this._boundOnFocus = this._onFocus.bind(this);
|
|
9282
10366
|
}
|
|
9283
10367
|
|
|
9284
|
-
/**
|
|
9285
|
-
|
|
9286
|
-
|
|
9287
|
-
|
|
9288
|
-
|
|
9289
|
-
|
|
9290
|
-
|
|
9291
|
-
|
|
10368
|
+
/** @protected */
|
|
10369
|
+
ready() {
|
|
10370
|
+
super.ready();
|
|
10371
|
+
|
|
10372
|
+
if (this.autofocus && !this.disabled) {
|
|
10373
|
+
requestAnimationFrame(() => {
|
|
10374
|
+
this.focus();
|
|
10375
|
+
this.setAttribute('focus-ring', '');
|
|
10376
|
+
});
|
|
10377
|
+
}
|
|
9292
10378
|
}
|
|
9293
10379
|
|
|
9294
10380
|
/**
|
|
9295
|
-
* A property for accessing the input element's value.
|
|
9296
|
-
*
|
|
9297
|
-
* Override this getter if the property is different from the default `value` one.
|
|
9298
|
-
*
|
|
9299
10381
|
* @protected
|
|
9300
|
-
* @
|
|
10382
|
+
* @override
|
|
9301
10383
|
*/
|
|
9302
|
-
|
|
9303
|
-
|
|
10384
|
+
focus() {
|
|
10385
|
+
if (this.focusElement && !this.disabled) {
|
|
10386
|
+
this.focusElement.focus();
|
|
10387
|
+
}
|
|
9304
10388
|
}
|
|
9305
10389
|
|
|
9306
10390
|
/**
|
|
9307
|
-
* The input element's value.
|
|
9308
|
-
*
|
|
9309
10391
|
* @protected
|
|
9310
|
-
* @
|
|
10392
|
+
* @override
|
|
9311
10393
|
*/
|
|
9312
|
-
|
|
9313
|
-
|
|
10394
|
+
blur() {
|
|
10395
|
+
if (this.focusElement) {
|
|
10396
|
+
this.focusElement.blur();
|
|
10397
|
+
}
|
|
9314
10398
|
}
|
|
9315
10399
|
|
|
9316
10400
|
/**
|
|
9317
|
-
* The input element's value.
|
|
9318
|
-
*
|
|
9319
10401
|
* @protected
|
|
10402
|
+
* @override
|
|
9320
10403
|
*/
|
|
9321
|
-
|
|
9322
|
-
if (this.
|
|
9323
|
-
this.
|
|
10404
|
+
click() {
|
|
10405
|
+
if (this.focusElement && !this.disabled) {
|
|
10406
|
+
this.focusElement.click();
|
|
9324
10407
|
}
|
|
9325
10408
|
}
|
|
9326
10409
|
|
|
9327
|
-
/**
|
|
9328
|
-
|
|
9329
|
-
|
|
9330
|
-
|
|
9331
|
-
|
|
9332
|
-
|
|
9333
|
-
|
|
9334
|
-
|
|
9335
|
-
|
|
9336
|
-
// Otherwise, when using Lit, the old value would be restored.
|
|
9337
|
-
this._inputElementValue = '';
|
|
10410
|
+
/** @protected */
|
|
10411
|
+
_focusElementChanged(element, oldElement) {
|
|
10412
|
+
if (element) {
|
|
10413
|
+
element.disabled = this.disabled;
|
|
10414
|
+
this._addFocusListeners(element);
|
|
10415
|
+
this.__forwardTabIndex(this.tabindex);
|
|
10416
|
+
} else if (oldElement) {
|
|
10417
|
+
this._removeFocusListeners(oldElement);
|
|
10418
|
+
}
|
|
9338
10419
|
}
|
|
9339
10420
|
|
|
9340
10421
|
/**
|
|
9341
|
-
*
|
|
9342
|
-
* Override this method to add custom listeners.
|
|
9343
|
-
* @param {!HTMLElement} input
|
|
10422
|
+
* @param {HTMLElement} element
|
|
9344
10423
|
* @protected
|
|
9345
10424
|
*/
|
|
9346
|
-
|
|
9347
|
-
|
|
9348
|
-
|
|
10425
|
+
_addFocusListeners(element) {
|
|
10426
|
+
element.addEventListener('blur', this._boundOnBlur);
|
|
10427
|
+
element.addEventListener('focus', this._boundOnFocus);
|
|
9349
10428
|
}
|
|
9350
10429
|
|
|
9351
10430
|
/**
|
|
9352
|
-
*
|
|
9353
|
-
* @param {!HTMLElement} input
|
|
10431
|
+
* @param {HTMLElement} element
|
|
9354
10432
|
* @protected
|
|
9355
10433
|
*/
|
|
9356
|
-
|
|
9357
|
-
|
|
9358
|
-
|
|
10434
|
+
_removeFocusListeners(element) {
|
|
10435
|
+
element.removeEventListener('blur', this._boundOnBlur);
|
|
10436
|
+
element.removeEventListener('focus', this._boundOnFocus);
|
|
9359
10437
|
}
|
|
9360
10438
|
|
|
9361
10439
|
/**
|
|
9362
|
-
*
|
|
9363
|
-
*
|
|
9364
|
-
*
|
|
9365
|
-
*
|
|
9366
|
-
* @param {string} value
|
|
10440
|
+
* Focus event does not bubble, so we dispatch it manually
|
|
10441
|
+
* on the host element to support adding focus listeners
|
|
10442
|
+
* when the focusable element is placed in light DOM.
|
|
10443
|
+
* @param {FocusEvent} event
|
|
9367
10444
|
* @protected
|
|
9368
10445
|
*/
|
|
9369
|
-
|
|
9370
|
-
|
|
9371
|
-
|
|
9372
|
-
// implements this mixin, for example in `connectedCallback`.
|
|
9373
|
-
if (!this.inputElement) {
|
|
9374
|
-
return;
|
|
9375
|
-
}
|
|
9376
|
-
|
|
9377
|
-
this._inputElementValue = value != null ? value : '';
|
|
10446
|
+
_onFocus(event) {
|
|
10447
|
+
event.stopPropagation();
|
|
10448
|
+
this.dispatchEvent(new Event('focus'));
|
|
9378
10449
|
}
|
|
9379
10450
|
|
|
9380
10451
|
/**
|
|
9381
|
-
*
|
|
9382
|
-
*
|
|
10452
|
+
* Blur event does not bubble, so we dispatch it manually
|
|
10453
|
+
* on the host element to support adding blur listeners
|
|
10454
|
+
* when the focusable element is placed in light DOM.
|
|
10455
|
+
* @param {FocusEvent} event
|
|
9383
10456
|
* @protected
|
|
9384
10457
|
*/
|
|
9385
|
-
|
|
9386
|
-
|
|
9387
|
-
|
|
9388
|
-
} else if (oldInput) {
|
|
9389
|
-
this._removeInputListeners(oldInput);
|
|
9390
|
-
}
|
|
9391
|
-
}
|
|
9392
|
-
|
|
9393
|
-
/**
|
|
9394
|
-
* Observer to notify about the change of private property.
|
|
9395
|
-
*
|
|
9396
|
-
* @private
|
|
9397
|
-
*/
|
|
9398
|
-
_hasInputValueChanged(hasValue, oldHasValue) {
|
|
9399
|
-
if (hasValue || oldHasValue) {
|
|
9400
|
-
this.dispatchEvent(new CustomEvent('has-input-value-changed'));
|
|
9401
|
-
}
|
|
9402
|
-
}
|
|
9403
|
-
|
|
9404
|
-
/**
|
|
9405
|
-
* An input event listener used to update `_hasInputValue` property.
|
|
9406
|
-
* Do not override this method.
|
|
9407
|
-
*
|
|
9408
|
-
* @param {Event} event
|
|
9409
|
-
* @private
|
|
9410
|
-
*/
|
|
9411
|
-
__onInput(event) {
|
|
9412
|
-
this._setHasInputValue(event);
|
|
9413
|
-
this._onInput(event);
|
|
10458
|
+
_onBlur(event) {
|
|
10459
|
+
event.stopPropagation();
|
|
10460
|
+
this.dispatchEvent(new Event('blur'));
|
|
9414
10461
|
}
|
|
9415
10462
|
|
|
9416
10463
|
/**
|
|
9417
|
-
*
|
|
9418
|
-
*
|
|
9419
|
-
* @param {Event} event
|
|
10464
|
+
* @param {FocusEvent} event
|
|
10465
|
+
* @return {boolean}
|
|
9420
10466
|
* @protected
|
|
10467
|
+
* @override
|
|
9421
10468
|
*/
|
|
9422
|
-
|
|
9423
|
-
|
|
9424
|
-
// the actual native input element, on which the event occurred,
|
|
9425
|
-
// can be inside shadow trees.
|
|
9426
|
-
const target = event.composedPath()[0];
|
|
9427
|
-
// Ignore fake input events e.g. used by clear button.
|
|
9428
|
-
this.__userInput = event.isTrusted;
|
|
9429
|
-
this.value = target.value;
|
|
9430
|
-
this.__userInput = false;
|
|
10469
|
+
_shouldSetFocus(event) {
|
|
10470
|
+
return event.target === this.focusElement;
|
|
9431
10471
|
}
|
|
9432
10472
|
|
|
9433
10473
|
/**
|
|
9434
|
-
*
|
|
9435
|
-
*
|
|
9436
|
-
* @param {Event} _event
|
|
9437
|
-
* @protected
|
|
9438
|
-
*/
|
|
9439
|
-
_onChange(_event) {}
|
|
9440
|
-
|
|
9441
|
-
/**
|
|
9442
|
-
* Toggle the has-value attribute based on the value property.
|
|
9443
|
-
*
|
|
9444
|
-
* @param {boolean} hasValue
|
|
10474
|
+
* @param {FocusEvent} event
|
|
10475
|
+
* @return {boolean}
|
|
9445
10476
|
* @protected
|
|
10477
|
+
* @override
|
|
9446
10478
|
*/
|
|
9447
|
-
|
|
9448
|
-
this.
|
|
10479
|
+
_shouldRemoveFocus(event) {
|
|
10480
|
+
return event.target === this.focusElement;
|
|
9449
10481
|
}
|
|
9450
10482
|
|
|
9451
10483
|
/**
|
|
9452
|
-
*
|
|
9453
|
-
* @param {
|
|
9454
|
-
* @param {string | undefined} oldVal
|
|
10484
|
+
* @param {boolean} disabled
|
|
10485
|
+
* @param {boolean} oldDisabled
|
|
9455
10486
|
* @protected
|
|
10487
|
+
* @override
|
|
9456
10488
|
*/
|
|
9457
|
-
|
|
9458
|
-
|
|
10489
|
+
_disabledChanged(disabled, oldDisabled) {
|
|
10490
|
+
super._disabledChanged(disabled, oldDisabled);
|
|
9459
10491
|
|
|
9460
|
-
|
|
9461
|
-
|
|
9462
|
-
return;
|
|
10492
|
+
if (this.focusElement) {
|
|
10493
|
+
this.focusElement.disabled = disabled;
|
|
9463
10494
|
}
|
|
9464
10495
|
|
|
9465
|
-
|
|
9466
|
-
|
|
9467
|
-
return;
|
|
10496
|
+
if (disabled) {
|
|
10497
|
+
this.blur();
|
|
9468
10498
|
}
|
|
9469
|
-
|
|
9470
|
-
// Setting a value programmatically, sync it to input element.
|
|
9471
|
-
this._forwardInputValue(newVal);
|
|
9472
10499
|
}
|
|
9473
10500
|
|
|
9474
10501
|
/**
|
|
9475
|
-
*
|
|
9476
|
-
*
|
|
9477
|
-
*
|
|
10502
|
+
* Override an observer from `TabindexMixin`.
|
|
10503
|
+
* Do not call super to remove tabindex attribute
|
|
10504
|
+
* from the host after it has been forwarded.
|
|
10505
|
+
* @param {string} tabindex
|
|
9478
10506
|
* @protected
|
|
10507
|
+
* @override
|
|
9479
10508
|
*/
|
|
9480
|
-
|
|
9481
|
-
|
|
9482
|
-
|
|
9483
|
-
|
|
9484
|
-
|
|
9485
|
-
|
|
10509
|
+
_tabindexChanged(tabindex) {
|
|
10510
|
+
this.__forwardTabIndex(tabindex);
|
|
10511
|
+
}
|
|
10512
|
+
|
|
10513
|
+
/** @private */
|
|
10514
|
+
__forwardTabIndex(tabindex) {
|
|
10515
|
+
if (tabindex !== undefined && this.focusElement) {
|
|
10516
|
+
this.focusElement.tabIndex = tabindex;
|
|
10517
|
+
|
|
10518
|
+
// Preserve tabindex="-1" on the host element
|
|
10519
|
+
if (tabindex !== -1) {
|
|
10520
|
+
this.tabindex = undefined;
|
|
10521
|
+
}
|
|
10522
|
+
}
|
|
10523
|
+
|
|
10524
|
+
if (this.disabled && tabindex) {
|
|
10525
|
+
// If tabindex attribute was changed while component was disabled
|
|
10526
|
+
if (tabindex !== -1) {
|
|
10527
|
+
this._lastTabIndex = tabindex;
|
|
10528
|
+
}
|
|
10529
|
+
this.tabindex = undefined;
|
|
10530
|
+
}
|
|
9486
10531
|
}
|
|
9487
10532
|
},
|
|
9488
10533
|
);
|
|
@@ -9494,138 +10539,123 @@ const InputMixin = dedupingMixin(
|
|
|
9494
10539
|
*/
|
|
9495
10540
|
|
|
9496
10541
|
/**
|
|
9497
|
-
*
|
|
10542
|
+
* A mixin to delegate properties and attributes to a target element.
|
|
9498
10543
|
*
|
|
9499
|
-
* @
|
|
9500
|
-
* @return {boolean}
|
|
9501
|
-
*/
|
|
9502
|
-
function isEmptyTextNode(node) {
|
|
9503
|
-
return node.nodeType === Node.TEXT_NODE && node.textContent.trim() === '';
|
|
9504
|
-
}
|
|
9505
|
-
|
|
9506
|
-
/**
|
|
9507
|
-
* @license
|
|
9508
|
-
* Copyright (c) 2023 Vaadin Ltd.
|
|
9509
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
9510
|
-
*/
|
|
9511
|
-
|
|
9512
|
-
/**
|
|
9513
|
-
* A helper for observing slot changes.
|
|
10544
|
+
* @polymerMixin
|
|
9514
10545
|
*/
|
|
9515
|
-
|
|
9516
|
-
|
|
9517
|
-
|
|
9518
|
-
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9523
|
-
|
|
9524
|
-
|
|
9525
|
-
|
|
9526
|
-
|
|
9527
|
-
|
|
9528
|
-
|
|
9529
|
-
|
|
9530
|
-
this._schedule();
|
|
9531
|
-
};
|
|
10546
|
+
const DelegateStateMixin = dedupingMixin(
|
|
10547
|
+
(superclass) =>
|
|
10548
|
+
class DelegateStateMixinClass extends superclass {
|
|
10549
|
+
static get properties() {
|
|
10550
|
+
return {
|
|
10551
|
+
/**
|
|
10552
|
+
* A target element to which attributes and properties are delegated.
|
|
10553
|
+
* @protected
|
|
10554
|
+
*/
|
|
10555
|
+
stateTarget: {
|
|
10556
|
+
type: Object,
|
|
10557
|
+
observer: '_stateTargetChanged',
|
|
10558
|
+
},
|
|
10559
|
+
};
|
|
10560
|
+
}
|
|
9532
10561
|
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
10562
|
+
/**
|
|
10563
|
+
* An array of the host attributes to delegate to the target element.
|
|
10564
|
+
*/
|
|
10565
|
+
static get delegateAttrs() {
|
|
10566
|
+
return [];
|
|
10567
|
+
}
|
|
9536
10568
|
|
|
9537
|
-
|
|
9538
|
-
|
|
9539
|
-
|
|
9540
|
-
|
|
9541
|
-
|
|
9542
|
-
|
|
9543
|
-
this.slot.addEventListener('slotchange', this._boundSchedule);
|
|
9544
|
-
this._connected = true;
|
|
9545
|
-
}
|
|
10569
|
+
/**
|
|
10570
|
+
* An array of the host properties to delegate to the target element.
|
|
10571
|
+
*/
|
|
10572
|
+
static get delegateProps() {
|
|
10573
|
+
return [];
|
|
10574
|
+
}
|
|
9546
10575
|
|
|
9547
|
-
|
|
9548
|
-
|
|
9549
|
-
|
|
9550
|
-
* may be subsequently called to reactivate the observer.
|
|
9551
|
-
*/
|
|
9552
|
-
disconnect() {
|
|
9553
|
-
this.slot.removeEventListener('slotchange', this._boundSchedule);
|
|
9554
|
-
this._connected = false;
|
|
9555
|
-
}
|
|
10576
|
+
/** @protected */
|
|
10577
|
+
ready() {
|
|
10578
|
+
super.ready();
|
|
9556
10579
|
|
|
9557
|
-
|
|
9558
|
-
|
|
9559
|
-
|
|
9560
|
-
this._scheduled = true;
|
|
10580
|
+
this._createDelegateAttrsObserver();
|
|
10581
|
+
this._createDelegatePropsObserver();
|
|
10582
|
+
}
|
|
9561
10583
|
|
|
9562
|
-
|
|
9563
|
-
|
|
9564
|
-
|
|
9565
|
-
|
|
9566
|
-
|
|
10584
|
+
/** @protected */
|
|
10585
|
+
_stateTargetChanged(target) {
|
|
10586
|
+
if (target) {
|
|
10587
|
+
this._ensureAttrsDelegated();
|
|
10588
|
+
this._ensurePropsDelegated();
|
|
10589
|
+
}
|
|
10590
|
+
}
|
|
9567
10591
|
|
|
9568
|
-
|
|
9569
|
-
|
|
9570
|
-
|
|
9571
|
-
|
|
9572
|
-
if (!this._connected) {
|
|
9573
|
-
return;
|
|
9574
|
-
}
|
|
10592
|
+
/** @protected */
|
|
10593
|
+
_createDelegateAttrsObserver() {
|
|
10594
|
+
this._createMethodObserver(`_delegateAttrsChanged(${this.constructor.delegateAttrs.join(', ')})`);
|
|
10595
|
+
}
|
|
9575
10596
|
|
|
9576
|
-
|
|
10597
|
+
/** @protected */
|
|
10598
|
+
_createDelegatePropsObserver() {
|
|
10599
|
+
this._createMethodObserver(`_delegatePropsChanged(${this.constructor.delegateProps.join(', ')})`);
|
|
10600
|
+
}
|
|
9577
10601
|
|
|
9578
|
-
|
|
9579
|
-
|
|
10602
|
+
/** @protected */
|
|
10603
|
+
_ensureAttrsDelegated() {
|
|
10604
|
+
this.constructor.delegateAttrs.forEach((name) => {
|
|
10605
|
+
this._delegateAttribute(name, this[name]);
|
|
10606
|
+
});
|
|
10607
|
+
}
|
|
9580
10608
|
|
|
9581
|
-
|
|
9582
|
-
|
|
9583
|
-
|
|
10609
|
+
/** @protected */
|
|
10610
|
+
_ensurePropsDelegated() {
|
|
10611
|
+
this.constructor.delegateProps.forEach((name) => {
|
|
10612
|
+
this._delegateProperty(name, this[name]);
|
|
10613
|
+
});
|
|
10614
|
+
}
|
|
9584
10615
|
|
|
9585
|
-
|
|
9586
|
-
|
|
9587
|
-
|
|
10616
|
+
/** @protected */
|
|
10617
|
+
_delegateAttrsChanged(...values) {
|
|
10618
|
+
this.constructor.delegateAttrs.forEach((name, index) => {
|
|
10619
|
+
this._delegateAttribute(name, values[index]);
|
|
10620
|
+
});
|
|
10621
|
+
}
|
|
9588
10622
|
|
|
9589
|
-
|
|
9590
|
-
|
|
9591
|
-
|
|
10623
|
+
/** @protected */
|
|
10624
|
+
_delegatePropsChanged(...values) {
|
|
10625
|
+
this.constructor.delegateProps.forEach((name, index) => {
|
|
10626
|
+
this._delegateProperty(name, values[index]);
|
|
10627
|
+
});
|
|
10628
|
+
}
|
|
9592
10629
|
|
|
9593
|
-
|
|
9594
|
-
|
|
9595
|
-
|
|
9596
|
-
|
|
9597
|
-
removedNodes.push(node);
|
|
9598
|
-
} else if (idx !== index) {
|
|
9599
|
-
movedNodes.push(node);
|
|
10630
|
+
/** @protected */
|
|
10631
|
+
_delegateAttribute(name, value) {
|
|
10632
|
+
if (!this.stateTarget) {
|
|
10633
|
+
return;
|
|
9600
10634
|
}
|
|
9601
|
-
});
|
|
9602
|
-
}
|
|
9603
|
-
|
|
9604
|
-
if (addedNodes.length || removedNodes.length || movedNodes.length) {
|
|
9605
|
-
this.callback({ addedNodes, movedNodes, removedNodes });
|
|
9606
|
-
}
|
|
9607
10635
|
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
}
|
|
10636
|
+
if (name === 'invalid') {
|
|
10637
|
+
this._delegateAttribute('aria-invalid', value ? 'true' : false);
|
|
10638
|
+
}
|
|
9611
10639
|
|
|
9612
|
-
|
|
9613
|
-
|
|
9614
|
-
|
|
9615
|
-
|
|
9616
|
-
|
|
10640
|
+
if (typeof value === 'boolean') {
|
|
10641
|
+
this.stateTarget.toggleAttribute(name, value);
|
|
10642
|
+
} else if (value) {
|
|
10643
|
+
this.stateTarget.setAttribute(name, value);
|
|
10644
|
+
} else {
|
|
10645
|
+
this.stateTarget.removeAttribute(name);
|
|
10646
|
+
}
|
|
10647
|
+
}
|
|
9617
10648
|
|
|
9618
|
-
|
|
10649
|
+
/** @protected */
|
|
10650
|
+
_delegateProperty(name, value) {
|
|
10651
|
+
if (!this.stateTarget) {
|
|
10652
|
+
return;
|
|
10653
|
+
}
|
|
9619
10654
|
|
|
9620
|
-
|
|
9621
|
-
|
|
9622
|
-
|
|
9623
|
-
|
|
9624
|
-
*/
|
|
9625
|
-
function generateUniqueId() {
|
|
9626
|
-
// eslint-disable-next-line no-plusplus
|
|
9627
|
-
return uniqueId++;
|
|
9628
|
-
}
|
|
10655
|
+
this.stateTarget[name] = value;
|
|
10656
|
+
}
|
|
10657
|
+
},
|
|
10658
|
+
);
|
|
9629
10659
|
|
|
9630
10660
|
/**
|
|
9631
10661
|
* @license
|
|
@@ -9634,234 +10664,279 @@ function generateUniqueId() {
|
|
|
9634
10664
|
*/
|
|
9635
10665
|
|
|
9636
10666
|
/**
|
|
9637
|
-
* A
|
|
10667
|
+
* A mixin to store the reference to an input element
|
|
10668
|
+
* and add input and change event listeners to it.
|
|
10669
|
+
*
|
|
10670
|
+
* @polymerMixin
|
|
9638
10671
|
*/
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
9649
|
-
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
10672
|
+
const InputMixin = dedupingMixin(
|
|
10673
|
+
(superclass) =>
|
|
10674
|
+
class InputMixinClass extends superclass {
|
|
10675
|
+
static get properties() {
|
|
10676
|
+
return {
|
|
10677
|
+
/**
|
|
10678
|
+
* A reference to the input element controlled by the mixin.
|
|
10679
|
+
* Any component implementing this mixin is expected to provide it
|
|
10680
|
+
* by using `this._setInputElement(input)` Polymer API.
|
|
10681
|
+
*
|
|
10682
|
+
* A typical case is using `InputController` that does this automatically.
|
|
10683
|
+
* However, the input element does not have to always be native <input>:
|
|
10684
|
+
* as an example, <vaadin-combo-box-light> accepts other components.
|
|
10685
|
+
*
|
|
10686
|
+
* @protected
|
|
10687
|
+
* @type {!HTMLElement}
|
|
10688
|
+
*/
|
|
10689
|
+
inputElement: {
|
|
10690
|
+
type: Object,
|
|
10691
|
+
readOnly: true,
|
|
10692
|
+
observer: '_inputElementChanged',
|
|
10693
|
+
},
|
|
9655
10694
|
|
|
9656
|
-
|
|
10695
|
+
/**
|
|
10696
|
+
* String used to define input type.
|
|
10697
|
+
* @protected
|
|
10698
|
+
*/
|
|
10699
|
+
type: {
|
|
10700
|
+
type: String,
|
|
10701
|
+
readOnly: true,
|
|
10702
|
+
},
|
|
9657
10703
|
|
|
9658
|
-
|
|
9659
|
-
|
|
9660
|
-
|
|
9661
|
-
|
|
9662
|
-
|
|
9663
|
-
|
|
10704
|
+
/**
|
|
10705
|
+
* The value of the field.
|
|
10706
|
+
*/
|
|
10707
|
+
value: {
|
|
10708
|
+
type: String,
|
|
10709
|
+
value: '',
|
|
10710
|
+
observer: '_valueChanged',
|
|
10711
|
+
notify: true,
|
|
10712
|
+
sync: true,
|
|
10713
|
+
},
|
|
9664
10714
|
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
10715
|
+
/**
|
|
10716
|
+
* Whether the input element has a non-empty value.
|
|
10717
|
+
*
|
|
10718
|
+
* @protected
|
|
10719
|
+
*/
|
|
10720
|
+
_hasInputValue: {
|
|
10721
|
+
type: Boolean,
|
|
10722
|
+
value: false,
|
|
10723
|
+
observer: '_hasInputValueChanged',
|
|
10724
|
+
},
|
|
10725
|
+
};
|
|
10726
|
+
}
|
|
9668
10727
|
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
this.defaultId = this.constructor.generateId(host, slotName);
|
|
9672
|
-
}
|
|
9673
|
-
}
|
|
10728
|
+
constructor() {
|
|
10729
|
+
super();
|
|
9674
10730
|
|
|
9675
|
-
|
|
9676
|
-
|
|
9677
|
-
if (this.multiple) {
|
|
9678
|
-
this.initMultiple();
|
|
9679
|
-
} else {
|
|
9680
|
-
this.initSingle();
|
|
10731
|
+
this._boundOnInput = this.__onInput.bind(this);
|
|
10732
|
+
this._boundOnChange = this._onChange.bind(this);
|
|
9681
10733
|
}
|
|
9682
10734
|
|
|
9683
|
-
|
|
9684
|
-
|
|
10735
|
+
/**
|
|
10736
|
+
* Indicates whether the value is different from the default one.
|
|
10737
|
+
* Override if the `value` property has a type other than `string`.
|
|
10738
|
+
*
|
|
10739
|
+
* @protected
|
|
10740
|
+
*/
|
|
10741
|
+
get _hasValue() {
|
|
10742
|
+
return this.value != null && this.value !== '';
|
|
9685
10743
|
}
|
|
9686
10744
|
|
|
9687
|
-
|
|
9688
|
-
|
|
9689
|
-
|
|
9690
|
-
|
|
9691
|
-
|
|
9692
|
-
|
|
9693
|
-
|
|
9694
|
-
|
|
9695
|
-
|
|
9696
|
-
|
|
9697
|
-
|
|
9698
|
-
} else {
|
|
9699
|
-
this.node = node;
|
|
9700
|
-
this.initAddedNode(node);
|
|
9701
|
-
}
|
|
9702
|
-
}
|
|
10745
|
+
/**
|
|
10746
|
+
* A property for accessing the input element's value.
|
|
10747
|
+
*
|
|
10748
|
+
* Override this getter if the property is different from the default `value` one.
|
|
10749
|
+
*
|
|
10750
|
+
* @protected
|
|
10751
|
+
* @return {string}
|
|
10752
|
+
*/
|
|
10753
|
+
get _inputElementValueProperty() {
|
|
10754
|
+
return 'value';
|
|
10755
|
+
}
|
|
9703
10756
|
|
|
9704
|
-
|
|
9705
|
-
|
|
9706
|
-
|
|
10757
|
+
/**
|
|
10758
|
+
* The input element's value.
|
|
10759
|
+
*
|
|
10760
|
+
* @protected
|
|
10761
|
+
* @return {string}
|
|
10762
|
+
*/
|
|
10763
|
+
get _inputElementValue() {
|
|
10764
|
+
return this.inputElement ? this.inputElement[this._inputElementValueProperty] : undefined;
|
|
10765
|
+
}
|
|
9707
10766
|
|
|
9708
|
-
|
|
9709
|
-
|
|
9710
|
-
|
|
9711
|
-
|
|
9712
|
-
|
|
10767
|
+
/**
|
|
10768
|
+
* The input element's value.
|
|
10769
|
+
*
|
|
10770
|
+
* @protected
|
|
10771
|
+
*/
|
|
10772
|
+
set _inputElementValue(value) {
|
|
10773
|
+
if (this.inputElement) {
|
|
10774
|
+
this.inputElement[this._inputElementValueProperty] = value;
|
|
10775
|
+
}
|
|
9713
10776
|
}
|
|
9714
|
-
} else {
|
|
9715
|
-
this.nodes = children;
|
|
9716
|
-
children.forEach((node) => {
|
|
9717
|
-
this.initAddedNode(node);
|
|
9718
|
-
});
|
|
9719
|
-
}
|
|
9720
|
-
}
|
|
9721
10777
|
|
|
9722
|
-
|
|
9723
|
-
|
|
9724
|
-
|
|
9725
|
-
|
|
9726
|
-
|
|
9727
|
-
attachDefaultNode() {
|
|
9728
|
-
const { host, slotName, tagName } = this;
|
|
10778
|
+
/**
|
|
10779
|
+
* Clear the value of the field.
|
|
10780
|
+
*/
|
|
10781
|
+
clear() {
|
|
10782
|
+
this._hasInputValue = false;
|
|
9729
10783
|
|
|
9730
|
-
|
|
9731
|
-
let node = this.defaultNode;
|
|
10784
|
+
this.value = '';
|
|
9732
10785
|
|
|
9733
|
-
|
|
9734
|
-
|
|
9735
|
-
|
|
9736
|
-
if (node instanceof Element) {
|
|
9737
|
-
if (slotName !== '') {
|
|
9738
|
-
node.setAttribute('slot', slotName);
|
|
9739
|
-
}
|
|
9740
|
-
this.node = node;
|
|
9741
|
-
this.defaultNode = node;
|
|
10786
|
+
// Clear the input immediately without waiting for the observer.
|
|
10787
|
+
// Otherwise, when using Lit, the old value would be restored.
|
|
10788
|
+
this._inputElementValue = '';
|
|
9742
10789
|
}
|
|
9743
|
-
}
|
|
9744
10790
|
|
|
9745
|
-
|
|
9746
|
-
|
|
9747
|
-
|
|
10791
|
+
/**
|
|
10792
|
+
* Add event listeners to the input element instance.
|
|
10793
|
+
* Override this method to add custom listeners.
|
|
10794
|
+
* @param {!HTMLElement} input
|
|
10795
|
+
* @protected
|
|
10796
|
+
*/
|
|
10797
|
+
_addInputListeners(input) {
|
|
10798
|
+
input.addEventListener('input', this._boundOnInput);
|
|
10799
|
+
input.addEventListener('change', this._boundOnChange);
|
|
10800
|
+
}
|
|
9748
10801
|
|
|
9749
|
-
|
|
9750
|
-
|
|
10802
|
+
/**
|
|
10803
|
+
* Remove event listeners from the input element instance.
|
|
10804
|
+
* @param {!HTMLElement} input
|
|
10805
|
+
* @protected
|
|
10806
|
+
*/
|
|
10807
|
+
_removeInputListeners(input) {
|
|
10808
|
+
input.removeEventListener('input', this._boundOnInput);
|
|
10809
|
+
input.removeEventListener('change', this._boundOnChange);
|
|
10810
|
+
}
|
|
9751
10811
|
|
|
9752
|
-
|
|
9753
|
-
|
|
9754
|
-
|
|
9755
|
-
|
|
9756
|
-
|
|
9757
|
-
|
|
9758
|
-
|
|
9759
|
-
|
|
9760
|
-
|
|
9761
|
-
|
|
9762
|
-
|
|
9763
|
-
|
|
9764
|
-
|
|
9765
|
-
|
|
10812
|
+
/**
|
|
10813
|
+
* A method to forward the value property set on the field
|
|
10814
|
+
* programmatically back to the input element value.
|
|
10815
|
+
* Override this method to perform additional checks,
|
|
10816
|
+
* for example to skip this in certain conditions.
|
|
10817
|
+
* @param {string} value
|
|
10818
|
+
* @protected
|
|
10819
|
+
*/
|
|
10820
|
+
_forwardInputValue(value) {
|
|
10821
|
+
// Value might be set before an input element is initialized.
|
|
10822
|
+
// This case should be handled separately by a component that
|
|
10823
|
+
// implements this mixin, for example in `connectedCallback`.
|
|
10824
|
+
if (!this.inputElement) {
|
|
10825
|
+
return;
|
|
10826
|
+
}
|
|
9766
10827
|
|
|
9767
|
-
|
|
9768
|
-
|
|
9769
|
-
* @return {Node}
|
|
9770
|
-
*/
|
|
9771
|
-
getSlotChild() {
|
|
9772
|
-
return this.getSlotChildren()[0];
|
|
9773
|
-
}
|
|
10828
|
+
this._inputElementValue = value != null ? value : '';
|
|
10829
|
+
}
|
|
9774
10830
|
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9778
|
-
|
|
9779
|
-
|
|
9780
|
-
|
|
9781
|
-
|
|
9782
|
-
|
|
9783
|
-
|
|
9784
|
-
|
|
9785
|
-
|
|
9786
|
-
|
|
9787
|
-
}
|
|
9788
|
-
}
|
|
10831
|
+
/**
|
|
10832
|
+
* @param {HTMLElement | undefined} input
|
|
10833
|
+
* @param {HTMLElement | undefined} oldInput
|
|
10834
|
+
* @protected
|
|
10835
|
+
*/
|
|
10836
|
+
_inputElementChanged(input, oldInput) {
|
|
10837
|
+
if (input) {
|
|
10838
|
+
this._addInputListeners(input);
|
|
10839
|
+
} else if (oldInput) {
|
|
10840
|
+
this._removeInputListeners(oldInput);
|
|
10841
|
+
}
|
|
10842
|
+
}
|
|
9789
10843
|
|
|
9790
|
-
|
|
9791
|
-
|
|
9792
|
-
|
|
9793
|
-
|
|
9794
|
-
|
|
9795
|
-
|
|
9796
|
-
|
|
10844
|
+
/**
|
|
10845
|
+
* Observer to notify about the change of private property.
|
|
10846
|
+
*
|
|
10847
|
+
* @private
|
|
10848
|
+
*/
|
|
10849
|
+
_hasInputValueChanged(hasValue, oldHasValue) {
|
|
10850
|
+
if (hasValue || oldHasValue) {
|
|
10851
|
+
this.dispatchEvent(new CustomEvent('has-input-value-changed'));
|
|
10852
|
+
}
|
|
10853
|
+
}
|
|
9797
10854
|
|
|
9798
|
-
|
|
9799
|
-
|
|
9800
|
-
|
|
9801
|
-
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
10855
|
+
/**
|
|
10856
|
+
* An input event listener used to update `_hasInputValue` property.
|
|
10857
|
+
* Do not override this method.
|
|
10858
|
+
*
|
|
10859
|
+
* @param {Event} event
|
|
10860
|
+
* @private
|
|
10861
|
+
*/
|
|
10862
|
+
__onInput(event) {
|
|
10863
|
+
this._setHasInputValue(event);
|
|
10864
|
+
this._onInput(event);
|
|
10865
|
+
}
|
|
9805
10866
|
|
|
9806
|
-
|
|
9807
|
-
|
|
9808
|
-
|
|
9809
|
-
|
|
9810
|
-
|
|
9811
|
-
|
|
9812
|
-
|
|
9813
|
-
|
|
9814
|
-
|
|
9815
|
-
|
|
9816
|
-
|
|
9817
|
-
|
|
10867
|
+
/**
|
|
10868
|
+
* An input event listener used to update the field value.
|
|
10869
|
+
*
|
|
10870
|
+
* @param {Event} event
|
|
10871
|
+
* @protected
|
|
10872
|
+
*/
|
|
10873
|
+
_onInput(event) {
|
|
10874
|
+
// In the case a custom web component is passed as `inputElement`,
|
|
10875
|
+
// the actual native input element, on which the event occurred,
|
|
10876
|
+
// can be inside shadow trees.
|
|
10877
|
+
const target = event.composedPath()[0];
|
|
10878
|
+
// Ignore fake input events e.g. used by clear button.
|
|
10879
|
+
this.__userInput = event.isTrusted;
|
|
10880
|
+
this.value = target.value;
|
|
10881
|
+
this.__userInput = false;
|
|
10882
|
+
}
|
|
9818
10883
|
|
|
9819
|
-
|
|
9820
|
-
|
|
9821
|
-
|
|
9822
|
-
|
|
9823
|
-
|
|
9824
|
-
|
|
9825
|
-
|
|
9826
|
-
const slot = this.host.shadowRoot.querySelector(selector);
|
|
10884
|
+
/**
|
|
10885
|
+
* A change event listener.
|
|
10886
|
+
* Override this method with an actual implementation.
|
|
10887
|
+
* @param {Event} _event
|
|
10888
|
+
* @protected
|
|
10889
|
+
*/
|
|
10890
|
+
_onChange(_event) {}
|
|
9827
10891
|
|
|
9828
|
-
|
|
9829
|
-
|
|
10892
|
+
/**
|
|
10893
|
+
* Toggle the has-value attribute based on the value property.
|
|
10894
|
+
*
|
|
10895
|
+
* @param {boolean} hasValue
|
|
10896
|
+
* @protected
|
|
10897
|
+
*/
|
|
10898
|
+
_toggleHasValue(hasValue) {
|
|
10899
|
+
this.toggleAttribute('has-value', hasValue);
|
|
10900
|
+
}
|
|
9830
10901
|
|
|
9831
|
-
|
|
9832
|
-
|
|
9833
|
-
|
|
10902
|
+
/**
|
|
10903
|
+
* Observer called when a value property changes.
|
|
10904
|
+
* @param {string | undefined} newVal
|
|
10905
|
+
* @param {string | undefined} oldVal
|
|
10906
|
+
* @protected
|
|
10907
|
+
*/
|
|
10908
|
+
_valueChanged(newVal, oldVal) {
|
|
10909
|
+
this._toggleHasValue(this._hasValue);
|
|
9834
10910
|
|
|
9835
|
-
|
|
9836
|
-
|
|
10911
|
+
// Setting initial value to empty string, do nothing.
|
|
10912
|
+
if (newVal === '' && oldVal === undefined) {
|
|
10913
|
+
return;
|
|
10914
|
+
}
|
|
9837
10915
|
|
|
9838
|
-
|
|
9839
|
-
|
|
9840
|
-
|
|
10916
|
+
// Value is set by the user, no need to sync it back to input.
|
|
10917
|
+
if (this.__userInput) {
|
|
10918
|
+
return;
|
|
10919
|
+
}
|
|
10920
|
+
|
|
10921
|
+
// Setting a value programmatically, sync it to input element.
|
|
10922
|
+
this._forwardInputValue(newVal);
|
|
9841
10923
|
}
|
|
9842
10924
|
|
|
9843
|
-
|
|
9844
|
-
|
|
9845
|
-
|
|
9846
|
-
|
|
9847
|
-
|
|
9848
|
-
|
|
9849
|
-
|
|
9850
|
-
|
|
9851
|
-
|
|
9852
|
-
|
|
9853
|
-
|
|
9854
|
-
|
|
9855
|
-
if (this.node) {
|
|
9856
|
-
this.node.remove();
|
|
9857
|
-
}
|
|
9858
|
-
this.node = newNodes[0];
|
|
9859
|
-
this.initAddedNode(this.node);
|
|
9860
|
-
}
|
|
10925
|
+
/**
|
|
10926
|
+
* Sets the `_hasInputValue` property based on the `input` event.
|
|
10927
|
+
*
|
|
10928
|
+
* @param {InputEvent} event
|
|
10929
|
+
* @protected
|
|
10930
|
+
*/
|
|
10931
|
+
_setHasInputValue(event) {
|
|
10932
|
+
// In the case a custom web component is passed as `inputElement`,
|
|
10933
|
+
// the actual native input element, on which the event occurred,
|
|
10934
|
+
// can be inside shadow trees.
|
|
10935
|
+
const target = event.composedPath()[0];
|
|
10936
|
+
this._hasInputValue = target.value.length > 0;
|
|
9861
10937
|
}
|
|
9862
|
-
}
|
|
9863
|
-
|
|
9864
|
-
}
|
|
10938
|
+
},
|
|
10939
|
+
);
|
|
9865
10940
|
|
|
9866
10941
|
/**
|
|
9867
10942
|
* @license
|
|
@@ -10518,67 +11593,6 @@ const requiredField = i$1`
|
|
|
10518
11593
|
|
|
10519
11594
|
registerStyles('', requiredField, { moduleId: 'lumo-required-field' });
|
|
10520
11595
|
|
|
10521
|
-
/**
|
|
10522
|
-
* @license
|
|
10523
|
-
* Copyright (c) 2021 - 2023 Vaadin Ltd.
|
|
10524
|
-
* This program is available under Apache License Version 2.0, available at https://vaadin.com/license/
|
|
10525
|
-
*/
|
|
10526
|
-
|
|
10527
|
-
/**
|
|
10528
|
-
* Takes a string with values separated by space and returns a set the values
|
|
10529
|
-
*
|
|
10530
|
-
* @param {string} value
|
|
10531
|
-
* @return {Set<string>}
|
|
10532
|
-
*/
|
|
10533
|
-
function deserializeAttributeValue(value) {
|
|
10534
|
-
if (!value) {
|
|
10535
|
-
return new Set();
|
|
10536
|
-
}
|
|
10537
|
-
|
|
10538
|
-
return new Set(value.split(' '));
|
|
10539
|
-
}
|
|
10540
|
-
|
|
10541
|
-
/**
|
|
10542
|
-
* Takes a set of string values and returns a string with values separated by space
|
|
10543
|
-
*
|
|
10544
|
-
* @param {Set<string>} values
|
|
10545
|
-
* @return {string}
|
|
10546
|
-
*/
|
|
10547
|
-
function serializeAttributeValue(values) {
|
|
10548
|
-
return values ? [...values].join(' ') : '';
|
|
10549
|
-
}
|
|
10550
|
-
|
|
10551
|
-
/**
|
|
10552
|
-
* Adds a value to an attribute containing space-delimited values.
|
|
10553
|
-
*
|
|
10554
|
-
* @param {HTMLElement} element
|
|
10555
|
-
* @param {string} attr
|
|
10556
|
-
* @param {string} value
|
|
10557
|
-
*/
|
|
10558
|
-
function addValueToAttribute(element, attr, value) {
|
|
10559
|
-
const values = deserializeAttributeValue(element.getAttribute(attr));
|
|
10560
|
-
values.add(value);
|
|
10561
|
-
element.setAttribute(attr, serializeAttributeValue(values));
|
|
10562
|
-
}
|
|
10563
|
-
|
|
10564
|
-
/**
|
|
10565
|
-
* Removes a value from an attribute containing space-delimited values.
|
|
10566
|
-
* If the value is the last one, the whole attribute is removed.
|
|
10567
|
-
*
|
|
10568
|
-
* @param {HTMLElement} element
|
|
10569
|
-
* @param {string} attr
|
|
10570
|
-
* @param {string} value
|
|
10571
|
-
*/
|
|
10572
|
-
function removeValueFromAttribute(element, attr, value) {
|
|
10573
|
-
const values = deserializeAttributeValue(element.getAttribute(attr));
|
|
10574
|
-
values.delete(value);
|
|
10575
|
-
if (values.size === 0) {
|
|
10576
|
-
element.removeAttribute(attr);
|
|
10577
|
-
return;
|
|
10578
|
-
}
|
|
10579
|
-
element.setAttribute(attr, serializeAttributeValue(values));
|
|
10580
|
-
}
|
|
10581
|
-
|
|
10582
11596
|
/**
|
|
10583
11597
|
* @license
|
|
10584
11598
|
* Copyright (c) 2023 Vaadin Ltd.
|
|
@@ -11409,4 +12423,4 @@ const FieldMixin = (superclass) =>
|
|
|
11409
12423
|
}
|
|
11410
12424
|
};
|
|
11411
12425
|
|
|
11412
|
-
export {
|
|
12426
|
+
export { timeOut$1 as A, microTask$1 as B, matches as C, DelegateStateMixin as D, ElementMixin as E, FieldMixin as F, translate as G, SlotController as H, InputMixin as I, ControllerMixin as J, KeyboardMixin as K, LabelMixin as L, getDeepActiveElement as M, getFocusableElements as N, getAncestorRootNodes as O, PolymerElement as P, TabindexMixin as Q, idlePeriod as R, SlotObserver as S, TooltipController as T, animationFrame as U, ValidateMixin as V, flush as W, enqueueDebouncer as X, DisabledMixin as a, isElementFocused as b, DelegateFocusMixin as c, dedupingMixin as d, InputController as e, LabelledInputController as f, defineCustomElement as g, html as h, i$1 as i, ThemableMixin as j, requiredField as k, helper as l, FocusMixin as m, microTask as n, DirMixin as o, Debouncer as p, generateUniqueId as q, registerStyles as r, PropertyEffects as s, timeOut as t, strictTemplatePolicy as u, legacyWarnings as v, wrap as w, legacyOptimizations as x, useShadow as y, suppressTemplateNotifications as z };
|