wrec 0.4.2 → 0.4.3
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/README.md +21 -3
- package/dist/wrec.min.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -104,15 +104,21 @@ Here are the steps:
|
|
|
104
104
|
|
|
105
105
|
## More Detail
|
|
106
106
|
|
|
107
|
+
When the value of an attribute is a Boolean,
|
|
108
|
+
wrec adds the attribute to the element with no value
|
|
109
|
+
or removes the attribute from the element.
|
|
110
|
+
This is commonly used for attributes like `disabled`.
|
|
111
|
+
|
|
107
112
|
To wire event listeners,
|
|
108
113
|
Wrec looks for attributes whose name begins with "on".
|
|
109
114
|
It assumes the remainder of the attribute name is an event name.
|
|
110
115
|
It also assumes that the value of the attribute is either
|
|
111
116
|
a method name that should be called or code that should be executed
|
|
112
117
|
when that event is dispatched.
|
|
113
|
-
For example, the attribute `onclick="increment"
|
|
118
|
+
For example, with the attribute `onclick="increment"`,
|
|
119
|
+
if `increment` is a method in the component, wrec will
|
|
114
120
|
add an event listener to the element containing the attribute
|
|
115
|
-
for "click" events and
|
|
121
|
+
for "click" events and call `this.increment(event)`.
|
|
116
122
|
Alternatively, the attribute `onclick="this.count++"`
|
|
117
123
|
adds an event listener that increments `this.count`
|
|
118
124
|
when the element is clicked.
|
|
@@ -142,7 +148,19 @@ See `examples/radio-group.js` for an example of a web component
|
|
|
142
148
|
that iterates over values in a comma-delimited attribute value
|
|
143
149
|
to determine what to render.
|
|
144
150
|
|
|
145
|
-
|
|
151
|
+
Data binding in Lit is not two-way like in wrec.
|
|
152
|
+
A Lit component cannot simply pass one of its properties to
|
|
153
|
+
a child Lit component and have the child can update the property.
|
|
154
|
+
The child must dispatch custom events that
|
|
155
|
+
the parent listens for so it can update its own state.
|
|
156
|
+
For an example of this, see
|
|
157
|
+
[wrec-compare](https://github.com/mvolkmann/lit-examples/blob/main/wrec-compare/binding-demo.ts).
|
|
158
|
+
|
|
159
|
+
Wrec supports two-way data binding.
|
|
160
|
+
See the example component binding-demo
|
|
161
|
+
and the components it renders.
|
|
162
|
+
|
|
163
|
+
Wrec two-way data binding can be used with HTML form elements.
|
|
146
164
|
|
|
147
165
|
- `input` and `select` elements can have a `value` attribute
|
|
148
166
|
whose value is "this.somePropertyName".
|
package/dist/wrec.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
const FIRST_CHAR="a-zA-Z_$",OTHER_CHAR=FIRST_CHAR+"0-9",IDENTIFIER=`[${FIRST_CHAR}][${OTHER_CHAR}]*`,REFERENCE_RE=new RegExp(`^this.${IDENTIFIER}$`),REFERENCES_RE=new RegExp(`this.${IDENTIFIER}`,"g"),SKIP=5;class Wrec extends HTMLElement{static#t=document.createElement("template");#e=new Map;#s;#r;#o=new Map;constructor(){super(),this.attachShadow({mode:"open"});this.constructor["#propertyToExpressionsMap"]||(this.constructor["#propertyToExpressionsMap"]=new Map),this.constructor.formAssociated&&(this.#r=this.attachInternals(),this.#s=new FormData,this.#r.setFormValue(this.#s))}attributeChangedCallback(t,e,s){const r=this.#n(t,s);this[t]=r,this.#i(t,r)}#a(t,e,s){t.addEventListener("input",t=>{this[e]=t.target.value});let r=this.#o.get(e);r||(r=[],this.#o.set(e,r)),r.push(s?{element:t,attrName:s}:t)}buildDOM(){const t=this.constructor;let e=t.css?`<style>${t.css}</style>`:"";e+=t.html,Wrec.#t.innerHTML=e,this.shadowRoot.replaceChildren(Wrec.#t.content.cloneNode(!0))}connectedCallback(){this.#c(),this.buildDOM(),requestAnimationFrame(()=>{this.#l(this.shadowRoot),this.#h(this.shadowRoot),this.constructor.processed=!0})}#c(){const t=this.constructor.properties,{observedAttributes:e}=this.constructor;for(const[s,r]of Object.entries(t))this.#
|
|
1
|
+
const FIRST_CHAR="a-zA-Z_$",OTHER_CHAR=FIRST_CHAR+"0-9",IDENTIFIER=`[${FIRST_CHAR}][${OTHER_CHAR}]*`,REFERENCE_RE=new RegExp(`^this.${IDENTIFIER}$`),REFERENCES_RE=new RegExp(`this.${IDENTIFIER}`,"g"),SKIP=5;class Wrec extends HTMLElement{static#t=document.createElement("template");#e=new Map;#s;#r;#o=new Map;constructor(){super(),this.attachShadow({mode:"open"});this.constructor["#propertyToExpressionsMap"]||(this.constructor["#propertyToExpressionsMap"]=new Map),this.constructor.formAssociated&&(this.#r=this.attachInternals(),this.#s=new FormData,this.#r.setFormValue(this.#s))}attributeChangedCallback(t,e,s){const r=this.#n(t,s);this[t]=r,this.#i(t,r)}#a(t,e,s){t.addEventListener("input",t=>{this[e]=t.target.value});let r=this.#o.get(e);r||(r=[],this.#o.set(e,r)),r.push(s?{element:t,attrName:s}:t)}buildDOM(){const t=this.constructor;let e=t.css?`<style>${t.css}</style>`:"";e+=t.html,Wrec.#t.innerHTML=e,this.shadowRoot.replaceChildren(Wrec.#t.content.cloneNode(!0))}connectedCallback(){this.#c(),this.buildDOM(),requestAnimationFrame(()=>{this.#l(this.shadowRoot),this.#h(this.shadowRoot),this.constructor.processed=!0})}#c(){const t=this.constructor.properties,{observedAttributes:e}=this.constructor;for(const[s,r]of Object.entries(t))this.#p(s,r,e)}#p(t,e,s){const r=s.includes(t)&&this.hasAttribute(t)?this.#u(t):e.value,o="#"+t;this[o]=r,Object.defineProperty(this,t,{enumerable:!0,get(){return this[o]},set(e){if(e===this[o])return;if(this[o]=e,this.hasAttribute(t)){e!==this.#u(t)&&this.#m(this,t,e)}this.#d(t);const s=this.propertyToParentPropertyMap,r=s?s.get(t):null;if(r){this.getRootNode().host.setAttribute(r,e)}this.#i(t,e)}})}#f(t){const e=t.localName.includes("-");for(const s of t.getAttributeNames()){const r=t.getAttribute(s);if(REFERENCE_RE.test(r)){const o=r.substring(SKIP),n=this[o];if(!n){const t=this.constructor.name;throw new Error(`component ${t} missing property "${o}"`)}if(t[o]=n,"value"===s&&this.#a(t,o,s),e){let e=t.propertyToParentPropertyMap;e||(e=new Map,t.propertyToParentPropertyMap=e),e.set(s,o)}}this.#E(r,t,s)}}#b(expression){return(()=>eval(expression)).call(this)}#g(t){const{localName:e}=t;if("style"===e)return;const s=t.textContent.trim();if("textarea"===e&&REFERENCE_RE.test(s)){const e=s.substring(SKIP);this.#a(t,e),t.textContent=this[e]}else this.#E(s,t)}#u(t){return this.#n(t,this.getAttribute(t))}#n(t,e){const s=this.constructor.properties[t].type;return s===Number?Number(e):s===Boolean?Boolean(e):e}#h(t){const e=t.querySelectorAll("*");for(const t of e)this.#f(t),t.firstElementChild||this.#g(t)}static get observedAttributes(){return Object.keys(this.properties||{})}#d(t){const e=this.constructor["#propertyToExpressionsMap"].get(t)||[];for(const t of e){const e=this.#b(t),s=this.#e.get(t)||[];for(const t of s)if(t instanceof Element)this.#R(t,e);else{const{element:s,attrName:r}=t;this.#m(s,r,e)}}requestAnimationFrame(()=>{this.#A(t)})}static register(){const t=Wrec.#y(this.name);customElements.get(t)||customElements.define(t,this)}#E(t,e,s){const r=t.match(REFERENCES_RE);if(!r)return;this.constructor.processed||r.forEach(e=>{const s=e.substring(SKIP),r=this.constructor["#propertyToExpressionsMap"];let o=r.get(s);o||(o=[],r.set(s,o)),o.push(t)});let o=this.#e.get(t);o||(o=[],this.#e.set(t,o)),o.push(s?{element:e,attrName:s}:e);const n=this.#b(t);s?this.#m(e,s,n):this.#R(e,n)}static#y=t=>t.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();#i(t,e){this.#s&&(this.#s.set(t,e),this.#r.setFormValue(this.#s))}#m(t,e,s){const r=t.getAttribute(e);"boolean"==typeof s?s?r!==e&&t.setAttribute(e,e):t.removeAttribute(e):r!==s&&t.setAttribute(e,s)}#A(t){const e=this[t],s=this.#o.get(t)||[];for(const t of s)if(t instanceof Element)"textarea"===t.localName?t.value=e:t.textContent=e;else{const{element:s,attrName:r}=t;this.#m(s,r,e),s[r]=e}}#R(t,e){const{localName:s}=t;"textarea"===s?t.value=e:"string"==typeof e&&e.trim().startsWith("<")?(t.innerHTML=e,this.#l(t),this.#h(t)):t.textContent=e}#l(root){const elements=root.querySelectorAll("*");for(const element of elements)for(const attr of element.attributes){const{name:name}=attr;if(name.startsWith("on")){const eventName=name.slice(2).toLowerCase(),{value:value}=attr,fn="function"==typeof this[value]?t=>this[value](t):()=>eval(value);element.addEventListener(eventName,fn),element.removeAttribute(name)}}}}export default Wrec;export const css=String.raw;export const html=String.raw;
|