lego-dom 1.3.3 → 1.3.4
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/CHANGELOG.md +6 -0
- package/docs/.vitepress/config.js +1 -2
- package/docs/guide/cdn-usage.md +39 -13
- package/docs/guide/components.md +6 -0
- package/docs/guide/sfc.md +44 -0
- package/main.min.js +7 -0
- package/package.json +3 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [1.3.4] - 2026-01-16
|
|
6
|
+
|
|
7
|
+
### Improvements
|
|
8
|
+
|
|
9
|
+
- **Minified Build:** Added a build script (`npm run build`) that uses `esbuild` to generate a `main.min.js` file, reducing file size by ~55% for optimal CDN performance.
|
|
10
|
+
|
|
5
11
|
## [1.3.3] - 2026-01-16
|
|
6
12
|
|
|
7
13
|
### Fixes
|
|
@@ -16,7 +16,7 @@ export default defineConfig({
|
|
|
16
16
|
{ text: 'Examples', link: '/examples/' },
|
|
17
17
|
{ text: 'Router', link: '/router/' },
|
|
18
18
|
{
|
|
19
|
-
text: 'v1.3.
|
|
19
|
+
text: 'v1.3.4',
|
|
20
20
|
items: [
|
|
21
21
|
{ text: 'Changelog', link: 'https://github.com/rayattack/LegoDOM/releases' }
|
|
22
22
|
|
|
@@ -69,7 +69,6 @@ export default defineConfig({
|
|
|
69
69
|
{ text: 'What is LegoDOM?', link: '/guide/' },
|
|
70
70
|
{ text: 'Getting Started', link: '/guide/getting-started' },
|
|
71
71
|
{ text: 'Quick Start', link: '/guide/quick-start' },
|
|
72
|
-
{ text: 'Contributing', link: '/guide/contributing' }
|
|
73
72
|
]
|
|
74
73
|
},
|
|
75
74
|
{
|
package/docs/guide/cdn-usage.md
CHANGED
|
@@ -39,7 +39,7 @@ That's it! Open this file in any browser and it works.
|
|
|
39
39
|
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
40
40
|
|
|
41
41
|
<!-- Specific version -->
|
|
42
|
-
<script src="https://unpkg.com/lego-dom@
|
|
42
|
+
<script src="https://unpkg.com/lego-dom@1.3.4/main.js"></script>
|
|
43
43
|
```
|
|
44
44
|
|
|
45
45
|
### jsdelivr
|
|
@@ -49,14 +49,10 @@ That's it! Open this file in any browser and it works.
|
|
|
49
49
|
<script src="https://cdn.jsdelivr.net/npm/lego-dom/main.js"></script>
|
|
50
50
|
|
|
51
51
|
<!-- Specific version -->
|
|
52
|
-
<script src="https://cdn.jsdelivr.net/npm/lego-dom@
|
|
52
|
+
<script src="https://cdn.jsdelivr.net/npm/lego-dom@1.3.4/main.js"></script>
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
### cdnjs
|
|
56
55
|
|
|
57
|
-
```html
|
|
58
|
-
<script src="https://cdnjs.cloudflare.com/ajax/libs/lego-dom/0.0.7/main.js"></script>
|
|
59
|
-
```
|
|
60
56
|
|
|
61
57
|
## Complete Example
|
|
62
58
|
|
|
@@ -246,7 +242,7 @@ Lego components work alongside other frameworks:
|
|
|
246
242
|
Always pin to a specific version:
|
|
247
243
|
|
|
248
244
|
```html
|
|
249
|
-
<script src="https://unpkg.com/lego-dom@
|
|
245
|
+
<script src="https://unpkg.com/lego-dom@1.3.4/main.js"></script>
|
|
250
246
|
```
|
|
251
247
|
|
|
252
248
|
### For Development/Prototyping
|
|
@@ -271,7 +267,7 @@ For maximum security:
|
|
|
271
267
|
|
|
272
268
|
```html
|
|
273
269
|
<script
|
|
274
|
-
src="https://unpkg.com/lego-dom@
|
|
270
|
+
src="https://unpkg.com/lego-dom@1.3.4/main.js"
|
|
275
271
|
integrity="sha384-..."
|
|
276
272
|
crossorigin="anonymous">
|
|
277
273
|
</script>
|
|
@@ -288,9 +284,42 @@ Lego works in all modern browsers:
|
|
|
288
284
|
|
|
289
285
|
No polyfills needed for these browsers!
|
|
290
286
|
|
|
287
|
+
## Using .lego Files without Build Tools
|
|
288
|
+
|
|
289
|
+
You can use full Single File Components (`.lego` files) directly in the browser without any build step!
|
|
290
|
+
Lego provides a `loader` configuration that lets you fetch component files on demand.
|
|
291
|
+
|
|
292
|
+
### How it Works
|
|
293
|
+
|
|
294
|
+
1. **Serve your files**: Make sure your `.lego` files are accessible via HTTP (e.g., in a `/components` folder).
|
|
295
|
+
2. **Configure the loader**: Tell Lego how to fetch a component when it encounters an unknown tag.
|
|
296
|
+
|
|
297
|
+
### Example
|
|
298
|
+
|
|
299
|
+
```html
|
|
300
|
+
<script>
|
|
301
|
+
Lego.init(document.body, {
|
|
302
|
+
// The loader function receives the tag name (e.g., 'user-card')
|
|
303
|
+
// and must return a Promise that resolves to the component's source code.
|
|
304
|
+
loader: (tagName) => {
|
|
305
|
+
// Fetch the raw text content of the .lego file
|
|
306
|
+
return fetch(`/components/${tagName}.lego`).then(res => res.text());
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
</script>
|
|
310
|
+
|
|
311
|
+
<!-- Now just use the tag! Lego will fetch, compile, and render it automatically. -->
|
|
312
|
+
<user-card></user-card>
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
This is perfect for:
|
|
316
|
+
- **Micro-frontends**: Load components from different services.
|
|
317
|
+
- **CMS Integration**: Store component code in a database.
|
|
318
|
+
- **Dynamic Apps**: Load features only when they are needed.
|
|
319
|
+
|
|
291
320
|
## Pros and Cons
|
|
292
321
|
|
|
293
|
-
###
|
|
322
|
+
### Advantages
|
|
294
323
|
|
|
295
324
|
- **No build step** - Instant development
|
|
296
325
|
- **No npm** - No dependency management
|
|
@@ -298,11 +327,8 @@ No polyfills needed for these browsers!
|
|
|
298
327
|
- **Progressive enhancement** - Add to existing sites easily
|
|
299
328
|
- **Low barrier** - Great for beginners
|
|
300
329
|
|
|
301
|
-
###
|
|
330
|
+
### Limitations
|
|
302
331
|
|
|
303
|
-
- No tree-shaking (you get the whole library)
|
|
304
|
-
- No TypeScript compilation
|
|
305
|
-
- No `.lego` SFC support
|
|
306
332
|
- No hot module replacement
|
|
307
333
|
- Slower for large apps compared to bundled versions
|
|
308
334
|
|
package/docs/guide/components.md
CHANGED
|
@@ -6,6 +6,12 @@ Learn how to create and use components in Lego.
|
|
|
6
6
|
|
|
7
7
|
A component is a reusable, self-contained piece of UI with its own template, styles, and logic.
|
|
8
8
|
|
|
9
|
+
|
|
10
|
+
::: warning Note That
|
|
11
|
+
`style` tags inside NON SFC components are inside the `<template>` tag. And outside the tag in SFCs.
|
|
12
|
+
:::
|
|
13
|
+
|
|
14
|
+
|
|
9
15
|
```html
|
|
10
16
|
<template b-id="user-badge">
|
|
11
17
|
<style>
|
package/docs/guide/sfc.md
CHANGED
|
@@ -310,6 +310,50 @@ Scoped styles using Shadow DOM. Use `self` to target the component root:
|
|
|
310
310
|
|
|
311
311
|
Styles are automatically scoped to your component—they won't affect other components or global styles.
|
|
312
312
|
|
|
313
|
+
## Dynamic Styles
|
|
314
|
+
|
|
315
|
+
A powerful feature of LegoDOM SFCs is that **interpolation works inside `<style>` tags too!**
|
|
316
|
+
|
|
317
|
+
You can use `[[ ]]` to bind CSS values directly to your component's state, props, or logic. Because styles are scoped (Shadow DOM), this is safe and won't leak.
|
|
318
|
+
|
|
319
|
+
```html
|
|
320
|
+
<template>
|
|
321
|
+
<button @click="toggleTheme()">Toggle Theme</button>
|
|
322
|
+
</template>
|
|
323
|
+
|
|
324
|
+
<style>
|
|
325
|
+
/* Use state variables directly in CSS */
|
|
326
|
+
self {
|
|
327
|
+
background-color: [[ theme === 'dark' ? '#333' : '#fff' ]];
|
|
328
|
+
color: [[ theme === 'dark' ? '#fff' : '#000' ]];
|
|
329
|
+
|
|
330
|
+
/* You can also bind strict values for calculation */
|
|
331
|
+
--padding: [[ basePadding + 'px' ]];
|
|
332
|
+
padding: var(--padding);
|
|
333
|
+
}
|
|
334
|
+
</style>
|
|
335
|
+
|
|
336
|
+
<script>
|
|
337
|
+
export default {
|
|
338
|
+
theme: 'light',
|
|
339
|
+
basePadding: 20,
|
|
340
|
+
|
|
341
|
+
toggleTheme() {
|
|
342
|
+
this.theme = this.theme === 'light' ? 'dark' : 'light';
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
</script>
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
::: tip Why this rocks 🤘
|
|
349
|
+
This eliminates the need for CSS-in-JS libraries. You get full reactivity in your CSS with standard syntax.
|
|
350
|
+
:::
|
|
351
|
+
|
|
352
|
+
::: warning Performance Note
|
|
353
|
+
Binding to CSS properties works great for themes, settings, and layout changes.
|
|
354
|
+
For high-frequency updates (like drag-and-drop coordinates or 60fps animations), prefer binding to **CSS Variables** on the host element (`style="--x: [[ x ]]"`) to avoid re-parsing the stylesheet on every frame.
|
|
355
|
+
:::
|
|
356
|
+
|
|
313
357
|
## Hot Module Replacement
|
|
314
358
|
|
|
315
359
|
During development, changes to `.lego` files trigger a full page reload. Your changes appear instantly!
|
package/main.min.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
const Lego=(()=>{const w={},M=new WeakMap,k=new WeakMap,O=new WeakMap,$=new Set,P=new Map,B=new Map,H=new Map,q=new Map;let G={};const p={onError:(e,s,c)=>{console.error(`[Lego Error] [${s}]`,e,c)},metrics:{},syntax:"brackets"},_=()=>p.syntax==="brackets"?["[[","]]"]:["{{","}}"],L=()=>{const[e,s]=_(),c=e.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),o=s.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");return new RegExp(`${c}(.*?)${o}`,"g")},R=[],ee=e=>typeof e!="string"?e:e.replace(/[&<>"']/g,s=>({"&":"&","<":"<",">":">",'"':""","'":"'"})[s]),K=e=>{const c=e.split("/").pop().replace(/\.lego$/,"").replace(/_/g,"-").replace(/([a-z])([A-Z])/g,"$1-$2").toLowerCase();if(!c.includes("-"))throw new Error(`[Lego] Invalid component definition: "${e}". Component names must contain a hyphen (e.g. user-card.lego or UserCard.lego).`);return c},V=(e,s)=>{if(typeof e=="function"){const o=Array.from(document.querySelectorAll("*")).filter(t=>t.tagName.includes("-"));return[].concat(e(o))}if(e.startsWith("#")){const o=document.getElementById(e.slice(1));return o?[o]:[]}const c=s?.querySelectorAll(e)||[];return c.length>0?[...c]:[...document.querySelectorAll(e)]},j=(e,...s)=>c=>{const o=async(t,a=null,r=!0,n={})=>{if(r){const d={legoTargets:s.filter(i=>typeof i=="string"),method:t,body:a};history.pushState(d,"",e)}await F(s.length?s:null,c)};return{get:(t=!0,a={})=>o("GET",null,t,a),post:(t,a=!0,r={})=>o("POST",t,a,r),put:(t,a=!0,r={})=>o("PUT",t,a,r),patch:(t,a=!0,r={})=>o("PATCH",t,a,r),delete:(t=!0,a={})=>o("DELETE",null,t,a)}},J=(()=>{let e=!1;const s=new Set;let c=!1;return{add:o=>{!o||c||(s.add(o),!e&&(e=!0,requestAnimationFrame(()=>{c=!0;const t=Array.from(s);s.clear(),e=!1,t.forEach(a=>C(a)),setTimeout(()=>{t.forEach(a=>{const r=a._studs;if(r&&typeof r.updated=="function")try{r.updated.call(r)}catch(n){console.error("[Lego] Error in updated hook:",n)}}),c=!1},0)})))}}})(),S=(e,s,c=J)=>{if(e===null||typeof e!="object"||e instanceof Node)return e;if(M.has(e))return M.get(e);const o={get:(a,r)=>{const n=Reflect.get(a,r);return n!==null&&typeof n=="object"&&!(n instanceof Node)?S(n,s,c):n},set:(a,r,n)=>{const l=a[r],d=Reflect.set(a,r,n);return l!==n&&c.add(s),d},deleteProperty:(a,r)=>{const n=Reflect.deleteProperty(a,r);return c.add(s),n}},t=new Proxy(e,o);return M.set(e,t),t},I=e=>{try{return new Function(`return (${e})`)()}catch(s){return console.error("[Lego] Failed to parse b-data:",e,s),{}}},N=e=>(k.has(e)||k.set(e,{snapped:!1,bindings:null,bound:!1,rendering:!1,anchor:null,hasGlobalDependency:!1}),k.get(e)),D=(e,s)=>{if(!e)return"";const c=e.trim().split(".");let o=s;for(const t of c){if(o==null)return"";o=o[t]}return o??""},Z=(e,s)=>{let c=e.parentElement||e.getRootNode().host;for(;c;){if(c.tagName&&c.tagName.toLowerCase()===s.toLowerCase())return c._studs;c=c.parentElement||c.getRootNode&&c.getRootNode().host}},h=(e,s,c=!1)=>{if(/\b(function|eval|import|class|module|deploy|constructor|__proto__)\b/.test(e)){console.warn(`[Lego] Security Warning: Blocked dangerous expression "${e}"`);return}try{const o=s.state||{};let t=H.get(e);t||(t=new Function("global","self","event","helpers",`
|
|
2
|
+
with(helpers) {
|
|
3
|
+
with(this) {
|
|
4
|
+
return ${e}
|
|
5
|
+
}
|
|
6
|
+
}
|
|
7
|
+
`),H.set(e,t));const a={$ancestors:n=>Z(s.self,n),$registry:n=>B.get(n.toLowerCase()),$element:s.self,$route:Lego.globals.$route,$go:(n,...l)=>j(n,...l)(s.self),$emit:(n,l)=>{s.self.dispatchEvent(new CustomEvent(n,{detail:l,bubbles:!0,composed:!0}))}},r=t.call(o,s.global,s.self,s.event,a);return typeof r=="function"?r.call(o,s.event):r}catch(o){if(c)throw o;p.onError(o,"render-error",s.self);return}},z=(e,s)=>{if(e.type==="checkbox")e.checked!==!!s&&(e.checked=!!s);else{const c=s==null?"":String(s);e.value!==c&&(e.value=c)}},x=(e,s,c=null)=>{const o=s._studs,t=n=>{const l=N(n);if(!l.bound){if(n.hasAttributes()){const d=n.attributes;for(let i=0;i<d.length;i++){const u=d[i];if(u.name.startsWith("@")){const f=u.name.slice(1);n.addEventListener(f,g=>{try{let m=o;if(c){const y=h(c.listName,{state:o,global:Lego.globals,self:s})[c.index];m=Object.assign(Object.create(o),{[c.name]:y})}h(u.value,{state:m,global:Lego.globals,self:n,event:g},!0)}catch(m){p.onError(m,"event-handler",n)}})}}if(n.hasAttribute("b-sync")){const i=n.getAttribute("b-sync"),u=()=>{try{let f,g;if(c&&i.startsWith(c.name+".")){const y=h(c.listName,{state:o,global:Lego.globals,self:s})[c.index];if(!y)return;const E=i.split(".").slice(1);g=E.pop(),f=E.reduce((T,A)=>T[A],y)}else{const b=i.split(".");g=b.pop(),f=b.reduce((y,E)=>y[E],o)}const m=n.type==="checkbox"?n.checked:n.value;f&&f[g]!==m&&(f[g]=m)}catch(f){p.onError(f,"sync-update",n)}};n.addEventListener("input",u),n.addEventListener("change",u)}if(n.hasAttribute("b-var")){const i=n.getAttribute("b-var");o.$vars&&(o.$vars[i]=n)}}l.bound=!0}};e instanceof Element&&t(e);const a=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT);let r;for(;r=a.nextNode();)t(r)},Y=e=>{const s=[],c=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT);let o;for(;o=c.nextNode();){if((r=>{let n=r.parentNode;for(;n&&n!==e;){if(n.hasAttribute&&n.hasAttribute("b-for"))return!0;n=n.parentNode}return!1})(o))continue;const a=r=>{if(/\bglobal\b/.test(r)){const n=e.host||e;N(n).hasGlobalDependency=!0}};if(o.nodeType===Node.ELEMENT_NODE){if(o.hasAttribute("b-if")){const n=o.getAttribute("b-if");a(n);const l=document.createComment(`b-if: ${n}`),d=N(o);d.anchor=l,s.push({type:"b-if",node:o,anchor:l,expr:n})}if(o.hasAttribute("b-show")){const n=o.getAttribute("b-show");a(n),s.push({type:"b-show",node:o,expr:n})}if(o.hasAttribute("b-for")){const n=o.getAttribute("b-for").match(/^\s*(\w+)\s+in\s+([\s\S]+?)\s*$/);n&&(a(n[2]),s.push({type:"b-for",node:o,itemName:n[1],listName:n[2].trim(),template:o.cloneNode(!0)}),o.innerHTML="")}if(o.hasAttribute("b-text")&&s.push({type:"b-text",node:o,path:o.getAttribute("b-text")}),o.hasAttribute("b-html")){const n=o.getAttribute("b-html");a(n),s.push({type:"b-html",node:o,expr:n})}o.hasAttribute("b-sync")&&s.push({type:"b-sync",node:o});const[r]=_();[...o.attributes].forEach(n=>{n.value.includes(r)&&(a(n.value),s.push({type:"attr",node:o,attrName:n.name,template:n.value}))})}else if(o.nodeType===Node.TEXT_NODE){const[r]=_();o.textContent.includes(r)&&(a(o.textContent),s.push({type:"text",node:o,template:o.textContent}))}}return s},Q=(e,s)=>{const c=a=>{if(a.nodeType===Node.TEXT_NODE){a._tpl===void 0&&(a._tpl=a.textContent);const r=a._tpl.replace(L(),(n,l)=>h(l.trim(),{state:s,global:Lego.globals,self:a})??"");a.textContent!==r&&(a.textContent=r)}else if(a.nodeType===Node.ELEMENT_NODE){const[r]=_();[...a.attributes].forEach(n=>{if(n._tpl===void 0&&(n._tpl=n.value),n._tpl.includes(r)){const l=n._tpl.replace(L(),(d,i)=>h(i.trim(),{state:s,global:Lego.globals,self:a})??"");n.value!==l&&(n.value=l,n.name==="class"&&(a.className=l))}})}};c(e);const o=document.createTreeWalker(e,NodeFilter.SHOW_ELEMENT|NodeFilter.SHOW_TEXT);let t;for(;t=o.nextNode();)c(t)},C=e=>{const s=e._studs;if(!s)return;const c=N(e);if(!c.rendering){c.rendering=!0,p.metrics&&p.metrics.onRenderStart&&p.metrics.onRenderStart(e);try{const o=e.shadowRoot||e;c.bindings||(c.bindings=Y(o)),c.bindings.forEach(t=>{if(t.type==="b-if"){const a=!!h(t.expr,{state:s,global:Lego.globals,self:t.node}),r=!!t.node.parentNode;a&&!r?t.anchor.parentNode&&t.anchor.parentNode.replaceChild(t.node,t.anchor):!a&&r&&t.node.parentNode.replaceChild(t.anchor,t.node)}if(t.type==="b-show"&&(t.node.style.display=h(t.expr,{state:s,global:Lego.globals,self:t.node})?"":"none"),t.type==="b-text"&&(t.node.textContent=D(t.path,s)),t.type==="b-html"&&(t.node.innerHTML=h(t.expr,{state:s,global:Lego.globals,self:t.node})||""),t.type==="b-sync"&&z(t.node,D(t.node.getAttribute("b-sync"),s)),t.type==="text"){const a=t.template.replace(L(),(r,n)=>h(n.trim(),{state:s,global:Lego.globals,self:t.node})??"");t.node.textContent!==a&&(t.node.textContent=a)}if(t.type==="attr"){const a=t.template.replace(L(),(r,n)=>h(n.trim(),{state:s,global:Lego.globals,self:t.node})??"");t.node.getAttribute(t.attrName)!==a&&(t.node.setAttribute(t.attrName,a),t.attrName==="class"&&(t.node.className=a))}if(t.type==="b-for"){const a=h(t.listName,{state:s,global:Lego.globals,self:e})||[];O.has(t.node)||O.set(t.node,new Map);const r=O.get(t.node),n=new Set;a.forEach((l,d)=>{const i=l&&typeof l=="object"?l.__id||(l.__id=Math.random()):`${d}-${l}`;n.add(i);let u=r.get(i);u||(u=t.template.cloneNode(!0),u.removeAttribute("b-for"),r.set(i,u),x(u,e,{name:t.itemName,listName:t.listName,index:d}));const f=Object.assign(Object.create(s),{[t.itemName]:l});Q(u,f),u.querySelectorAll("[b-sync]").forEach(g=>{const m=g.getAttribute("b-sync");if(m.startsWith(t.itemName+".")){const b=h(t.listName,{state:s,global:Lego.globals,self:e});z(g,D(m.split(".").slice(1).join("."),b[d]))}}),t.node.children[d]!==u&&t.node.insertBefore(u,t.node.children[d]||null)});for(const[l,d]of r.entries())n.has(l)||(d.remove(),r.delete(l))}}),s===Lego.globals&&$.forEach(t=>{N(t).hasGlobalDependency&&C(t)})}catch(o){p.onError(o,"render",e)}finally{p.metrics&&p.metrics.onRenderEnd&&p.metrics.onRenderEnd(e),c.rendering=!1}}},v=e=>{if(!e||e.nodeType!==Node.ELEMENT_NODE)return;const s=N(e),c=e.tagName.toLowerCase(),o=w[c];if(o&&!s.snapped){s.snapped=!0;const a=o.content.cloneNode(!0),r=e.attachShadow({mode:"open"}),n=(o.getAttribute("b-styles")||"").split(/\s+/).filter(Boolean);if(n.length>0){const f=n.flatMap(g=>q.get(g)||[]);f.length>0&&(r.adoptedStyleSheets=[...f])}const l=P.get(c)||{},d=I(o.getAttribute("b-data")||"{}"),i=I(e.getAttribute("b-data")||"{}");e._studs=S({...l,...d,...i,$vars:{},$element:e,$emit:(f,g)=>{e.dispatchEvent(new CustomEvent(f,{detail:g,bubbles:!0,composed:!0}))},get $route(){return Lego.globals.$route},get $go(){return Lego.globals.$go}},e),r.appendChild(a);const u=r.querySelector("style");if(u&&(u.textContent=u.textContent.replace(/\bself\b/g,":host")),x(r,e),$.add(e),C(e),[...r.children].forEach(v),typeof e._studs.mounted=="function")try{e._studs.mounted.call(e._studs)}catch(f){p.onError(f,"mounted",e)}}let t=e.parentElement;for(;t&&!t._studs;)t=t.parentElement;t&&t._studs&&x(e,t),[...e.children].forEach(v)},W=e=>{if(e._studs&&typeof e._studs.unmounted=="function")try{e._studs.unmounted.call(e._studs)}catch(s){console.error("[Lego] Error in unmounted:",s)}e.shadowRoot&&[...e.shadowRoot.children].forEach(W),$.delete(e),[...e.children].forEach(W)},F=async(e=null,s=null)=>{const c=window.location.pathname,o=window.location.search,t=R.find(d=>d.regex.test(c));if(!t)return;let a=[];if(e)a=e.flatMap(d=>V(d,s));else{const d=document.querySelector("lego-router");d&&(a=[d])}if(a.length===0)return;const r=c.match(t.regex).slice(1),n=Object.fromEntries(t.paramNames.map((d,i)=>[d,r[i]])),l=Object.fromEntries(new URLSearchParams(o));t.middleware&&!await t.middleware(n,Lego.globals)||(Lego.globals.$route.url=c+o,Lego.globals.$route.route=t.path,Lego.globals.$route.params=n,Lego.globals.$route.query=l,Lego.globals.$route.method=history.state?.method||"GET",Lego.globals.$route.body=history.state?.body||null,a.forEach(d=>{if(d){const i=document.createElement(t.tagName);d.replaceChildren(i)}}))},U={init:async(e=document.body,s={})=>{(!e||typeof e.nodeType!="number")&&(e=document.body),G=s.styles||{},p.loader=s.loader;const c=Object.entries(G).map(async([t,a])=>{const r=await Promise.all(a.map(async n=>{try{const d=await(await fetch(n)).text(),i=new CSSStyleSheet;return await i.replace(d),i}catch(l){return console.error(`[Lego] Failed to load stylesheet: ${n}`,l),null}}));q.set(t,r.filter(n=>n!==null))});await Promise.all(c),document.querySelectorAll("template[b-id]").forEach(t=>{w[t.getAttribute("b-id")]=t}),new MutationObserver(t=>t.forEach(a=>{a.addedNodes.forEach(r=>{if(r.nodeType===Node.ELEMENT_NODE){v(r);const n=r.tagName.toLowerCase();if(n.includes("-")&&!w[n]&&p.loader&&!$.has(r)){const l=p.loader(n);if(l){const d=typeof l=="string"?fetch(l).then(i=>i.text()):l;Promise.resolve(d).then(i=>U.defineSFC(i,n+".lego")).catch(i=>console.error(`[Lego] Failed to load ${n}:`,i))}}}}),a.removedNodes.forEach(r=>r.nodeType===Node.ELEMENT_NODE&&W(r))})).observe(e,{childList:!0,subtree:!0}),e._studs=Lego.globals,v(e),x(e,e),C(e),R.length>0&&(window.addEventListener("popstate",t=>{const a=t.state?.legoTargets||null;F(a)}),document.addEventListener("submit",t=>{t.preventDefault()}),document.addEventListener("click",t=>{const r=t.composedPath().find(n=>n.tagName==="A"&&(n.hasAttribute("b-target")||n.hasAttribute("b-link")));if(r){t.preventDefault();const n=r.getAttribute("href"),l=r.getAttribute("b-target"),d=l?l.split(/\s+/).filter(Boolean):[],i=r.getAttribute("b-link")!=="false";Lego.globals.$go(n,...d).get(i)}}),F())},globals:S({$route:{url:window.location.pathname,route:"",params:{},query:{},method:"GET",body:null},$go:(e,...s)=>j(e,...s)(document.body)},document.body),defineSFC:(e,s="component.lego")=>{let c="",o="{}",t="",a="",r=e;const n=/<(template|script|style)\b((?:\s+(?:[^>"']|"[^"]*"|'[^']*')*)*)>/i;for(;r;){const i=r.match(n);if(!i)break;const u=i[1].toLowerCase(),f=i[2],g=i[0],m=i.index,b=`</${u}>`,y=m+g.length,E=r.indexOf(b,y);if(E===-1){console.warn(`[Lego] Unclosed <${u}> tag in ${s}`);break}const T=r.slice(y,E);if(u==="template"){c=T.trim();const A=f.match(/b-styles=["']([^"']+)["']/);A&&(t=A[1])}else if(u==="script"){const A=T.trim(),X=A.match(/export\s+default\s+({[\s\S]*})/);o=X?X[1]:A}else u==="style"&&(a=T.trim());r=r.slice(E+b.length)}const l=K(s),d=new Function(`return ${o}`)();a&&(c=`<style>${a}</style>`+c),w[l]=document.createElement("template"),w[l].innerHTML=c,w[l].setAttribute("b-styles",t),P.set(l,d),document.querySelectorAll(l).forEach(i=>!N(i).snapped&&v(i))},define:(e,s,c={},o="")=>{const t=document.createElement("template");t.setAttribute("b-id",e),t.setAttribute("b-styles",o),t.innerHTML=s,w[e]=t,P.set(e,c);try{B.set(e.toLowerCase(),S({...c},document.body))}catch(a){p.onError(a,"define",e)}document.querySelectorAll(e).forEach(v)},getActiveComponentsCount:()=>$.size,config:p,route:(e,s,c=null)=>{const o=[],t=e.replace(/:([^\/]+)/g,(a,r)=>(o.push(r),"([^/]+)"));R.push({path:e,regex:new RegExp(`^${t}$`),tagName:s,paramNames:o,middleware:c})}};return U})();typeof window<"u"&&(window.Lego=Lego);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lego-dom",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.4",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A feature-rich web components + SFC frontend framework",
|
|
6
6
|
"main": "main.js",
|
|
@@ -22,11 +22,13 @@
|
|
|
22
22
|
"author": "Tersoo Ortserga",
|
|
23
23
|
"scripts": {
|
|
24
24
|
"test": "vitest run",
|
|
25
|
+
"build": "esbuild main.js --minify --outfile=main.min.js",
|
|
25
26
|
"docs:dev": "vitepress dev docs",
|
|
26
27
|
"docs:build": "vitepress build docs",
|
|
27
28
|
"docs:preview": "vitepress preview docs"
|
|
28
29
|
},
|
|
29
30
|
"devDependencies": {
|
|
31
|
+
"esbuild": "^0.27.2",
|
|
30
32
|
"jsdom": "^22.0.0",
|
|
31
33
|
"vitepress": "^1.6.4",
|
|
32
34
|
"vitest": "^1.0.0"
|