vaderjs 1.3.0 → 1.3.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vaderjs",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "A Reactive Framework for Building Content Rich Single-Page Applications (SPA)",
5
5
  "main": "index.js",
6
6
  "scripts": {
package/vader-min.js ADDED
@@ -0,0 +1 @@
1
+ let dom=[],states={},worker=new Worker(new URL("./worker.js",import.meta.url));function markdown(e){let t=e.match(/(#+)(.*)/g);return t&&t.forEach((t=>{if(t.includes("/")||t.includes("<")||t.includes(">"))return;let s=t.split("#").length;e=e.replace(t,`<h${s} class="markdown_heading">${t.replace(/#/g,"")}</h${s}>`)})),e=(e=(e=(e=(e=(e=(e=e.replace(/\*\*(.*?)\*\*/g,((e,t)=>`<b class="markdown_bold">${t}</b>`))).replace(/\*(.*?)\*/g,((e,t)=>`<i class="markdown_italic">${t}</i>`))).replace(/`(.*?)`/g,((e,t)=>`<code>${t}</code>`))).replace(/\[([^\]]+)\]\(([^)]+)\)/g,((e,t,s)=>`<a class="markdown_link" href="${s}">${t}</a>`))).replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((e,t,s)=>`<img class="markdown_image" src="${s}" alt="${t}" />`))).split("\n").map(((e,t,s)=>e.match(/^\s*-\s+(.*?)$/gm)?0!==t&&s[t-1].match(/^\s*-\s+(.*?)$/gm)?t!==s.length-1&&s[t+1].match(/^\s*-\s+(.*?)$/gm)?`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`:`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`:e)).join("\n")).split("\n").map(((e,t,s)=>e.match(/^\s*\d+\.\s+(.*?)$/gm)?0!==t&&s[t-1].match(/^\s*\d+\.\s+(.*?)$/gm)?t!==s.length-1&&s[t+1].match(/^\s*\d+\.\s+(.*?)$/gm)?`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`:`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`:e)).join("\n")}export const useRef=e=>{const t=document.querySelector(`[ref="${e}"]`);return{current:t,update:e=>{const s=(new DOMParser).parseFromString(e,"text/html").body.firstChild;if(t){!s.isEqualNode(t)&&t.parentNode.replaceChild(s,t)}}}};let components=[];export class Component{constructor(){this.states={},this.name=this.constructor.name,this.executedEffects={},this.storedProps={},this.componentMounted=!1,this.hasMounted=!1,this.$_signal_subscribers=[],this.$_signal_subscribers_ran=[],this.effects={},this.$_useStore_subscribers=[],this.init(),this.Componentcontent=null,this.$_signal_dispatch_event=new CustomEvent("signalDispatch",{detail:{hasUpdated:!1,state:null}}),this.snapshots=[],this.dom=[],this.cfr=!1}adapter(){}init(){this.registerComponent()}registerComponent(){components.push(this)}setState(e,t){this.states[e]=t,this.updateComponent()}unmount(){this.componentMounted=!1,this.componentWillUnmount(),document.querySelector(`[data-component="${this.name}"]`).remove(),document.querySelector(`[data-component="${this.name}"]`)||(components=components.filter((e=>e.name!==this.name)))}componentUpdate(e,t,s){}componentDidMount(){}componentWillUnmount(){}signal=(e,t)=>{let s=!1,[r,n]=this.useState(e,t,(()=>{if(this.$_signal_subscribers.length>0){for(var e=0;e<this.$_signal_subscribers.length;e++)if(!s){if(this.$_signal_subscribers[e].runonce&&this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[e]))break;return this.$_signal_subscribers[e].function(r),void this.$_signal_subscribers_ran.push(this.$_signal_subscribers[e])}}else this.$_signal_dispatch_event.detail.hasUpdated=!0,this.$_signal_dispatch_event.detail.state=r,window.dispatchEvent(this.$_signal_dispatch_event)}));return this.$_signal_subscribe=(e,t)=>{this.$_signal_subscribers.push({function:e,runonce:t})},this.$_signal_cleanup=e=>{this.$_signal_subscribers=this.$_signal_subscribers.filter((t=>t.function!==e))},this.$_signal_dispatch=()=>{for(var e=0;e<this.$_signal_subscribers.length&&(!this.$_signal_subscribers[e].runonce||!this.$_signal_subscribers_ran.includes(this.$_signal_subscribers[e]));e++)this.$_signal_subscribers[e].function(r),this.$_signal_subscribers_ran.push(this.$_signal_subscribers[e])},this.$_signal_get=()=>r,this.$_signal_call=()=>{s=!0,this.$_signal_dispatch()},this.$_signal_set=e=>{n(e)},{subscribe:this.$_signal_subscribe,cleanup:this.$_signal_cleanup,dispatch:this.$_signal_dispatch,call:this.$_signal_call,set:this.$_signal_set,get:this.$_signal_get}};useAuth(e){let t=e.rulesets;if(!t)throw new Error("No rulesets provided");let s=e.user,r={can:e=>{let r=!1;return t.forEach((t=>{t.action===e&&t.condition(s)&&(r=!0)})),r},hasRole:e=>s.role&&s.role.includes(e),canWithRole:(e,t)=>r.can(e)&&r.hasRole(t),assignRule:e=>{t.some((t=>t.action===e.action))||t.push(e)},revokeRule:e=>{t=t.filter((t=>t.action!==e))},canAnyOf:e=>e.some((e=>r.can(e))),canAllOf:e=>e.every((e=>r.can(e))),canGroup:(e,t="any")=>"any"===t?r.canAnyOf(e):r.canAllOf(e)};return r}useReducer(e,t,s){return this.states[e]||(this.states[e]=s),[this.states[e],s=>{this.states[e]=t(this.states[e],s),this.updateComponent()}]}runEffects(){Object.keys(this.effects).forEach((e=>{this.effects[e].forEach((e=>{this.executedEffects[e]||(e(),this.executedEffects[e]=!0)}))}))}useSyncStore(e,t){let[s,r]=this.useState(e,t||localStorage.getItem(`$_vader_${e}`,(t=>{localStorage.setItem(`$_vader_${e}`,JSON.stringify(t)),this.$_useStore_subscribers.forEach((e=>{e(t)}))}))||{});return{getField:e=>s[e],setField:(e,t)=>{const n={...s,[e]:t};r(n)},subscribe:e=>this.$_useStore_subscribers.push(e),clear:e=>{let t=s;delete t[e],r(t)}}}useState(e,t,s=null){return this.states[e]||(this.states[e]=t),[this.states[e],t=>{this.states[e]=t,this.updateComponent(),"function"==typeof s&&s()}]}useRef(e){console.log(this.dom);const t=this.dom[e];return{current:()=>t,update:e=>{const s=(new DOMParser).parseFromString(e,"text/html").body.firstChild;if(t){!s.isEqualNode(t)&&t.parentNode.replaceChild(s,t)}}}}useEffect(e,t){return this.effects[this.name]||(this.effects[this.name]=[]),this.effects[this.name].push(e),t.length>0?t.forEach((e=>{if(e.set)throw new Error("signal found, do not use effect and signals at the same time - signals are more efficient")})):this.hasMounted||(e(),this.hasMounted=!0),{cleanup:()=>{this.effects[this.name]=this.effects[this.name].filter((t=>t!==e))}}}$Function(e){let t=e.name;return t||(t="anonymous"+Math.floor(1e17*Math.random())),window[t]=e,`window.${t}()`}updateComponent(){const e=document.createDocumentFragment();Object.keys(components).forEach((async t=>{const{name:s}=components[t];let r=document.querySelector(`[data-component="${s}"]`),n={name:s,time:(new Date).getTime(),prev_state:this.states,prev_props:this.storedProps,content:r.innerHTML};if(!r)return;const i=await new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","props","render","return `"+await this.render()+"`;")(this.useState,this.useEffect,this.useAuth,this.useReducer,this.useSyncStore,this.signal,this.render);if(i!==r.innerHTML){if(this.snapshots.length>0){this.snapshots[this.snapshots.length-1]!==n&&this.snapshots.push(n)}else this.snapshots.push(n);this.componentUpdate(n.prev_state,n.prev_props,n.content),e.appendChild(document.createRange().createContextualFragment(i)),r.innerHTML="",r.appendChild(e),this.runEffects()}}))}validateClassName(e){return/^[a-zA-Z0-9-_]+$/.test(e)}parseHTML(e){const t=(new DOMParser).parseFromString(e,"text/html");console.log(t);return t.documentElement.querySelectorAll("*").forEach((e=>{if("IMG"===e.nodeName){if(!e.hasAttribute("alt")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${e.outerHTML} missing alt attribute`);if(e.hasAttribute("alt")&&e.getAttribute("alt").length<1&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new SyntaxError(`Image: ${e.outerHTML} alt attribute cannot be empty`);if(e.hasAttribute("src")&&!e.getAttribute("src")?.includes("http")||!e.getAttribute("src")?.includes("https")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_accessibility --\x3e")){let t=e.getAttribute("src");e.setAttribute("aria-hidden","true"),e.setAttribute("hidden","true");let s=window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/"+e.getAttribute("src"),r=new Image;r.src=s,r.onerror=()=>{throw e.setAttribute("src",t),new Error(`Image: ${e.outerHTML} not found`)},e.setAttribute("src",s),r.onload=()=>{document.querySelectorAll(`img[src="${s}"]`).forEach((e=>{e.setAttribute("src",s),e.removeAttribute("aria-hidden"),e.removeAttribute("hidden")}))}}}else{if(e.hasAttribute("ref")&&(t[e.getAttribute("ref")]=e),"MARKDOWN"===e.nodeName&&(e.innerHTML=markdown(e.innerHTML.replace(/\\n/g,"\n").trim())),e.hasAttribute("class")){if(!document.documentElement.outerHTML.includes("\x3c!-- #vader-allow_class --\x3e"))throw console.warn("you can disable class errors using, \x3c!-- #vader-allow_class --\x3e"),new Error("class attribute is not allowed, please use className instead")}else e.hasAttribute("className")&&(e.setAttribute("class",e.getAttribute("className")),e.removeAttribute("className"));e.hasAttribute("href")&&e.getAttribute("href").startsWith("/")&&!document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")&&e.setAttribute("href",`#/${e.getAttribute("href").replace("/","")}`),!e.hasAttribute("src")||e.getAttribute("src").includes("http")||e.getAttribute("src").includes("https")||document.documentElement.outerHTML.includes("\x3c!-- #vader-disable_relative-paths --\x3e")||e.setAttribute("src",`./public/${e.getAttribute("src")}`)}})),e=t.body.innerHTML,this.Componentcontent=e,e.includes("<div data-component")||(e=`<div data-component="${this.name}">${e}</div>`),markdown(e.replace(/\\n/g,"\n").trim())}html(e,...t){let s=setInterval((()=>{document.querySelector(`[data-component="${this.name}"]`)&&(clearInterval(s),this.componentMounted=!0,document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((e=>{e.hasAttribute("ref")&&(this.dom[e.getAttribute("ref")]=e)})),this.componentDidMount())}),100),r=document.createElement("script");r.setAttribute("type","text/javascript"),r.setAttribute("data-component-script",this.name);this.dom;if(this.cfr){worker.postMessage({strings:e,args:t,location:window.location.origin+window.location.pathname.replace(/\/[^\/]*$/,"")+"/public/",name:this.name});let s=new Promise(((e,t)=>{worker.onmessage=t=>{if(t.data.error)throw new Error(t.data.error);this.dom;console.log(this.dom);let s=t.data.js,r=t.data.template;const n=this.useState.bind(this),i=this.useEffect.bind(this),a=this.useReducer.bind(this),o=this.useAuth.bind(this),c=this.useSyncStore.bind(this),l=this.signal.bind(this),u=this.$Function.bind(this);let h=this.states;const d=this.useRef.bind(this);new Function("useState","useEffect","useAuth","useReducer","useSyncStore","signal","rf","dom","render","states","useRef",s)(n,i,o,a,c,l,u,this.dom,this.render,this.states,d),e(new Function("useRef","states","return`"+r+"`")(d,h))},worker.onerror=e=>{t(e)}}));return s}{let s="";for(let r=0;r<e.length;r++)s+=e[r],r<t.length&&(s+=t[r]);return s=new Function("useRef",`return \`${s}\``)(useRef),s.trim().startsWith("<body>")||console.warn("You should wrap your html in a body tag, vader may not grab all html!"),this.parseHTML(s)}}async render(e){}}const Vader={Component:Component,useRef:useRef};export const component=e=>new Component;export const rf=(e,t)=>{window[e]=t};let cache={};async function handletemplate(e){let t=(new DOMParser).parseFromString(e,"text/html"),s=t.documentElement.querySelectorAll("*");if(s.length>0)for(var r=0;r<s.length;r++)if("INCLUDE"===s[r].nodeName){if(!s[r].getAttribute("src")||""===s[r].getAttribute("src"))throw new Error("Include tag must have src attribute");let e=s[r].getAttribute("src")?.split("/").pop()?.split(".")[0],n=await include(s[r].getAttribute("src"));n=n.replace(/`/g,"\\`"),cache[s[r].getAttribute("src")]=n,n=new Function(`return \`${n}\`;`)();let i=(new DOMParser).parseFromString(n,"text/html");i.querySelectorAll("include").forEach((e=>{e.remove()})),t.querySelectorAll(e).forEach((e=>{if(e.attributes.length>0)for(var s=0;s<e.attributes.length;s++)i.body.outerHTML=i.body.outerHTML.replace(`{{${e.attributes[s].name}}}`,e.attributes[s].value);if(e.children.length>0&&i.body.querySelector("slot"))for(s=0;s<e.children.length;s++){i.body.querySelectorAll("slot").forEach((t=>{t.getAttribute("id")===e.nodeName.toLowerCase()&&(t.outerHTML=`<div>${e.innerHTML}</div>`)}))}t.body.querySelectorAll("include").forEach((e=>{e.remove()})),t.body.outerHTML=t.body.outerHTML.replace(/`/g,"\\`"),t.body.outerHTML=t.body.outerHTML.replace(e.outerHTML,new Function(`return \`${i.body.outerHTML}\`;`)())}))}return t.body.outerHTML=t.body.outerHTML.replace(/`/g,"\\`"),e=new Function(`return \`${t.body.outerHTML}\`;`)()}export const include=async e=>(!e.startsWith("/")||e.includes("/src/")||document.documentElement.outerHTML.trim().includes("\x3c!-- #vader-disable_relative-paths --\x3e")||(e="/src/"+e),cache[e]?await handletemplate(new Function(`return \`${cache[e]}\`;`)()):fetch(`./${e}`).then((t=>{if(404===t.status)throw new Error(`No file found at ${e}`);return t.text()})).then((async t=>(cache[e]=t,t=await handletemplate(new Function(`return \`${t}\`;`)())))));export default Vader;
package/vader.js CHANGED
@@ -1,4 +1,4 @@
1
- let dom = /**@type {Obect} **/ {};
1
+ let dom = []
2
2
  let states = {};
3
3
  let worker = new Worker(new URL('./worker.js', import.meta.url));
4
4
  /**
@@ -7,125 +7,65 @@ let worker = new Worker(new URL('./worker.js', import.meta.url));
7
7
  * @description Allows you to convert markdown to html
8
8
  */
9
9
  function markdown(content) {
10
- const lines = content.split('\n').filter((line) => line !== '').map((line) => line.trim());
11
-
12
- let result = '';
13
-
14
- lines.forEach((line) => {
15
- let heading = line.match(/^#{1,6}\s/);
16
- let bold = line.match(/\*\*(.*?)\*\*/g);
17
- let italic = line.match(/\*(.*?)\*/g);
18
-
19
- let link = line.match(/\[(.*?)\]\((.*?)\)/g);
20
- let ul = line.match(/^\-\s/);
21
- let ol = line.match(/^\d\.\s/);
22
10
 
23
- let li = line.match(/^\s/);
24
- let hr = line.match(/^\-\-\-\s/);
25
- let blockquote = line.match(/^\>\s/);
26
- let image = line.match(/\!\[(.*?)\]\((.*?)\)/g);
27
-
28
-
29
- let codeBlock = line.match(/\`\`\`/g);
30
- let codeBlockEnd = line.match(/\`\`\`/g);
31
- let code = line.match(/\`(.*?)\`/g);
32
-
11
+ let headers = content.match(/(#+)(.*)/g);
12
+ if (headers) {
13
+ headers.forEach((header) => {
14
+ if(header.includes('/') || header.includes('<') || header.includes('>')){
15
+ return
33
16
 
34
-
35
- if (heading) {
36
- // @ts-ignore
37
- let headingLevel = heading[0].match(/#/g).length;
38
- line = line.replace(heading[0], `<h${headingLevel}>`);
39
- line += `</h${headingLevel}>`;
40
- }
41
- if (bold) {
42
- bold.forEach((b) => {
43
- line = line.replace(b, `<strong
44
- className="$vader_markdown_bold"
45
- >${b.replace(/\*\*/g, "")}</strong>`);
46
- });
47
- }
48
- if (italic) {
49
- italic.forEach((i) => {
50
- line = line.replace(i, `<em
51
- className="$vader_markdown_italic"
52
- >${i.replace(/\*/g, "")}</em>`);
53
- });
54
- }
17
+ }
18
+ let level = header.split('#').length;
19
+ content = content.replace(header, `<h${level} class="markdown_heading">${header.replace(/#/g, '')}</h${level}>`);
20
+ });
21
+ }
55
22
 
56
-
57
- if(link){
58
- link.forEach((l) => {
59
- // @ts-ignore
60
- let text = l.match(/\[(.*?)\]/g)[0].replace(/\[|\]/g, "");
61
- // @ts-ignore
62
- let href = l.match(/\((.*?)\)/g)[0].replace(/\(|\)/g, "");
63
- line = line.replace(l, `<a
64
- className="$vader_markdown_link"
65
- href="${href}">${text}</a>`);
66
- });
67
- }
68
- if (ul) {
69
- line = line.replace(ul[0], `<li
70
- className="$vader_markdown_ul"
71
- style="list-style-type: disc;">`);
72
- line += `</li>`;
73
- }
74
- if (ol) {
75
- line = line.replace(ol[0], `<li
76
- className="$vader_markdown_ol"
77
- style="list-style-type: decimal;">`);
78
- line += `</li>`;
79
- }
80
- if (hr) {
81
- line = line.replace(hr[0], `<hr/>`);
82
- }
83
- if (blockquote) {
84
- line = line.replace(blockquote[0], `<blockquote
85
- className="$vader_markdown_blockquote"
86
- >`);
87
- line += `</blockquote>`;
88
- }
89
- if (image) {
90
- image.forEach((i) => {
91
- // @ts-ignore
92
- let alt = i.match(/\[(.*?)\]/g)[0].replace(/\[|\]/g, "");
93
- // @ts-ignore
94
- let src = i.match(/\((.*?)\)/g)[0].replace(/\(|\)/g, "");
95
- i.replace(i, `<img src="${src}" alt="${alt}"/>`);
96
- line = line.replace(i, `<img
97
- className="$vader_markdown_image"
98
- src="${src}" alt="${alt}"/>`).replace('!','')
99
- });
100
- }
101
- if (li) {
102
- line = line.replace(li[0], `<li>`);
103
- line += `</li>`;
104
- }
105
- if (codeBlock) {
106
- line = line.replace(codeBlock[0], `<pre className="$vader_markdown_code_block" ><code>`);
107
- }
108
- if (codeBlockEnd) {
109
- line = line.replace(codeBlockEnd[0], `</code></pre>`);
23
+ content = content.replace(/\*\*(.*?)\*\*/g, (match, text) => {
24
+ return `<b class="markdown_bold">${text}</b>`;
25
+ });
26
+ content = content.replace(/\*(.*?)\*/g, (match, text) => {
27
+ return `<i class="markdown_italic">${text}</i>`;
28
+ })
29
+ content = content.replace(/`(.*?)`/g, (match, text) => {
30
+ return `<code>${text}</code>`;
31
+ });
32
+ content = content.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (match, text, url) => {
33
+ return `<a class="markdown_link" href="${url}">${text}</a>`;
34
+ });
35
+ content = content.replace(/!\[([^\]]+)\]\(([^)]+)\)/g, (match, alt, src) => {
36
+ return `<img class="markdown_image" src="${src}" alt="${alt}" />`;
37
+ });
38
+ content = content.split('\n').map((line, index, arr) => {
39
+ if (line.match(/^\s*-\s+(.*?)$/gm)) {
40
+ if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) {
41
+ return `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`;
42
+ } else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*-\s+(.*?)$/gm)) {
43
+ return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li></ul>`;
44
+ } else {
45
+ return `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`;
46
+ }
47
+ } else {
48
+ return line;
110
49
  }
50
+ }).join('\n');
111
51
 
112
- if (code) {
113
- code.forEach((c) => {
114
- line = line.replace(c, `<code
115
- className="$vader_markdown_code"
116
- style="background-color: #f5f5f5; padding: 5px; border-radius: 5px;
117
- "
118
- >${c.replace(/\`/g, "")}</code>`);
119
- });
52
+ content = content.split('\n').map((line, index, arr) => {
53
+ if (line.match(/^\s*\d+\.\s+(.*?)$/gm)) {
54
+ if (index === 0 || !arr[index - 1].match(/^\s*\d+\.\s+(.*?)$/gm)) {
55
+ return `<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li>`;
56
+ } else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*\d+\.\s+(.*?)$/gm)) {
57
+ return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li></ol>`;
58
+ } else {
59
+ return `<li>${line.replace(/^\s*\d+\.\s+(.*?)$/gm, '$1')}</li>`;
60
+ }
61
+ } else {
62
+ return line;
120
63
  }
121
-
122
-
64
+ }).join('\n');
123
65
 
124
66
 
125
- result += `${line}\n`;
126
- });
127
-
128
- return result;
67
+ return content
68
+
129
69
  }
130
70
 
131
71
 
@@ -208,6 +148,13 @@ export class Component {
208
148
  },
209
149
  });
210
150
  this.snapshots = [];
151
+ /**
152
+ * @property {Object} dom
153
+ * @description Allows you to get reference to DOM element
154
+ * @returns {void | HTMLElement}
155
+ *
156
+ */
157
+ this.dom = []
211
158
 
212
159
  /**
213
160
  * @property {Boolean} cfr
@@ -562,6 +509,8 @@ export class Component {
562
509
  },
563
510
  ];
564
511
  }
512
+
513
+
565
514
  runEffects() {
566
515
  Object.keys(this.effects).forEach((component) => {
567
516
  this.effects[component].forEach((effect) => {
@@ -572,6 +521,7 @@ export class Component {
572
521
  });
573
522
  });
574
523
  }
524
+
575
525
  /**
576
526
  * @method useSyncStore
577
527
  * @description Allows you to create a store
@@ -660,8 +610,50 @@ export class Component {
660
610
  },
661
611
  ];
662
612
  }
613
+ /**
614
+ * @method useRef
615
+ * @memberof Component
616
+ * @param {string} ref
617
+ * @description Allows you to get reference to DOM elements from the dom array
618
+ * @returns {Object} {current, update}
619
+ * @example
620
+ * let ref = this.useRef('ref')
621
+ * ref.current // returns the DOM element
622
+
623
+ */
624
+
625
+ useRef(ref) {
626
+ // get ref from array
627
+ console.log(this.dom)
628
+ const element = this.dom[ref]
629
+
630
+ const getElement = () => element;
631
+
632
+ const update = (data) => {
633
+ const newDom = new DOMParser().parseFromString(data, "text/html");
634
+ const newElement = newDom.body.firstChild;
635
+
636
+ if (element) {
637
+ // @ts-ignore
638
+ const isDifferent = !newElement.isEqualNode(element);
639
+ if (isDifferent) {
640
+ // @ts-ignore
641
+ element.parentNode.replaceChild(newElement, element);
642
+ }
643
+ }
644
+ };
645
+
646
+ return {
647
+ /**@type {HTMLElement} */
648
+ // @ts-ignore
649
+ current: getElement,
650
+ /**@type {Function} */
651
+ update,
652
+ };
653
+ }
663
654
 
664
655
  /**
656
+ *
665
657
  * @function useEffect
666
658
  * @param {*} effectFn
667
659
  * @param {*} dependencies
@@ -726,11 +718,12 @@ export class Component {
726
718
  const fragment = document.createDocumentFragment();
727
719
  Object.keys(components).forEach(async (component) => {
728
720
  const { name } = components[component];
729
- const componentContainer = document.querySelector(
721
+
722
+
723
+ let componentContainer = document.querySelector(
730
724
  `[data-component="${name}"]`
731
725
  );
732
-
733
- let time = new Date().getTime().toLocaleString();
726
+ let time = new Date().getTime();
734
727
  /**
735
728
  * @property {Object} snapshot
736
729
  * @description Allows you to keep track of component snapshots
@@ -989,22 +982,28 @@ export class Component {
989
982
 
990
983
  html(strings, ...args) {
991
984
  // @ts-ignore
992
- if (
993
- // @ts-ignore
994
- new Error().stack &&
995
- // @ts-ignore
996
- new Error().stack.split("\n").length > 0 &&
997
- // @ts-ignore
998
- new Error().stack.split("\n")[2] &&
999
- // @ts-ignore
1000
- new Error().stack.split("\n")[2].includes("render") &&
1001
- !this.componentMounted
1002
- ) {
1003
- this.componentMounted = true;
1004
- this.componentDidMount();
1005
- }
985
+ let tiemr = setInterval(()=>{
986
+ if(document.querySelector(`[data-component="${this.name}"]`)){
987
+ clearInterval(tiemr)
988
+ this.componentMounted = true;
989
+
990
+ document.querySelector(`[data-component="${this.name}"]`)?.querySelectorAll("*").forEach((element)=>{
991
+ if(element.hasAttribute("ref")){
992
+ // @ts-ignore
993
+ this.dom[element.getAttribute("ref")] = element
994
+ }
995
+ })
996
+ this.componentDidMount();
997
+ }
998
+ }, 100)
999
+ let script = document.createElement("script");
1000
+ script.setAttribute("type", "text/javascript");
1001
+ script.setAttribute(`data-component-script`, this.name);
1002
+
1006
1003
 
1007
1004
 
1005
+ let dom = this.dom
1006
+
1008
1007
  if(this.cfr){
1009
1008
 
1010
1009
  worker.postMessage({strings, args, location: window.location.origin + window.location.pathname.replace(/\/[^\/]*$/, '') + '/public/', name: this.name})
@@ -1013,11 +1012,39 @@ export class Component {
1013
1012
  if(e.data.error){
1014
1013
  throw new Error(e.data.error)
1015
1014
  }
1016
-
1017
-
1018
- resolve(new Function("useRef", `return \`${e.data}\``)(useRef))
1015
+ const dom = this.dom; // Assuming this.dom is an object
1016
+ console.log(this.dom)
1017
+ let js = e.data.js
1018
+ let template = e.data.template
1019
+ // Bind the component's context
1020
+
1021
+ const useState = this.useState.bind(this); // Bind the component's context
1022
+ const useEffect = this.useEffect.bind(this); // Bind the component's context
1023
+ const useReducer = this.useReducer.bind(this); // Bind the component's context
1024
+ const useAuth = this.useAuth.bind(this); // Bind the component's context
1025
+ const useSyncStore = this.useSyncStore.bind(this); // Bind the component's context
1026
+ const signal = this.signal.bind(this); // Bind the component's context
1027
+ const rf = this.$Function.bind(this); // Bind the component's context
1028
+ let states = this.states
1029
+ const useRef = this.useRef.bind(this); // Bind the component's context
1030
+ new Function("useState", "useEffect", "useAuth", "useReducer", "useSyncStore", "signal", "rf", "dom", "render", "states", "useRef", js)(
1031
+ useState,
1032
+ useEffect,
1033
+ useAuth,
1034
+ useReducer,
1035
+ useSyncStore,
1036
+ signal,
1037
+ rf,
1038
+ this.dom,
1039
+ this.render,
1040
+ this.states,
1041
+ useRef
1042
+ )
1043
+
1044
+ resolve(new Function("useRef", "states", "return" + "`" + template + "`")(useRef, states))
1019
1045
 
1020
1046
 
1047
+
1021
1048
 
1022
1049
  }
1023
1050
  worker.onerror = (e)=>{
package/worker-min.js ADDED
@@ -0,0 +1 @@
1
+ onmessage=e=>{let a=Date.now(),l=e.data.strings,s=e.data.args,t="",r=e.data.location.split("/").slice(0,-1).join("/"),c="";for(let e=0;e<l.length;e++)c+=l[e],e<s.length&&(c+=s[e]);let o=c.match(/--([^>]*)--/gs);if(o)for(;o.length;){let e=o.pop();console.log(e),c=c.replace(e,"")}if(c=c.replace(/(#+)(.*)/g,((e,a,l)=>{if(console.log(e),e.includes("<")&&e.includes(">"))return e;{let e=a.length;return`<h ${e} class="markdown_heading">${l}</h${e}>`}})),c=c.replace(/\*\*(.*?)\*\*/g,((e,a)=>`<b class="markdown_bold">${a}</b>`)),c=c.replace(/\*(.*?)\*/g,((e,a)=>`<i class="markdown_italic">${a}</i>`)),c=c.replace(/`(.*?)`/g,((e,a)=>`<code>${a}</code>`)),c=c.replace(/\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<a class="markdown_link" href="${l}">${a}</a>`)),c=c.replace(/!\[([^\]]+)\]\(([^)]+)\)/g,((e,a,l)=>`<img class="markdown_image" src="${l}" alt="${a}" />`)),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*-\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*-\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*-\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li></ul>`):c.replace(e,`<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${e.replace(/^\s*-\s+(.*?)$/gm,"$1")}</li>`))})),c.split("\n").forEach(((e,a,l)=>{e.match(/^\s*\d+\.\s+(.*?)$/gm)&&(c=0!==a&&l[a-1].match(/^\s*\d+\.\s+(.*?)$/gm)?a!==l.length-1&&l[a+1].match(/^\s*\d+\.\s+(.*?)$/gm)?c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`):c.replace(e,`<li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li></ol>`):c.replace(e,`<ol class="markdown_ordered" style="list-style-type:decimal;"><li>${e.replace(/^\s*\d+\.\s+(.*?)$/gm,"$1")}</li>`))})),c=c.replace(/^\s*-\s+(.*?)$/gm,((e,a)=>`<li class="markdown_list_item">${a}</li>`)),c=c.replace(/^\s*---\s*$/gm,'<hr class="markdown_horizontal" />'),c=c.replace(/^\s*> (.*)$/gm,((e,a)=>`<blockquote class="markdown_blockquote">${a}</blockquote>`)),c=c.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm,((e,a,l)=>{const s=a.split("|").slice(1,-1),t=l.split("|").slice(1,-1);let r='<table class="markdown_table">';return r+='<thead class="markdown_table_head"><tr class="markdown_table_row">',s.forEach((e=>{r+=`<th class="markdown_table_header_cell">${e}</th>`})),r+='</tr></thead><tbody class="markdown_table_body"><tr class="markdown_table_row">',t.forEach((e=>{r+=`<td class="markdown_table_body_cell">${e}</td>`})),r+="</tr></tbody></table>",r})),!c.includes("<body>"))throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${c}`);c=c.replace(/classname/g,"class");let n=c.match(/<img([^>]*)>/g);if(n)for(let a=0;a<n.length;a++){let l=n[a],s=l.match(/src="([^"]*)"/),t=l.match(/alt="([^"]*)"/);if(s){if(s[1].includes("http")&&c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use relative paths in the src attribute of ${s[0]}. Use absolute paths instead. \n\n${s[0]}`);c=c.replace(s[1],`${r}/${s[1]}`)}if(!t&&!c.includes("\x3c!-- #vader-disable_accessibility --\x3e"))throw new Error(`Vader Error: You must include an alt attribute in the image tag \n\n${l} of class ${e.data.name}. `);caches.match(`${r}/${s[1]}`)?console.log("already cached",caches.match(`${r}/${s[1]}`)):caches.open("vader").then((e=>{e.add(`${r}/${s[1]}`),console.log("cached",`${r}/${s[1]}`)})).catch((e=>{console.log(e)}))}let i=c.match(/href="([^"]*)"/g);if(i)for(;i.length;){let a=i.pop();if(a=a.replace('href="',"").replace('"',""),a.includes("http")&&c.includes("\x3c!-- #vader-disable_relative-paths --\x3e"))throw new Error(`Vader Error: You cannot use relative paths in ${e.data.file}. Use absolute paths instead. \n\n${a}`);c=c.replace(`href="${a}"`,`href="#${a}"`)}let d=Date.now()-a,$=!1;(r.includes("localhost")||r.includes("127.0.0.1")&&!$)&&($=!0,c+=`\${console.log('%c${e.data.name} component rendered in ${d}ms','color:#fff;background:#000;padding:5px;border-radius:5px;font-size:12px;font-weight:bold'),""}`);const h=c.split("<script>");h&&h.forEach(((e,a)=>{if(0===a)c=e;else{if(e.includes("// <![CDATA[ <-- For SVG support"))return;let a=e.split("<\/script>")[0];t+=a}}));let p=c.match(/(\$\(.*?\))/gs);if(p)for(;p.length;){let e=p.pop();c=c.replace(e,`\${${e.replace("$(","").replace(")","")}}`)}postMessage({template:`<div data-component=${e.data.name}>${c}</div>`,js:t||""})};
package/worker.js CHANGED
@@ -3,6 +3,7 @@ onmessage = (e)=>{
3
3
  let time_started = Date.now()
4
4
  let strings = e.data.strings
5
5
  let args = e.data.args
6
+ let js = ''
6
7
  let l = e.data.location.split('/').slice(0,-1).join('/')
7
8
  let result = "";
8
9
  for (let i = 0; i < strings.length; i++) {
@@ -26,9 +27,12 @@ onmessage = (e)=>{
26
27
  // Convert headings (e.g., #1-6 Heading => <h1-6>Heading</h1-6>)
27
28
  // @ts-ignore
28
29
  result = result.replace(/(#+)(.*)/g, (match, hashes, text) => {
29
- if(!match.includes('<')){
30
+ console.log(match)
31
+ if(!match.includes('<') || !match.includes('>')){
30
32
  let level = hashes.length;
31
- return `<h ${level} class="markdown_heading">${text}</h${level}>`;
33
+ return `<h ${level} class="markdown_heading">${text}</h${level}>`;
34
+ }else{
35
+ return match
32
36
  }
33
37
  });
34
38
 
@@ -62,7 +66,7 @@ onmessage = (e)=>{
62
66
  result.split('\n').forEach((line, index, arr) => {
63
67
  if (line.match(/^\s*-\s+(.*?)$/gm)) {
64
68
  if (index === 0 || !arr[index - 1].match(/^\s*-\s+(.*?)$/gm)) {
65
- result = result.replace(line, `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside;"><li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`);
69
+ result = result.replace(line, `<ul class="markdown_unordered" style="list-style-type:disc;list-style:inside"><li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li>`);
66
70
  } else if (index === arr.length - 1 || !arr[index + 1].match(/^\s*-\s+(.*?)$/gm)) {
67
71
  result = result.replace(line, `<li>${line.replace(/^\s*-\s+(.*?)$/gm, '$1')}</li></ul>`);
68
72
  } else {
@@ -70,8 +74,7 @@ onmessage = (e)=>{
70
74
  }
71
75
  }
72
76
  });
73
-
74
-
77
+
75
78
  // Convert ordered lists (e.g., 1. Item => <ol><li>Item</li></ol>) in order
76
79
 
77
80
  result.split('\n').forEach((line, index, arr) => {
@@ -91,10 +94,30 @@ onmessage = (e)=>{
91
94
  return `<li class="markdown_list_item">${text}</li>`;
92
95
  });
93
96
  result = result.replace(/^\s*---\s*$/gm, '<hr class="markdown_horizontal" />');
94
-
97
+
98
+ // Convert blockquotes (e.g., > Quote => <blockquote>Quote</blockquote>)
99
+ result = result.replace(/^\s*> (.*)$/gm, (match, text) => {
100
+ return `<blockquote class="markdown_blockquote">${text}</blockquote>`;
101
+ });
102
+
103
+ // Convert tables (e.g., | Header | Cell | => <table><thead><tr><th>Header</th><th>Cell</th></tr></thead></table>)
104
+ result = result.replace(/((?: *\|.*?)+)\n((?: *\|.*?)+)/gm, (match, header, cell) => {
105
+ const headerCells = header.split('|').slice(1, -1);
106
+ const cells = cell.split('|').slice(1, -1);
107
+ let table = '<table class="markdown_table">';
108
+ table += '<thead class="markdown_table_head"><tr class="markdown_table_row">';
109
+ headerCells.forEach((headerCell) => {
110
+ table += `<th class="markdown_table_header_cell">${headerCell}</th>`;
111
+ });
112
+ table += '</tr></thead><tbody class="markdown_table_body"><tr class="markdown_table_row">';
113
+ cells.forEach((cell) => {
114
+ table += `<td class="markdown_table_body_cell">${cell}</td>`;
115
+ });
116
+ table += '</tr></tbody></table>';
117
+ return table;
118
+ });
95
119
 
96
-
97
-
120
+
98
121
 
99
122
  if(!result.includes('<body>')){
100
123
  throw new Error(`Vader Error: You must enclose your html in a body tag for all components. \n\n${result}`)
@@ -168,6 +191,33 @@ onmessage = (e)=>{
168
191
  }
169
192
 
170
193
 
171
- postMessage(`<div data-component=${e.data.name}>${result}</div>`)
194
+ const d = result.split('<script>')
195
+
196
+ if (d) {
197
+ d.forEach((scriptTag, index) => {
198
+ if (index === 0) {
199
+ result = scriptTag;
200
+ } else {
201
+ if(scriptTag.includes('// <![CDATA[ <-- For SVG support')){
202
+ return
203
+ }
204
+ let script = scriptTag.split('</script>')[0];
205
+ js += script;
206
+ }
207
+ });
208
+ }
209
+
210
+ let jstemplates = result.match(/(\$\(.*?\))/gs)
211
+ if(jstemplates){
212
+ while(jstemplates.length){
213
+ let jstemplate = jstemplates.pop()
214
+ // @ts-ignore
215
+ result = result.replace(jstemplate,`$\{${jstemplate.replace('$(','').replace(')','')}\}`)
216
+ }
217
+ }
218
+ postMessage({
219
+ template: `<div data-component=${e.data.name}>${result}</div>`,
220
+ js: js ? js : ''
221
+ })
172
222
 
173
223
  }