wrec 0.5.6 → 0.5.8

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 CHANGED
@@ -20,6 +20,8 @@ It has the following advantages over Lit:
20
20
  - Wrec enables specifying the content of a `textarea` element
21
21
  with a JavaScript expressions in its text content.
22
22
 
23
+ Wrec components have many of the features provided by Alpine.js.
24
+
23
25
  ## Getting Started
24
26
 
25
27
  Let's use wrec to implement a counter component.
@@ -104,6 +106,12 @@ Here are the steps:
104
106
 
105
107
  1. Click the "-" and "+" buttons to verify that the component is working.
106
108
 
109
+ ## Required Attributes
110
+
111
+ The configuration object for required attributes in a Wrec component
112
+ should contain `required: true`.
113
+ For an example of this, see the `name` property in `examples/radio-group.js`.
114
+
107
115
  ## Boolean Attributes
108
116
 
109
117
  When the value of an attribute is a Boolean,
@@ -132,6 +140,15 @@ does not matter because Wrec lowercases the name.
132
140
  So the attributes in the previous examples
133
141
  can be replaced by `onClick="increment"`.
134
142
 
143
+ ## Property Change Events
144
+
145
+ Wrec components will dispatch change events whenever
146
+ a property configured with `dispatch: true` changes.
147
+ For an example of this,
148
+ see the `checked` property in `examples/toggle-switch.js`.
149
+ The component defined in `examples/binding-demo.js`
150
+ listens for that event, as does the `script` in `examples/index.html`.
151
+
135
152
  ## Reactivity
136
153
 
