web-signature 0.2.8 → 0.2.9

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
@@ -31,12 +31,17 @@ npm run dev
31
31
 
32
32
  * [Signature](#signature)
33
33
  * [Quick Start](#quick-start)
34
+ * [Try online](#try-online)
34
35
  * [Introduction](#introduction)
35
36
  * [Briefly about Signature](#briefly-about-signature)
36
37
  * [About Component](#about-component)
37
38
  * [Quick about the Library](#quick-about-the-library)
38
39
  * [See more here](#see-more-here)
39
40
 
41
+ ## Try online
42
+
43
+ You can also try Signature online using [StackBlitz](https://stackblitz.com/fork/signature-starter)
44
+
40
45
  # Introduction
41
46
 
42
47
  Signature uses four classes as its basis:
@@ -78,6 +78,9 @@ interface Component$1 {
78
78
  * The properties of the component.
79
79
  */
80
80
  data: Record<string, string | number | boolean | null>;
81
+ /**
82
+ * Plugins are stored here.
83
+ */
81
84
  $: Record<string, unknown>;
82
85
  /**
83
86
  * Returns the component as a string (template).
@@ -188,7 +191,15 @@ declare class Library {
188
191
  }
189
192
 
190
193
  declare abstract class Plugin {
194
+ /**
195
+ * Modules are mini plugins that are required for the plugin to work, they are processed and stored before the plugin itself is installed and stored in a safe place.
196
+ */
191
197
  readonly abstract modules: Record<string, () => Record<string, unknown>>;
198
+ /**
199
+ * The function returns an object that will be installed as a plugin in Signature.$
200
+ * @param modules
201
+ * @returns {Record<string, unknown>} The object that will be installed as a plugin
202
+ */
192
203
  abstract define(modules: Record<string, Record<string, unknown>>): Record<string, unknown>;
193
204
  }
194
205
 
@@ -228,6 +239,12 @@ declare class Signature {
228
239
  * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
229
240
  */
230
241
  libraries(): Record<string, ResolvedLib>;
242
+ /**
243
+ * Registers a plugin in the signature.
244
+ * @import {Plugin} from "./Plugin.js";
245
+ * @param {string} name The name of the plugin.
246
+ * @param {Plugin} plugin The plugin to register.
247
+ */
231
248
  use(name: string, plugin: Plugin): void;
232
249
  /**
233
250
  * Contacts the Component.onContact method through its reference.
@@ -267,14 +284,16 @@ declare class Prop<T extends keyof TypesMap> implements Prop$1 {
267
284
  isValid(value: TypesMap[keyof TypesMap]): boolean;
268
285
  }
269
286
 
270
- declare function html(strings: TemplateStringsArray, ...values: any[]): {
287
+ type HTMLTemplate = {
271
288
  strings: TemplateStringsArray;
272
289
  values: any[];
273
290
  };
274
- declare function unsafeHTML(value: any): {
291
+ declare function html(strings: TemplateStringsArray, ...values: any[]): HTMLTemplate;
292
+ type unsafeHTMLTemplate = {
275
293
  type: "unsafeHTML";
276
294
  value: any;
277
295
  };
296
+ declare function unsafeHTML(value: any): unsafeHTMLTemplate;
278
297
 
279
298
  declare function export_default(): Signature;
280
299
 
package/bundle/index.js CHANGED
@@ -101,6 +101,12 @@ class Signature {
101
101
  };
102
102
  return resolve(this.libs);
103
103
  }
104
+ /**
105
+ * Registers a plugin in the signature.
106
+ * @import {Plugin} from "./Plugin.js";
107
+ * @param {string} name The name of the plugin.
108
+ * @param {Plugin} plugin The plugin to register.
109
+ */
104
110
  use(name, plugin) {
105
111
  if (this.$[name]) {
106
112
  throw new Error(`Plugin with name ${name} already exists.`);
@@ -464,6 +470,14 @@ class Signature {
464
470
  update: () => this.updateRef(refName)
465
471
  };
466
472
  }
473
+ // Copying another attributes from the original element to the new one, with exceptions
474
+ for (const attr of Array.from(el.attributes)) {
475
+ const name = attr.name;
476
+ if (renderer.props[name] !== undefined || name === "ref" || name === "si-component" || name === "si-group")
477
+ continue;
478
+ if (!mountEl.hasAttribute(name))
479
+ mountEl.setAttribute(name, attr.value);
480
+ }
467
481
  el.replaceWith(body.firstElementChild);
468
482
  renderer.onMount?.(mountEl); // lifecycle hook
469
483
  });
@@ -619,8 +633,8 @@ function html(strings, ...values) {
619
633
  function unsafeHTML(value) {
620
634
  return { type: "unsafeHTML", value: value };
621
635
  }
636
+ // todo: make a loop function
622
637
 
623
- // todo: make description
624
638
  class Plugin {
625
639
  }
626
640
 
@@ -1 +1 @@
1
- class e{element;instance;constructor(e,t){this.instance=e,this.element=t}}const t={"element-not-found":"Element not found for selector: #selector","prop-is-required":"Property '#prop' in component '#component' is required but not provided.","unsupported-type-for-property":"Unsupported type for property '#prop' in component '#component': #type","invalid-value-for-property":"Invalid value for property '#prop' in component '#component': #value (value: #attr)","multiple-root-elements":"Component '#component' must render a single root element. \n\t#elements","ref-collision":"Ref collision detected for ref '#ref' in component '#component'.",unknown:"An unknown error occurred.","unknown-from":"An unknown error occurred in component '#from'.","stack-overflow":"Stack Overflow detected: possible recursive component rendering.","render-async-failed":"Error during asynchronous rendering of the component #component."};let n=0;class r{components={};refs={};libs={};bank=new Map;$={};$g={};constructor(){}add(e,t){const n="string"==typeof t?t:e.name;this.components[n]&&console.warn(new Error(`Component with name ${n} already exists.`)),this.components[n]=e}register(e,...t){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists.`));const n=e.list().filter(e=>!(e.name in t));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:n.map(e=>e.name),dependencies:e.libs};for(const t of n)this.add(t.component,`${e.name}-${t.name}`)}lib(e){return this.libs[e]}libraries(){const e=e=>{let t=e.name;return e.version&&(t+=`@${e.version}`),e.author&&(t+=`#${e.author}`),t},t=(n,r=new Set)=>{const o={};for(const[s,i]of Object.entries(n)){const n=e(i);r.has(n)||(r.add(n),o[n]={components:i.components,dependencies:t(i.dependencies,r)})}return o};return t(this.libs)}use(e,t){if(this.$[e])throw new Error(`Plugin with name ${e} already exists.`);let n={};Object.keys(t.modules).forEach(e=>{n[e]=t.modules[e]()}),this.$[e]={plugin:t.define(n),modules:n},this.$g[e]=this.$[e].plugin}contactWith(e,...t){const n=this.refs[e];if(!n)throw new Error(`Ref with name ${e} does not exist.`);const r=n.instance;return r.onContact?.(...t)}updateRef(e){const t=this.refs[e];if(!t)throw new Error(`Ref with name ${e} does not exist.`);const n=t.instance;let r={strings:Object.assign([],{raw:[]}),values:[]};try{r=n.render()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:n.name,err:e}}const o=document.createElement("template");(e=>{r instanceof Promise?r.then(t=>{o.content.appendChild(this.templateToElement(t,n.name)),e()}).catch(e=>{throw{id:"unknown-from",from:n.name,err:e}}):"object"==typeof r&&(o.content.appendChild(this.templateToElement(r,n.name)),e())})(()=>{if(1!==o.content.children.length)throw new Error(`Component '${n.name}' must render a single root element.`);const e=o.content.firstElementChild;let r=t.element.getAttribute("ref");r&&e.setAttribute("ref",r),n.groups.length>0&&e.setAttribute("si-group",n.groups.join(" ")),this.render(o.content),n.onRender?.(),t.element.replaceWith(e),t.element=e,n.onMount?.(e)})}contact(e,n){new Promise((t,r)=>{try{const t=document.querySelector(e);if(!t)return void r({id:"element-not-found",selector:e});const o=document.createElement("div");o.innerHTML=t.innerHTML,this.render(o),t.replaceChildren(...Array.from(o.childNodes)),n&&n()}catch(e){e instanceof Error?e instanceof RangeError&&e.message.includes("stack")?r({id:"stack-overflow",err:e}):r({id:"unknown",err:e}):r(e)}}).catch(e=>{let n=t[e.id];throw Object.keys(e).filter(e=>!(e in["id","err"])).forEach(t=>{n=n.replace(new RegExp(`#${t}`,"gm"),String(e[t]))}),window.SIGNATURE?.DEV_MODE&&console.log(e),e.id in["unknown","unknown-from","render-async-failed"]?console.error(`[${e.id}] ${n}`,e.err):console.error(`[${e.id}] ${n}`),"Page rendering was interrupted by Signature due to the above error."})}templateToString(e){let t="";for(let n=0;n<e.strings.length;n++)t+=e.strings[n],n<e.values.length&&(t+=`\x3c!--si-mark-${n}--\x3e`);return t}fillTemplate(e,t){let n;return this.bank.has(e.strings.join("@@"))?n=this.bank.get(e.strings.join("@@"))?.cloneNode(!0):(n=document.createElement("template"),n.innerHTML=t,this.bank.set(e.strings.join("@@"),n.cloneNode(!0))),(()=>{let t,r=document.createTreeWalker(n.content,NodeFilter.SHOW_COMMENT),o=[];for(;t=r.nextNode();)/si-mark-\d+/gm.test(t.nodeValue??"")&&o.push(t);for(const t of o){const n=e.values[Number((t.nodeValue??"").match(/si-mark-(\d+)/m)[1])];if("object"==typeof n&&"unsafeHTML"===n.type){let e=document.createElement("div");for(e.innerHTML=n.value;e.firstChild;)t.parentNode?.insertBefore(e.firstChild,t);t.remove()}else t.replaceWith(document.createTextNode(String(n)))}})(),(()=>{let t,r=document.createTreeWalker(n.content,NodeFilter.SHOW_ELEMENT);for(;t=r.nextNode();)for(const n of Array.from(t.attributes))if(/<!--si-mark-\d+-->/gm.test(n.value)){const r=n.value.match(/si-mark-(\d+)/m);if(r){const o=e.values[Number(r[1])];t.setAttribute(n.name,String(o))}}})(),n}templateToElement(e,t){const n=this.templateToString(e),r=this.fillTemplate(e,n);if(1!==r.content.children.length)throw{id:"multiple-root-elements",elements:r.innerHTML,component:t};return r.content.firstElementChild}render(t){for(const r of Object.keys(this.components)){const o=this.components[r];for(const s of Array.from(t.querySelectorAll(r)).concat(Array.from(t.querySelectorAll(`[si-component="${r}"]`)))){const t=new o;if(t.$=this.$g,Object.freeze(t.$),t.onInit?.(),s instanceof HTMLElement){t.content=s.innerHTML.trim();for(const e of Object.keys(t.props)){const n=s.getAttribute(e);if(null===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.data[e]=null}else if(""===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.props[e].isValid(n)&&(t.data[e]=null)}else{let o;switch(t.props[e].type){case"boolean":o=Boolean(n);break;case"number":o=Number(n);break;case"string":o=String(n);break;case"array":try{o=JSON.parse(n)}catch(t){throw{id:"invalid-value-for-property",component:r,prop:e,value:n,attr:n}}break;default:if(t.props[e].required)throw{id:"unsupported-type-for-property",component:r,prop:e,type:t.props[e].type}}if(void 0!==o){if(!t.props[e].isValid(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};if(t.props[e].validate&&!t.props[e].validate(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};t.data[e]=o,t.onPropParsed?.(t.props[e],o)}}}t.onPropsParsed?.()}const i=document.createElement("template");let a={strings:Object.assign([],{raw:[]}),values:[]};try{a=t.render()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:t.name,err:e}}(e=>{if(a instanceof Promise)try{a.then(t=>{i.appendChild(this.templateToElement(t,r)),e()}).catch(e=>{throw{id:"unknown-from",from:t.name,err:e}})}catch(e){throw{id:"render-async-failed",component:r,err:e}}else"object"==typeof a&&(i.appendChild(this.templateToElement(a,r)),e())})(()=>{this.render(i.content),t.onRender?.();const o=i.firstElementChild;if(t?.groups.length>0&&o.setAttribute("si-group",t.groups.join(" ")),s.hasAttribute("ref")||t.options.generateRefIfNotSpecified){let i=s.getAttribute("ref");if(null===i&&(i=""),n++,""===i&&(i=`r${n}${Math.random().toString(36).substring(2,15)}${n}`),this.refs[i])throw{id:"ref-collision",ref:i,component:r};this.refs[i]=new e(t,o),o.setAttribute("ref",i),t.ref={id:i,contact:(...e)=>this.contactWith(i,...e),update:()=>this.updateRef(i)}}s.replaceWith(i.firstElementChild),t.onMount?.(o)})}}}}class o{content;groups=[];options={generateRefIfNotSpecified:!1};ref;props={};data={};$={};onInit(){}onRender(){}onMount(e){}onContact(...e){}onPropsParsed(){}onPropParsed(e,t){}}class s{type;required=!0;validate;constructor(e,t=!0,n){this.type=e,this.required=t,this.validate=n||(()=>!0)}isValid(e){switch(this.type){case"boolean":return"boolean"==typeof e;case"number":return"number"==typeof e&&!isNaN(e);case"string":return"string"==typeof e;case"array":return Array.isArray(e);case"null":return null===e;default:return!1}}}class i{name;version;author;libs={};components={};constructor(e,t,n){this.name=e,this.author=t,this.version=n}add(e,t){const n="string"==typeof t?t:e.name;this.components[n]&&console.warn(new Error(`Component with name ${n} already exists.`)),this.components[n]=e}register(e,...t){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists in ${this.name}.`));const n=e.list().filter(e=>!(e.name in t));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:n.map(e=>e.name),dependencies:e.libs};for(const t of n)this.add(t.component,`${e.name}-${t.name}`)}get(e){return this.components[e]}lib(e){return this.libs[e]}list(){return Object.entries(this.components).map(([e,t])=>({component:t,name:e}))}}function a(e,...t){return{strings:e,values:t}}function c(e){return{type:"unsafeHTML",value:e}}class l{}function p(){return new r}export{o as Component,i as Library,l as Plugin,s as Prop,r as Signature,p as default,a as html,c as unsafeHTML};
1
+ class e{element;instance;constructor(e,t){this.instance=e,this.element=t}}const t={"element-not-found":"Element not found for selector: #selector","prop-is-required":"Property '#prop' in component '#component' is required but not provided.","unsupported-type-for-property":"Unsupported type for property '#prop' in component '#component': #type","invalid-value-for-property":"Invalid value for property '#prop' in component '#component': #value (value: #attr)","multiple-root-elements":"Component '#component' must render a single root element. \n\t#elements","ref-collision":"Ref collision detected for ref '#ref' in component '#component'.",unknown:"An unknown error occurred.","unknown-from":"An unknown error occurred in component '#from'.","stack-overflow":"Stack Overflow detected: possible recursive component rendering.","render-async-failed":"Error during asynchronous rendering of the component #component."};let n=0;class r{components={};refs={};libs={};bank=new Map;$={};$g={};constructor(){}add(e,t){const n="string"==typeof t?t:e.name;this.components[n]&&console.warn(new Error(`Component with name ${n} already exists.`)),this.components[n]=e}register(e,...t){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists.`));const n=e.list().filter(e=>!(e.name in t));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:n.map(e=>e.name),dependencies:e.libs};for(const t of n)this.add(t.component,`${e.name}-${t.name}`)}lib(e){return this.libs[e]}libraries(){const e=e=>{let t=e.name;return e.version&&(t+=`@${e.version}`),e.author&&(t+=`#${e.author}`),t},t=(n,r=new Set)=>{const o={};for(const[s,i]of Object.entries(n)){const n=e(i);r.has(n)||(r.add(n),o[n]={components:i.components,dependencies:t(i.dependencies,r)})}return o};return t(this.libs)}use(e,t){if(this.$[e])throw new Error(`Plugin with name ${e} already exists.`);let n={};Object.keys(t.modules).forEach(e=>{n[e]=t.modules[e]()}),this.$[e]={plugin:t.define(n),modules:n},this.$g[e]=this.$[e].plugin}contactWith(e,...t){const n=this.refs[e];if(!n)throw new Error(`Ref with name ${e} does not exist.`);const r=n.instance;return r.onContact?.(...t)}updateRef(e){const t=this.refs[e];if(!t)throw new Error(`Ref with name ${e} does not exist.`);const n=t.instance;let r={strings:Object.assign([],{raw:[]}),values:[]};try{r=n.render()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:n.name,err:e}}const o=document.createElement("template");(e=>{r instanceof Promise?r.then(t=>{o.content.appendChild(this.templateToElement(t,n.name)),e()}).catch(e=>{throw{id:"unknown-from",from:n.name,err:e}}):"object"==typeof r&&(o.content.appendChild(this.templateToElement(r,n.name)),e())})(()=>{if(1!==o.content.children.length)throw new Error(`Component '${n.name}' must render a single root element.`);const e=o.content.firstElementChild;let r=t.element.getAttribute("ref");r&&e.setAttribute("ref",r),n.groups.length>0&&e.setAttribute("si-group",n.groups.join(" ")),this.render(o.content),n.onRender?.(),t.element.replaceWith(e),t.element=e,n.onMount?.(e)})}contact(e,n){new Promise((t,r)=>{try{const t=document.querySelector(e);if(!t)return void r({id:"element-not-found",selector:e});const o=document.createElement("div");o.innerHTML=t.innerHTML,this.render(o),t.replaceChildren(...Array.from(o.childNodes)),n&&n()}catch(e){e instanceof Error?e instanceof RangeError&&e.message.includes("stack")?r({id:"stack-overflow",err:e}):r({id:"unknown",err:e}):r(e)}}).catch(e=>{let n=t[e.id];throw Object.keys(e).filter(e=>!(e in["id","err"])).forEach(t=>{n=n.replace(new RegExp(`#${t}`,"gm"),String(e[t]))}),window.SIGNATURE?.DEV_MODE&&console.log(e),e.id in["unknown","unknown-from","render-async-failed"]?console.error(`[${e.id}] ${n}`,e.err):console.error(`[${e.id}] ${n}`),"Page rendering was interrupted by Signature due to the above error."})}templateToString(e){let t="";for(let n=0;n<e.strings.length;n++)t+=e.strings[n],n<e.values.length&&(t+=`\x3c!--si-mark-${n}--\x3e`);return t}fillTemplate(e,t){let n;return this.bank.has(e.strings.join("@@"))?n=this.bank.get(e.strings.join("@@"))?.cloneNode(!0):(n=document.createElement("template"),n.innerHTML=t,this.bank.set(e.strings.join("@@"),n.cloneNode(!0))),(()=>{let t,r=document.createTreeWalker(n.content,NodeFilter.SHOW_COMMENT),o=[];for(;t=r.nextNode();)/si-mark-\d+/gm.test(t.nodeValue??"")&&o.push(t);for(const t of o){const n=e.values[Number((t.nodeValue??"").match(/si-mark-(\d+)/m)[1])];if("object"==typeof n&&"unsafeHTML"===n.type){let e=document.createElement("div");for(e.innerHTML=n.value;e.firstChild;)t.parentNode?.insertBefore(e.firstChild,t);t.remove()}else t.replaceWith(document.createTextNode(String(n)))}})(),(()=>{let t,r=document.createTreeWalker(n.content,NodeFilter.SHOW_ELEMENT);for(;t=r.nextNode();)for(const n of Array.from(t.attributes))if(/<!--si-mark-\d+-->/gm.test(n.value)){const r=n.value.match(/si-mark-(\d+)/m);if(r){const o=e.values[Number(r[1])];t.setAttribute(n.name,String(o))}}})(),n}templateToElement(e,t){const n=this.templateToString(e),r=this.fillTemplate(e,n);if(1!==r.content.children.length)throw{id:"multiple-root-elements",elements:r.innerHTML,component:t};return r.content.firstElementChild}render(t){for(const r of Object.keys(this.components)){const o=this.components[r];for(const s of Array.from(t.querySelectorAll(r)).concat(Array.from(t.querySelectorAll(`[si-component="${r}"]`)))){const t=new o;if(t.$=this.$g,Object.freeze(t.$),t.onInit?.(),s instanceof HTMLElement){t.content=s.innerHTML.trim();for(const e of Object.keys(t.props)){const n=s.getAttribute(e);if(null===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.data[e]=null}else if(""===n){if(t.props[e].required)throw{id:"prop-is-required",component:r,prop:e};t.props[e].isValid(n)&&(t.data[e]=null)}else{let o;switch(t.props[e].type){case"boolean":o=Boolean(n);break;case"number":o=Number(n);break;case"string":o=String(n);break;case"array":try{o=JSON.parse(n)}catch(t){throw{id:"invalid-value-for-property",component:r,prop:e,value:n,attr:n}}break;default:if(t.props[e].required)throw{id:"unsupported-type-for-property",component:r,prop:e,type:t.props[e].type}}if(void 0!==o){if(!t.props[e].isValid(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};if(t.props[e].validate&&!t.props[e].validate(o))throw{id:"invalid-value-for-property",component:r,prop:e,value:o,attr:n};t.data[e]=o,t.onPropParsed?.(t.props[e],o)}}}t.onPropsParsed?.()}const i=document.createElement("template");let a={strings:Object.assign([],{raw:[]}),values:[]};try{a=t.render()}catch(e){if(e instanceof Error)throw{id:"unknown-from",from:t.name,err:e}}(e=>{if(a instanceof Promise)try{a.then(t=>{i.appendChild(this.templateToElement(t,r)),e()}).catch(e=>{throw{id:"unknown-from",from:t.name,err:e}})}catch(e){throw{id:"render-async-failed",component:r,err:e}}else"object"==typeof a&&(i.appendChild(this.templateToElement(a,r)),e())})(()=>{this.render(i.content),t.onRender?.();const o=i.firstElementChild;if(t?.groups.length>0&&o.setAttribute("si-group",t.groups.join(" ")),s.hasAttribute("ref")||t.options.generateRefIfNotSpecified){let i=s.getAttribute("ref");if(null===i&&(i=""),n++,""===i&&(i=`r${n}${Math.random().toString(36).substring(2,15)}${n}`),this.refs[i])throw{id:"ref-collision",ref:i,component:r};this.refs[i]=new e(t,o),o.setAttribute("ref",i),t.ref={id:i,contact:(...e)=>this.contactWith(i,...e),update:()=>this.updateRef(i)}}for(const e of Array.from(s.attributes)){const n=e.name;void 0===t.props[n]&&"ref"!==n&&"si-component"!==n&&"si-group"!==n&&(o.hasAttribute(n)||o.setAttribute(n,e.value))}s.replaceWith(i.firstElementChild),t.onMount?.(o)})}}}}class o{content;groups=[];options={generateRefIfNotSpecified:!1};ref;props={};data={};$={};onInit(){}onRender(){}onMount(e){}onContact(...e){}onPropsParsed(){}onPropParsed(e,t){}}class s{type;required=!0;validate;constructor(e,t=!0,n){this.type=e,this.required=t,this.validate=n||(()=>!0)}isValid(e){switch(this.type){case"boolean":return"boolean"==typeof e;case"number":return"number"==typeof e&&!isNaN(e);case"string":return"string"==typeof e;case"array":return Array.isArray(e);case"null":return null===e;default:return!1}}}class i{name;version;author;libs={};components={};constructor(e,t,n){this.name=e,this.author=t,this.version=n}add(e,t){const n="string"==typeof t?t:e.name;this.components[n]&&console.warn(new Error(`Component with name ${n} already exists.`)),this.components[n]=e}register(e,...t){this.libs[e.name]&&console.warn(new Error(`Library with name ${e.name} already exists in ${this.name}.`));const n=e.list().filter(e=>!(e.name in t));this.libs[e.name]={name:e.name,version:e.version,author:e.author,components:n.map(e=>e.name),dependencies:e.libs};for(const t of n)this.add(t.component,`${e.name}-${t.name}`)}get(e){return this.components[e]}lib(e){return this.libs[e]}list(){return Object.entries(this.components).map(([e,t])=>({component:t,name:e}))}}function a(e,...t){return{strings:e,values:t}}function c(e){return{type:"unsafeHTML",value:e}}class l{}function p(){return new r}export{o as Component,i as Library,l as Plugin,s as Prop,r as Signature,p as default,a as html,c as unsafeHTML};
package/dist/Plugin.js CHANGED
@@ -1,3 +1,2 @@
1
- // todo: make description
2
1
  export default class Plugin {
3
2
  }
package/dist/Signature.js CHANGED
@@ -81,6 +81,12 @@ export default class Signature {
81
81
  };
82
82
  return resolve(this.libs);
83
83
  }
84
+ /**
85
+ * Registers a plugin in the signature.
86
+ * @import {Plugin} from "./Plugin.js";
87
+ * @param {string} name The name of the plugin.
88
+ * @param {Plugin} plugin The plugin to register.
89
+ */
84
90
  use(name, plugin) {
85
91
  if (this.$[name]) {
86
92
  throw new Error(`Plugin with name ${name} already exists.`);
@@ -444,6 +450,14 @@ export default class Signature {
444
450
  update: () => this.updateRef(refName)
445
451
  };
446
452
  }
453
+ // Copying another attributes from the original element to the new one, with exceptions
454
+ for (const attr of Array.from(el.attributes)) {
455
+ const name = attr.name;
456
+ if (renderer.props[name] !== undefined || name === "ref" || name === "si-component" || name === "si-group")
457
+ continue;
458
+ if (!mountEl.hasAttribute(name))
459
+ mountEl.setAttribute(name, attr.value);
460
+ }
447
461
  el.replaceWith(body.firstElementChild);
448
462
  renderer.onMount?.(mountEl); // lifecycle hook
449
463
  });
@@ -1,4 +1,12 @@
1
1
  export default abstract class Plugin {
2
+ /**
3
+ * Modules are mini plugins that are required for the plugin to work, they are processed and stored before the plugin itself is installed and stored in a safe place.
4
+ */
2
5
  readonly abstract modules: Record<string, () => Record<string, unknown>>;
6
+ /**
7
+ * The function returns an object that will be installed as a plugin in Signature.$
8
+ * @param modules
9
+ * @returns {Record<string, unknown>} The object that will be installed as a plugin
10
+ */
3
11
  abstract define(modules: Record<string, Record<string, unknown>>): Record<string, unknown>;
4
12
  }
@@ -37,6 +37,12 @@ export default class Signature {
37
37
  * @return {Record<string, ResolvedLib>} A object of formatted libraries with their components and dependencies.
38
38
  */
39
39
  libraries(): Record<string, ResolvedLib>;
40
+ /**
41
+ * Registers a plugin in the signature.
42
+ * @import {Plugin} from "./Plugin.js";
43
+ * @param {string} name The name of the plugin.
44
+ * @param {Plugin} plugin The plugin to register.
45
+ */
40
46
  use(name: string, plugin: Plugin): void;
41
47
  /**
42
48
  * Contacts the Component.onContact method through its reference.
package/dist/d/html.d.ts CHANGED
@@ -1,8 +1,12 @@
1
- export default function html(strings: TemplateStringsArray, ...values: any[]): {
1
+ type HTMLTemplate = {
2
2
  strings: TemplateStringsArray;
3
3
  values: any[];
4
4
  };
5
- export declare function unsafeHTML(value: any): {
5
+ export default function html(strings: TemplateStringsArray, ...values: any[]): HTMLTemplate;
6
+ type unsafeHTMLTemplate = {
6
7
  type: "unsafeHTML";
7
8
  value: any;
8
9
  };
10
+ export declare function unsafeHTML(value: any): unsafeHTMLTemplate;
11
+ export declare function joinTemplates(...templates: HTMLTemplate[]): HTMLTemplate;
12
+ export {};
@@ -49,6 +49,9 @@ interface Component {
49
49
  * The properties of the component.
50
50
  */
51
51
  data: Record<string, string | number | boolean | null>;
52
+ /**
53
+ * Plugins are stored here.
54
+ */
52
55
  $: Record<string, unknown>;
53
56
  /**
54
57
  * Returns the component as a string (template).
package/dist/html.js CHANGED
@@ -4,3 +4,16 @@ export default function html(strings, ...values) {
4
4
  export function unsafeHTML(value) {
5
5
  return { type: "unsafeHTML", value: value };
6
6
  }
7
+ export function joinTemplates(...templates) {
8
+ let strings = [];
9
+ let values = [];
10
+ templates.forEach((t) => {
11
+ strings.push(...t.strings);
12
+ values.push(...t.values);
13
+ });
14
+ return {
15
+ strings: strings,
16
+ values: values
17
+ };
18
+ }
19
+ // todo: make a loop function
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "web-signature",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Primitive and fast framework for rendering web interfaces",
5
5
  "license": "ISC",
6
6
  "author": "PinBib",
package/src/Plugin.ts CHANGED
@@ -1,6 +1,13 @@
1
- // todo: make description
2
1
  export default abstract class Plugin {
2
+ /**
3
+ * Modules are mini plugins that are required for the plugin to work, they are processed and stored before the plugin itself is installed and stored in a safe place.
4
+ */
3
5
  readonly abstract modules: Record<string, () => Record<string, unknown>>;
4
6
 
7
+ /**
8
+ * The function returns an object that will be installed as a plugin in Signature.$
9
+ * @param modules
10
+ * @returns {Record<string, unknown>} The object that will be installed as a plugin
11
+ */
5
12
  public abstract define(modules: Record<string, Record<string, unknown>>): Record<string, unknown>;
6
13
  }
package/src/Signature.ts CHANGED
@@ -114,6 +114,12 @@ export default class Signature {
114
114
  return resolve(this.libs);
115
115
  }
116
116
 
117
+ /**
118
+ * Registers a plugin in the signature.
119
+ * @import {Plugin} from "./Plugin.js";
120
+ * @param {string} name The name of the plugin.
121
+ * @param {Plugin} plugin The plugin to register.
122
+ */
117
123
  public use(name: string, plugin: Plugin): void {
118
124
  if (this.$[name]) {
119
125
  throw new Error(`Plugin with name ${name} already exists.`);
@@ -379,7 +385,7 @@ export default class Signature {
379
385
 
380
386
  renderer.$ = this.$g; // injecting plugins
381
387
  Object.freeze(renderer.$); // prevent plugins from being modified by components
382
-
388
+
383
389
  renderer.onInit?.(); // lifecycle hook
384
390
 
385
391
  if (el instanceof HTMLElement) {
@@ -550,6 +556,15 @@ export default class Signature {
550
556
  };
551
557
  }
552
558
 
559
+ // Copying another attributes from the original element to the new one, with exceptions
560
+ for (const attr of Array.from(el.attributes)) {
561
+ const name: string = attr.name;
562
+
563
+ if (renderer.props[name] !== undefined || name === "ref" || name === "si-component" || name === "si-group") continue;
564
+
565
+ if (!mountEl.hasAttribute(name)) mountEl.setAttribute(name, attr.value);
566
+ }
567
+
553
568
  el.replaceWith(body.firstElementChild as Element);
554
569
 
555
570
  renderer.onMount?.(mountEl); // lifecycle hook
package/src/html.ts CHANGED
@@ -1,10 +1,31 @@
1
- export default function html(strings: TemplateStringsArray, ...values: any[]): {
1
+ type HTMLTemplate = {
2
2
  strings: TemplateStringsArray,
3
3
  values: any[]
4
- } {
4
+ };
5
+
6
+ export default function html(strings: TemplateStringsArray, ...values: any[]): HTMLTemplate {
5
7
  return {strings, values};
6
8
  }
7
9
 
8
- export function unsafeHTML(value: any): { type: "unsafeHTML", value: any } {
10
+ type unsafeHTMLTemplate = { type: "unsafeHTML", value: any };
11
+
12
+ export function unsafeHTML(value: any): unsafeHTMLTemplate {
9
13
  return {type: "unsafeHTML", value: value};
10
- }
14
+ }
15
+
16
+ export function joinTemplates(...templates: HTMLTemplate[]): HTMLTemplate {
17
+ let strings: string[] = [];
18
+ let values: any[] = [];
19
+
20
+ templates.forEach((t) => {
21
+ strings.push(...t.strings);
22
+ values.push(...t.values);
23
+ });
24
+
25
+ return {
26
+ strings: strings as unknown as TemplateStringsArray,
27
+ values: values
28
+ } as HTMLTemplate;
29
+ }
30
+
31
+ // todo: make a loop function
@@ -61,7 +61,10 @@ interface Component {
61
61
  * The properties of the component.
62
62
  */
63
63
  data: Record<string, string | number | boolean | null>;
64
- // todo: make description
64
+
65
+ /**
66
+ * Plugins are stored here.
67
+ */
65
68
  $: Record<string, unknown>;
66
69
 
67
70
  /**