137
154
  Wrec supports reactivity.
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{#t=new Map;#e;#s;#r=new Map;constructor(){super(),this.attachShadow({mode:"open"});this.constructor["#propertyToExpressionsMap"]||(this.constructor["#propertyToExpressionsMap"]=new Map),this.constructor.formAssociated&&(this.#s=this.attachInternals(),this.#e=new FormData,this.#s.setFormValue(this.#e))}attributeChangedCallback(t,e,s){const r=this.#o(t,s);this[t]=r,this.#i(t,r)}#n(t,e,s){t.addEventListener("input",t=>{this[e]=t.target.value});let r=this.#r.get(e);r||(r=[],this.#r.set(e,r)),r.push(s?{element:t,attrName:s}:t)}#a(){const t=this.constructor;let{_template:e}=t;if(!e){e=t.template=document.createElement("template");let s=t.css?`<style>${t.css}</style>`:"";s+=t.html,e.innerHTML=s}this.shadowRoot.replaceChildren(e.content.cloneNode(!0))}connectedCallback(){this.#h(),this.#l(),this.#a(),requestAnimationFrame(()=>{this.#c(this.shadowRoot),this.#u(this.shadowRoot),this.constructor.processed=!0})}#l(){const{observedAttributes:t,properties:e}=this.constructor;for(const[s,r]of Object.entries(e))this.#p(s,r,t)}#p(t,e,s){const r=s.includes(t)&&this.hasAttribute(t)?this.#m(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.#m(t)&&this.#d(this,t,e)}this.#f(t);const s=this.propertyToParentPropertyMap,r=s?s.get(t):null;if(r){this.getRootNode().host.setAttribute(r,e)}this.#i(t,e)}})}static elementName(){return this.name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}#b(t){const e=t.localName.includes("-");for(const s of t.getAttributeNames()){const r=t.getAttribute(s),o=this.#E(t,r);if(o){const r=this[o];if(void 0===r&&this.#R(t,s,o),t[o]=r,"value"===s&&this.#n(t,o,s),e){let e=t.propertyToParentPropertyMap;e||(e=new Map,t.propertyToParentPropertyMap=e),e.set(s,o)}}this.#v(r,t,s)}}#g(expression){return(()=>eval(expression)).call(this)}#N(t){const{localName:e}=t;if("style"===e)return;const s=t.textContent.trim(),r=this.#E(t,s);"textarea"===e&&r?(this.#n(t,r),t.textContent=this[r]):this.#v(s,t)}#u(t){const e=t.querySelectorAll("*");for(const t of e)this.#b(t),t.firstElementChild||this.#N(t)}static get observedAttributes(){return Object.keys(this.properties||{})}#E(t,e){if(!REFERENCE_RE.test(e))return;const s=e.substring(SKIP);return void 0===this[s]&&this.#R(t,null,s),s}#f(t){const e=this.constructor["#propertyToExpressionsMap"].get(t)||[];for(const t of e){const e=this.#g(t),s=this.#t.get(t)||[];for(const t of s)if(t instanceof Element)this.#y(t,e);else{const{element:s,attrName:r}=t;this.#d(s,r,e)}}requestAnimationFrame(()=>{this.#A(t)})}static register(){const t=this.elementName();customElements.get(t)||customElements.define(t,this)}#v(t,e,s){const r=this.#w(e,s,t);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.#t.get(t);o||(o=[],this.#t.set(t,o)),o.push(s?{element:e,attrName:s}:e);const i=this.#g(t);s?this.#d(e,s,i):this.#y(e,i)}#i(t,e){this.#e&&(this.#e.set(t,e),this.#s.setFormValue(this.#e))}#x(t,e,s){throw new Error(`component ${this.constructor.elementName()}`+(t?`, element "${t.localName}"`:"")+(e?`, attribute "${e}"`:"")+` ${s}`)}#R(t,e,s){this.#x(t,e,`refers to missing property "${s}"`)}#m(t){return this.#o(t,this.getAttribute(t))}#o(t,e){if(e?.match(REFERENCES_RE))return e;const s=this.constructor.properties[t].type;if(s===Number){const s=Number(e);if(!isNaN(s))return s;this.#x(null,t,`must be a number, but was "${e}"`)}return s===Boolean?"true"===e||"false"!==e&&(e&&e!==t&&this.#x(null,t,"is a Boolean attribute, so its value must match attribute name or be missing"),e===t):e}#d(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.#r.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.#d(s,r,e),s[r]=e}}#y(t,e){const{localName:s}=t,r=typeof e;"string"!==r&&"number"!==r&&this.#x(t,null," computed content is not a string or number"),"textarea"===s?t.value=e:"string"===r&&e.trim().startsWith("<")?(t.innerHTML=e,this.#c(t),this.#u(t)):t.textContent=e}#h(){const t=new Set(Object.keys(this.constructor.properties));for(const e of this.getAttributeNames())e.startsWith("on")||t.has(e)||this.#x(null,e,"is not a supported attribute")}#w(t,e,s){const r=s.match(REFERENCES_RE);if(r)return r.forEach(s=>{const r=s.substring(SKIP);void 0===this[r]&&this.#R(t,e,r)}),r}#c(root){for(const element of root.querySelectorAll("*")){const attributesToRemove=[];for(const attr of element.attributes){const attrName=attr.name;if(attrName.startsWith("on")){const eventName=attrName.slice(2).toLowerCase(),attrValue=attr.value;let fn;this.#w(element,attrName,attrValue),"function"==typeof this[attrValue]?fn=t=>this[attrValue](t):(this.#w(element,attrName,attrValue),fn=event=>eval(attrValue)),element.addEventListener(eventName,fn),attributesToRemove.push(attrName)}}for(const t of attributesToRemove)element.removeAttribute(t)}}}export default Wrec;export const css=String.raw;export const html=String.raw;
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;function updateAttribute(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)}class Wrec extends HTMLElement{#t=new Map;#e;#s;#r=new Map;constructor(){super(),this.attachShadow({mode:"open"});this.constructor["#propertyToExpressionsMap"]||(this.constructor["#propertyToExpressionsMap"]=new Map),this.constructor.formAssociated&&(this.#s=this.attachInternals(),this.#e=new FormData,this.#s.setFormValue(this.#e))}attributeChangedCallback(t,e,s){const r=this.#i(t,s);this[t]=r,this.#o(t,r)}#n(t,e,s){t.addEventListener("input",t=>{this[e]=t.target.value});let r=this.#r.get(e);r||(r=[],this.#r.set(e,r)),r.push(s?{element:t,attrName:s}:t)}#a(){const t=this.constructor;let{_template:e}=t;if(!e){e=t.template=document.createElement("template");let s=t.css?`<style>${t.css}</style>`:"";s+=t.html,e.innerHTML=s}this.shadowRoot.replaceChildren(e.content.cloneNode(!0))}connectedCallback(){this.#h(),this.#u(),this.#a(),requestAnimationFrame(()=>{this.#c(this.shadowRoot),this.#l(this.shadowRoot),this.constructor.processed=!0})}#u(){const{observedAttributes:t,properties:e}=this.constructor;for(const[s,r]of Object.entries(e))this.#p(s,r,t)}#p(t,e,s){e.required&&!this.hasAttribute(t)&&this.#m(this,t,"is a required attribute");const r=s.includes(t)&&this.hasAttribute(t)?this.#d(t):e.value,i="#"+t;this[i]=r,Object.defineProperty(this,t,{enumerable:!0,get(){return this[i]},set(s){if(s===this[i])return;if(this[i]=s,this.hasAttribute(t)){s!==this.#d(t)&&updateAttribute(this,t,s)}this.#f(t);const r=this.propertyToParentPropertyMap,o=r?r.get(t):null;if(o){this.getRootNode().host.setAttribute(o,s)}this.#o(t,s),e.dispatch&&this.dispatchEvent(new CustomEvent("change",{bubbles:!0,composed:!0,detail:{propertyName:t}}))}})}static elementName(){return this.name.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase()}#b(t){const e=t.localName.includes("-");for(const s of t.getAttributeNames()){const r=t.getAttribute(s),i=this.#E(t,r);if(i){const r=this[i];if(void 0===r&&this.#R(t,s,i),t[i]=r,"value"===s&&this.#n(t,i,s),e){let e=t.propertyToParentPropertyMap;e||(e=new Map,t.propertyToParentPropertyMap=e),e.set(s,i)}}this.#v(r,t,s)}}#g(expression){return(()=>eval(expression)).call(this)}#y(t){const{localName:e}=t;if("style"===e)return;const s=t.textContent.trim(),r=this.#E(t,s);"textarea"===e&&r?(this.#n(t,r),t.textContent=this[r]):this.#v(s,t)}#l(t){const e=t.querySelectorAll("*");for(const t of e)this.#b(t),t.firstElementChild||this.#y(t)}static get observedAttributes(){return Object.keys(this.properties||{})}#E(t,e){if(!REFERENCE_RE.test(e))return;const s=e.substring(SKIP);return void 0===this[s]&&this.#R(t,null,s),s}#f(t){const e=this.constructor["#propertyToExpressionsMap"].get(t)||[];for(const t of e){const e=this.#g(t),s=this.#t.get(t)||[];for(const t of s)if(t instanceof Element)this.#N(t,e);else{const{element:s,attrName:r}=t;updateAttribute(s,r,e)}}requestAnimationFrame(()=>{this.#A(t)})}static register(){const t=this.elementName();customElements.get(t)||customElements.define(t,this)}#v(t,e,s){const r=this.#w(e,s,t);if(!r)return;this.constructor.processed||r.forEach(e=>{const s=e.substring(SKIP),r=this.constructor["#propertyToExpressionsMap"];let i=r.get(s);i||(i=[],r.set(s,i)),i.push(t)});let i=this.#t.get(t);i||(i=[],this.#t.set(t,i)),i.push(s?{element:e,attrName:s}:e);const o=this.#g(t);s?updateAttribute(e,s,o):this.#N(e,o)}#o(t,e){this.#e&&(this.#e.set(t,e),this.#s.setFormValue(this.#e))}#m(t,e,s){throw new Error(`component ${this.constructor.elementName()}`+(t?`, element "${t.localName}"`:"")+(e?`, attribute "${e}"`:"")+` ${s}`)}#R(t,e,s){this.#m(t,e,`refers to missing property "${s}"`)}#d(t){return this.#i(t,this.getAttribute(t))}#i(t,e){if(e?.match(REFERENCES_RE))return e;const{type:s}=this.constructor.properties[t];if(s===String)return e;if(s===Number){const s=Number(e);if(!isNaN(s))return s;this.#m(null,t,`must be a number, but was "${e}"`)}if(s===Boolean)return"true"===e||"false"!==e&&(e&&e!==t&&this.#m(null,t,"is a Boolean attribute, so its value must match attribute name or be missing"),e===t);this.#m(null,t,"does not specify its type")}#A(t){const e=this[t],s=this.#r.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;updateAttribute(s,r,e),s[r]=e}}#N(t,e){const{localName:s}=t,r=typeof e;"string"!==r&&"number"!==r&&this.#m(t,null," computed content is not a string or number"),"textarea"===s?t.value=e:"string"===r&&e.trim().startsWith("<")?(t.innerHTML=e,this.#c(t),this.#l(t)):t.textContent=e}#h(){const t=new Set(Object.keys(this.constructor.properties));for(const e of this.getAttributeNames())"id"!==e&&(e.startsWith("on")||t.has(e)||this.#m(null,e,"is not a supported attribute"))}#w(t,e,s){const r=s.match(REFERENCES_RE);if(r)return r.forEach(s=>{const r=s.substring(SKIP);void 0===this[r]&&this.#R(t,e,r)}),r}#c(root){for(const element of root.querySelectorAll("*")){const attributesToRemove=[];for(const attr of element.attributes){const attrName=attr.name;if(attrName.startsWith("on")){const eventName=attrName.slice(2).toLowerCase(),attrValue=attr.value;let fn;this.#w(element,attrName,attrValue),"function"==typeof this[attrValue]?fn=t=>this[attrValue](t):(this.#w(element,attrName,attrValue),fn=event=>eval(attrValue)),element.addEventListener(eventName,fn),attributesToRemove.push(attrName)}}for(const t of attributesToRemove)element.removeAttribute(t)}}}export default Wrec;export const css=String.raw;export const html=String.raw;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "wrec",
3
3
  "description": "a small library that greatly simplifies building web components",
4
4
  "author": "R. Mark Volkmann",
5
- "version": "0.5.6",
5
+ "version": "0.5.8",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",