lego-dom 1.0.0 → 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.
Files changed (74) hide show
  1. package/.legodom +87 -0
  2. package/CHANGELOG.md +87 -3
  3. package/cdn.html +10 -5
  4. package/docs/.vitepress/config.js +23 -7
  5. package/docs/api/config.md +95 -0
  6. package/docs/api/define.md +29 -2
  7. package/docs/api/directives.md +10 -2
  8. package/docs/api/index.md +1 -0
  9. package/docs/contributing/01-welcome.md +2 -0
  10. package/docs/contributing/02-registry.md +37 -3
  11. package/docs/contributing/06-init.md +13 -2
  12. package/docs/contributing/07-observer.md +3 -0
  13. package/docs/contributing/08-snap.md +15 -1
  14. package/docs/contributing/10-studs.md +3 -1
  15. package/docs/contributing/11-scanner.md +13 -0
  16. package/docs/contributing/12-render.md +32 -10
  17. package/docs/contributing/13-directives.md +19 -1
  18. package/docs/contributing/14-events.md +1 -1
  19. package/docs/contributing/15-router.md +49 -1
  20. package/docs/contributing/16-state.md +9 -10
  21. package/docs/contributing/17-legodom.md +1 -8
  22. package/docs/contributing/index.md +23 -4
  23. package/docs/examples/form.md +1 -1
  24. package/docs/examples/index.md +3 -3
  25. package/docs/examples/routing.md +10 -10
  26. package/docs/examples/sfc-showcase.md +1 -1
  27. package/docs/examples/todo-app.md +7 -7
  28. package/docs/guide/cdn-usage.md +44 -18
  29. package/docs/guide/components.md +18 -12
  30. package/docs/guide/directives.md +131 -22
  31. package/docs/guide/directory-structure.md +248 -0
  32. package/docs/guide/faq.md +210 -0
  33. package/docs/guide/getting-started.md +14 -10
  34. package/docs/guide/index.md +1 -1
  35. package/docs/guide/lifecycle.md +32 -0
  36. package/docs/guide/quick-start.md +4 -4
  37. package/docs/guide/reactivity.md +2 -2
  38. package/docs/guide/routing.md +69 -8
  39. package/docs/guide/server-side.md +134 -0
  40. package/docs/guide/sfc.md +96 -13
  41. package/docs/guide/templating.md +62 -57
  42. package/docs/index.md +9 -9
  43. package/docs/router/basic-routing.md +8 -8
  44. package/docs/router/cold-entry.md +2 -2
  45. package/docs/router/history.md +7 -7
  46. package/docs/router/index.md +1 -1
  47. package/docs/router/resolver.md +5 -5
  48. package/docs/router/surgical-swaps.md +5 -5
  49. package/docs/tutorial/01-project-setup.md +152 -0
  50. package/docs/tutorial/02-your-first-component.md +226 -0
  51. package/docs/tutorial/03-adding-routes.md +279 -0
  52. package/docs/tutorial/04-multi-page-app.md +329 -0
  53. package/docs/tutorial/05-state-and-globals.md +285 -0
  54. package/docs/tutorial/index.md +40 -0
  55. package/examples/vite-app/index.html +1 -0
  56. package/examples/vite-app/src/app.js +2 -2
  57. package/examples/vite-app/src/components/side-menu.lego +46 -0
  58. package/examples/vite-app/vite.config.js +2 -1
  59. package/main.js +261 -72
  60. package/main.min.js +7 -0
  61. package/monitoring-plugin.js +111 -0
  62. package/package.json +4 -2
  63. package/parse-lego.js +49 -22
  64. package/tests/error.test.js +74 -0
  65. package/tests/main.test.js +2 -2
  66. package/tests/memory.test.js +68 -0
  67. package/tests/monitoring.test.js +74 -0
  68. package/tests/naming.test.js +74 -0
  69. package/tests/parse-lego.test.js +2 -2
  70. package/tests/security.test.js +67 -0
  71. package/tests/server.test.js +114 -0
  72. package/tests/syntax.test.js +67 -0
  73. package/vite-plugin.js +3 -2
  74. package/docs/guide/contributing.md +0 -32
package/docs/guide/sfc.md CHANGED
@@ -2,11 +2,50 @@
2
2
 
3
3
  Single File Components (SFCs) let you define components in dedicated `.lego` files when using Vite as your build tool.
4
4
 
5
- ## Why SFCs?
5
+ ::: tip 🚀 New to LegoDOM?
6
+ Start with our **[Step-by-Step Tutorial](/tutorial/)** to build a complete multi-page app with SFCs!
7
+ :::
8
+
9
+ ## Where Does My Config Go?
10
+
11
+ The #1 question developers ask: **"I have a `.lego` file – now where do I put my routes?"**
12
+
13
+ **Answer: Everything goes in your entry file (`app.js` or `main.js`):**
14
+
15
+ ```javascript
16
+ // src/app.js – The control center of your app
17
+
18
+ import { Lego } from 'lego-dom';
19
+ import registerComponents from 'virtual:lego-components';
20
+
21
+ // 1. Register all .lego files automatically
22
+ registerComponents();
23
+
24
+ // 2. Define your routes
25
+ Lego.route('/', 'home-page'); // home-page.lego
26
+ Lego.route('/login', 'login-page'); // login-page.lego
27
+ Lego.route('/users/:id', 'user-profile'); // user-profile.lego
6
28
 
7
- When your project grows, keeping
29
+ // 3. Initialize global state (optional)
30
+ Lego.globals.user = null;
8
31
 
9
- components in separate files makes your codebase more organized and maintainable.
32
+ // 4. Start the engine
33
+ await Lego.init();
34
+ ```
35
+
36
+ Your `index.html` just needs:
37
+ ```html
38
+ <lego-router></lego-router>
39
+ <script type="module" src="/src/app.js"></script>
40
+ ```
41
+
42
+ That's the complete pattern! 🎉
43
+
44
+ ---
45
+
46
+ ## Why SFCs?
47
+
48
+ When your project grows, keeping components in separate files makes your codebase more organized and maintainable.
10
49
 
11
50
  ### Benefits
12
51
 
@@ -43,12 +82,12 @@ Here's a complete example (`user-card.lego`):
43
82
 
44
83
  ```html
45
84
  <template>
46
- <img class="avatar" src="{{ avatarUrl }}" alt="{{ name }}">
47
- <h2 class="name">{{ name }}</h2>
48
- <p class="bio">{{ bio }}</p>
49
- <p>Followers: {{ followers }}</p>
85
+ <img class="avatar" src="[[ avatarUrl ]]" alt="[[ name ]]">
86
+ <h2 class="name">[[ name ]]</h2>
87
+ <p class="bio">[[ bio ]]</p>
88
+ <p>Followers: [[ followers ]]</p>
50
89
  <button @click="follow()">
51
- {{ isFollowing ? 'Unfollow' : 'Follow' }}
90
+ [[ isFollowing ? 'Unfollow' : 'Follow' ]]
52
91
  </button>
53
92
  </template>
54
93
 
@@ -214,10 +253,10 @@ Contains your component's HTML markup with Lego directives:
214
253
 
215
254
  ```html
216
255
  <template>
217
- <h1>{{ title }}</h1>
218
- <p b-show="showContent">{{ content }}</p>
256
+ <h1>[[ title ]]</h1>
257
+ <p b-show="showContent">[[ content ]]</p>
219
258
  <ul>
220
- <li b-for="item in items">{{ item }}</li>
259
+ <li b-for="item in items">[[ item ]]</li>
221
260
  </ul>
222
261
  </template>
223
262
  ```
@@ -271,6 +310,50 @@ Scoped styles using Shadow DOM. Use `self` to target the component root:
271
310
 
272
311
  Styles are automatically scoped to your component—they won't affect other components or global styles.
273
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
+
274
357
  ## Hot Module Replacement
275
358
 
276
359
  During development, changes to `.lego` files trigger a full page reload. Your changes appear instantly!
@@ -340,7 +423,7 @@ components/
340
423
  ```html
341
424
  <template b-id="my-component">
342
425
  <style>self { padding: 1rem; }</style>
343
- <h1>{{ title }}</h1>
426
+ <h1>[[ title ]]</h1>
344
427
  </template>
345
428
 
346
429
  <my-component b-data="{ title: 'Hello' }"></my-component>
@@ -351,7 +434,7 @@ components/
351
434
  ```html
352
435
  <!-- my-component.lego -->
353
436
  <template>
354
- <h1>{{ title }}</h1>
437
+ <h1>[[ title ]]</h1>
355
438
  </template>
356
439
 
357
440
  <style>
@@ -4,38 +4,38 @@ Learn about Lego templating features and syntax.
4
4
 
5
5
  ## Interpolation
6
6
 
7
- Use `{{ }}` to insert dynamic content:
7
+ Use `[[ ]]` to insert dynamic content:
8
8
 
9
9
  ### Simple Values
10
10
 
11
11
  ```html
12
- <p>{{ message }}</p>
13
- <h1>{{ title }}</h1>
14
- <span>{{ count }}</span>
12
+ <p>[[ message ]]</p>
13
+ <h1>[[ title ]]</h1>
14
+ <span>[[ count ]]</span>
15
15
  ```
16
16
 
17
17
  ### Expressions
18
18
 
19
19
  ```html
20
- <p>{{ count * 2 }}</p>
21
- <span>{{ price.toFixed(2) }}</span>
22
- <div>{{ firstName + ' ' + lastName }}</div>
20
+ <p>[[ count * 2 ]]</p>
21
+ <span>[[ price.toFixed(2) ]]</span>
22
+ <div>[[ firstName + ' ' + lastName ]]</div>
23
23
  ```
24
24
 
25
25
  ### Method Calls
26
26
 
27
27
  ```html
28
- <p>{{ formatDate(timestamp) }}</p>
29
- <span>{{ calculateTotal() }}</span>
30
- <div>{{ getUsername() }}</div>
28
+ <p>[[ formatDate(timestamp) ]]</p>
29
+ <span>[[ calculateTotal() ]]</span>
30
+ <div>[[ getUsername() ]]</div>
31
31
  ```
32
32
 
33
33
  ### Conditional (Ternary)
34
34
 
35
35
  ```html
36
- <p>{{ age >= 18 ? 'Adult' : 'Minor' }}</p>
37
- <span>{{ isOnline ? '🟢 Online' : '🔴 Offline' }}</span>
38
- <div>{{ items.length > 0 ? items.length + ' items' : 'Empty' }}</div>
36
+ <p>[[ age >= 18 ? 'Adult' : 'Minor' ]]</p>
37
+ <span>[[ isOnline ? '🟢 Online' : '🔴 Offline' ]]</span>
38
+ <div>[[ items.length > 0 ? items.length + ' items' : 'Empty' ]]</div>
39
39
  ```
40
40
 
41
41
  ## Attribute Binding
@@ -45,29 +45,29 @@ Interpolate in any attribute:
45
45
  ### Simple Attributes
46
46
 
47
47
  ```html
48
- <img src="/avatars/{{ userId }}.png" alt="{{ username }}">
49
- <a href="/user/{{ userId }}">{{ username }}</a>
50
- <input placeholder="{{ defaultText }}">
48
+ <img src="/avatars/[[ userId ]].png" alt="[[ username ]]">
49
+ <a href="/user/[[ userId ]]">[[ username ]]</a>
50
+ <input placeholder="[[ defaultText ]]">
51
51
  ```
52
52
 
53
53
  ### Class Names
54
54
 
55
55
  ```html
56
- <div class="card {{ isActive ? 'active' : '' }}">...</div>
57
- <button class="{{ isDisabled ? 'disabled' : 'enabled' }}">...</button>
58
- <li class="item status-{{ status }}">...</li>
56
+ <div class="card [[ isActive ? 'active' : '' ]]">...</div>
57
+ <button class="[[ isDisabled ? 'disabled' : 'enabled' ]]">...</button>
58
+ <li class="item status-[[ status ]]">...</li>
59
59
  ```
60
60
 
61
61
  ### Data Attributes
62
62
 
63
63
  ```html
64
- <div data-id="{{ itemId }}" data-type="{{ itemType }}">...</div>
64
+ <div data-id="[[ itemId ]]" data-type="[[ itemType ]]">...</div>
65
65
  ```
66
66
 
67
67
  ### Style (Inline)
68
68
 
69
69
  ```html
70
- <div style="color: {{ textColor }}; background: {{ bgColor }}">...</div>
70
+ <div style="color: [[ textColor ]]; background: [[ bgColor ]]">...</div>
71
71
  ```
72
72
 
73
73
  ## Escaping
@@ -81,11 +81,16 @@ Lego automatically escapes HTML to prevent XSS:
81
81
  ```
82
82
 
83
83
  ```html
84
- <p>{{ userInput }}</p>
84
+ <p>[[ userInput ]]</p>
85
85
  <!-- Renders as: &lt;script&gt;alert("XSS")&lt;/script&gt; -->
86
86
  ```
87
87
 
88
- **There is no way to render raw HTML.** This is by design—for security.
88
+ **By default,## Raw HTML
89
+
90
+ To render raw HTML content, use the `b-html` directive.
91
+
92
+ > [!WARNING]
93
+ > Never use `b-html` on untrusted user input (e.g., comments, messages). It can lead to XSS attacks.
89
94
 
90
95
  ## Whitespace
91
96
 
@@ -93,7 +98,7 @@ Templates preserve whitespace:
93
98
 
94
99
  ```html
95
100
  <p>
96
- {{ message }}
101
+ [[ message ]]
97
102
  </p>
98
103
  <!-- Renders with newlines and indentation -->
99
104
  ```
@@ -101,25 +106,25 @@ Templates preserve whitespace:
101
106
  Trim manually if needed:
102
107
 
103
108
  ```html
104
- <p>{{ message.trim() }}</p>
109
+ <p>[[ message.trim() ]]</p>
105
110
  ```
106
111
 
107
112
  ## Context
108
113
 
109
- Inside `{{ }}`, you have access to:
114
+ Inside `[[ ]]`, you have access to:
110
115
 
111
116
  ### Component State (`this`)
112
117
 
113
118
  ```html
114
- <p>{{ count }}</p> <!-- this.count -->
115
- <span>{{ user.name }}</span> <!-- this.user.name -->
119
+ <p>[[ count ]]</p> <!-- this.count -->
120
+ <span>[[ user.name ]]</span> <!-- this.user.name -->
116
121
  ```
117
122
 
118
123
  ### Methods
119
124
 
120
125
  ```html
121
- <p>{{ formatDate(timestamp) }}</p>
122
- <div>{{ calculateTotal() }}</div>
126
+ <p>[[ formatDate(timestamp) ]]</p>
127
+ <div>[[ calculateTotal() ]]</div>
123
128
  ```
124
129
 
125
130
  ### Special Keywords
@@ -129,7 +134,7 @@ Inside `{{ }}`, you have access to:
129
134
  - `self` - Reference to component element (rare)
130
135
 
131
136
  ```html
132
- <p>{{ global.user.name }}</p>
137
+ <p>[[ global.user.name ]]</p>
133
138
  <button @click="console.log(event)">Click</button>
134
139
  ```
135
140
 
@@ -147,7 +152,7 @@ Inside `{{ }}`, you have access to:
147
152
  ```
148
153
 
149
154
  ```html
150
- <p>Price: {{ formatCurrency(price) }}</p>
155
+ <p>Price: [[ formatCurrency(price) ]]</p>
151
156
  ```
152
157
 
153
158
  ### Date Formatting
@@ -162,7 +167,7 @@ Inside `{{ }}`, you have access to:
162
167
  ```
163
168
 
164
169
  ```html
165
- <time>{{ formatDate(timestamp) }}</time>
170
+ <time>[[ formatDate(timestamp) ]]</time>
166
171
  ```
167
172
 
168
173
  ### Pluralization
@@ -177,7 +182,7 @@ Inside `{{ }}`, you have access to:
177
182
  ```
178
183
 
179
184
  ```html
180
- <p>{{ items.length }} {{ plural(items.length, 'item', 'items') }}</p>
185
+ <p>[[ items.length ]] [[ plural(items.length, 'item', 'items') ]]</p>
181
186
  ```
182
187
 
183
188
  ### Truncation
@@ -194,7 +199,7 @@ Inside `{{ }}`, you have access to:
194
199
  ```
195
200
 
196
201
  ```html
197
- <p>{{ truncate(description, 100) }}</p>
202
+ <p>[[ truncate(description, 100) ]]</p>
198
203
  ```
199
204
 
200
205
  ## Limitations
@@ -205,12 +210,12 @@ Can't use statements—only expressions:
205
210
 
206
211
  ```html
207
212
  <!-- ❌ Doesn't work -->
208
- <p>{{ if (condition) { return 'yes'; } }}</p>
209
- <p>{{ for (let i = 0; i < 10; i++) { } }}</p>
213
+ <p>[[ if (condition) { return 'yes'; } ]]</p>
214
+ <p>[[ for (let i = 0; i < 10; i++) { } ]]</p>
210
215
 
211
216
  <!-- ✅ Use ternary or methods -->
212
- <p>{{ condition ? 'yes' : 'no' }}</p>
213
- <p>{{ renderList() }}</p>
217
+ <p>[[ condition ? 'yes' : 'no' ]]</p>
218
+ <p>[[ renderList() ]]</p>
214
219
  ```
215
220
 
216
221
  ### No Declarations
@@ -219,10 +224,10 @@ Can't declare variables:
219
224
 
220
225
  ```html
221
226
  <!-- ❌ Doesn't work -->
222
- <p>{{ const total = price * qty; total }}</p>
227
+ <p>[[ const total = price * qty; total ]]</p>
223
228
 
224
229
  <!-- ✅ Use methods -->
225
- <p>{{ getTotal() }}</p>
230
+ <p>[[ getTotal() ]]</p>
226
231
  ```
227
232
 
228
233
  ```js
@@ -242,10 +247,10 @@ If logic is complex, use methods:
242
247
 
243
248
  ```html
244
249
  <!-- ❌ Too complex -->
245
- <p>{{ items.filter(x => x.active).map(x => x.name).join(', ') }}</p>
250
+ <p>[[ items.filter(x => x.active).map(x => x.name).join(', ') ]]</p>
246
251
 
247
252
  <!-- ✅ Better -->
248
- <p>{{ getActiveNames() }}</p>
253
+ <p>[[ getActiveNames() ]]</p>
249
254
  ```
250
255
 
251
256
  ```js
@@ -265,10 +270,10 @@ Don't put formatting logic in templates:
265
270
 
266
271
  ```html
267
272
  <!-- ❌ Messy -->
268
- <p>${{ (price * 1.2).toFixed(2) }}</p>
273
+ <p>$[[ (price * 1.2).toFixed(2) ]]</p>
269
274
 
270
275
  <!-- ✅ Clean -->
271
- <p>{{ formatPrice(price) }}</p>
276
+ <p>[[ formatPrice(price) ]]</p>
272
277
  ```
273
278
 
274
279
  ### 3. Avoid Side Effects
@@ -277,10 +282,10 @@ Don't mutate state in templates:
277
282
 
278
283
  ```html
279
284
  <!-- ❌ Bad -->
280
- <p>{{ count++ }}</p>
285
+ <p>[[ count++ ]]</p>
281
286
 
282
287
  <!-- ✅ Good -->
283
- <p>{{ count }}</p>
288
+ <p>[[ count ]]</p>
284
289
  <button @click="count++">Increment</button>
285
290
  ```
286
291
 
@@ -323,10 +328,10 @@ If a calculation is expensive, cache it:
323
328
 
324
329
  ```html
325
330
  <!-- ❌ Runs on every render -->
326
- <p>{{ expensiveCalculation() }}</p>
331
+ <p>[[ expensiveCalculation() ]]</p>
327
332
 
328
333
  <!-- ✅ Calculate once, store result -->
329
- <p>{{ cachedResult }}</p>
334
+ <p>[[ cachedResult ]]</p>
330
335
  ```
331
336
 
332
337
  ```js
@@ -343,7 +348,7 @@ If a calculation is expensive, cache it:
343
348
  ### Show/Hide Based on Condition
344
349
 
345
350
  ```html
346
- <p b-show="user">Welcome, {{ user.name }}!</p>
351
+ <p b-show="user">Welcome, [[ user.name ]]!</p>
347
352
  <p b-show="!user">Please log in</p>
348
353
  ```
349
354
 
@@ -352,7 +357,7 @@ If a calculation is expensive, cache it:
352
357
  ```html
353
358
  <ul>
354
359
  <li b-for="item in items">
355
- #{{ $index + 1 }}: {{ item.name }}
360
+ #[[ $index + 1 ]]: [[ item.name ]]
356
361
  </li>
357
362
  </ul>
358
363
  ```
@@ -360,8 +365,8 @@ If a calculation is expensive, cache it:
360
365
  ### Conditional Classes
361
366
 
362
367
  ```html
363
- <div class="item {{ item.active ? 'active' : '' }} {{ item.featured ? 'featured' : '' }}">
364
- {{ item.name }}
368
+ <div class="item [[ item.active ? 'active' : '' ]] [[ item.featured ? 'featured' : '' ]]">
369
+ [[ item.name ]]
365
370
  </div>
366
371
  ```
367
372
 
@@ -369,10 +374,10 @@ If a calculation is expensive, cache it:
369
374
 
370
375
  ```html
371
376
  <a
372
- href="/product/{{ product.id }}"
373
- class="product-link {{ product.inStock ? '' : 'out-of-stock' }}"
374
- title="{{ product.name }} - ${{ product.price }}">
375
- {{ product.name }}
377
+ href="/product/[[ product.id ]]"
378
+ class="product-link [[ product.inStock ? '' : 'out-of-stock' ]]"
379
+ title="[[ product.name ]] - $[[ product.price ]]">
380
+ [[ product.name ]]
376
381
  </a>
377
382
  ```
378
383
 
package/docs/index.md CHANGED
@@ -7,14 +7,14 @@ hero:
7
7
  tagline: A tiny, zero-dependency Web library for creating reactive Web Components directly in the browser
8
8
  image:
9
9
  src: /logo.svg
10
- alt: Lego
10
+ alt: LegoDOM
11
11
  actions:
12
12
  - theme: brand
13
13
  text: Get Started
14
14
  link: /guide/getting-started
15
15
  - theme: alt
16
16
  text: View on GitHub
17
- link: https://github.com/rayattack/Lego
17
+ link: https://github.com/rayattack/LegoDOM
18
18
  - theme: alt
19
19
  text: Try Examples
20
20
  link: /examples/
@@ -59,7 +59,7 @@ features:
59
59
 
60
60
  ## Components & Naming
61
61
 
62
- How you name your components depends on how you use Lego:
62
+ How you name your components depends on how you use LegoDOM:
63
63
 
64
64
  ### 1. Vite / Build Tools (Recommended)
65
65
  **Convention over Configuration.** The filename *is* the tag name.
@@ -109,21 +109,21 @@ Since there are no files, you must explicitly name your components using the `b-
109
109
  <script src="https://unpkg.com/lego-dom/main.js"></script>
110
110
  <script>
111
111
  // Complete the initialization
112
- Lego.init();
112
+ LegoDOM.init();
113
113
  </script>
114
114
  ```
115
115
 
116
116
  That's it. No build step, no npm, no configuration.
117
117
 
118
118
  > [!IMPORTANT]
119
- > **Why call `Lego.init()`?**
120
- > While `Lego.define()` will "snap" your components into the page immediately, you must call `Lego.init()` to start the background engine. Without it:
119
+ > **Why call `LegoDOM.init()`?**
120
+ > While `LegoDOM.define()` will "snap" your components into the page immediately, you must call `LegoDOM.init()` to start the background engine. Without it:
121
121
  > - **Reactivity** to data changes won't work.
122
122
  > - **Mustaches** (<code v-pre>{{...}}</code>) outside of components won't hydrate.
123
123
  > - **Single Page Routing** won't be activated.
124
124
  > - **New components** added to the DOM dynamically won't be auto-initialized.
125
125
 
126
- ## Why Lego?
126
+ ## Why LegoDOM?
127
127
 
128
128
  **For small projects**, you get reactive components without the overhead of a full framework.
129
129
 
@@ -133,7 +133,7 @@ That's it. No build step, no npm, no configuration.
133
133
 
134
134
  ## Comparison
135
135
 
136
- | Feature | Lego | Vue | React |
136
+ | Feature | LegoDOM | Vue | React |
137
137
  |---------|--------|-----|-------|
138
138
  | Size | < 17KB | ~33KB | ~40KB |
139
139
  | Dependencies | 0 | Many | Many |
@@ -146,7 +146,7 @@ That's it. No build step, no npm, no configuration.
146
146
 
147
147
  ## Browser Support
148
148
 
149
- Lego works in all modern browsers that support:
149
+ LegoDOM works in all modern browsers that support:
150
150
  - Web Components
151
151
  - Shadow DOM
152
152
  - ES6 Proxy
@@ -1,6 +1,6 @@
1
1
  # Basic Routing: The Global Outlet
2
2
 
3
- Before we dive into surgical swaps, we must understand how LegoJS handles the initial entry into your application. Every application needs a primary gateway—a place where the main content lives. In Lego, this is the `<lego-router>`.
3
+ Before we dive into surgical swaps, we must understand how LegoDOM handles the initial entry into your application. Every application needs a primary gateway—a place where the main content lives. In LegoDOM, this is the `<lego-router>`.
4
4
 
5
5
  ## The Entry Point
6
6
 
@@ -15,7 +15,7 @@ In your `index.html`, you define a single custom element that acts as the "Maste
15
15
  ```
16
16
 
17
17
 
18
- When the page loads, the LegoJS router looks at the current browser URL and searches its internal "Route Map" for a match.
18
+ When the page loads, the LegoDOM router looks at the current browser URL and searches its internal "Route Map" for a match.
19
19
 
20
20
  ## Defining Your First Routes
21
21
 
@@ -32,16 +32,16 @@ Lego.route('/user/:id', 'profile-page');
32
32
 
33
33
  ### How the Matching Works
34
34
 
35
- 1. **The Match**: Lego uses Regex to compare the window location with your defined paths.
35
+ 1. **The Match**: LegoDOM uses Regex to compare the window location with your defined paths.
36
36
 
37
- 2. **The Injection**: If a match is found, Lego creates an instance of the associated component (e.g., `<home-page>`) and injects it into the `<lego-router>` tag.
37
+ 2. **The Injection**: If a match is found, LegoDOM creates an instance of the associated component (e.g., `<home-page>`) and injects it into the `<lego-router>` tag.
38
38
 
39
39
  3. **The Hydration**: The framework then "snaps" the component to life, initializing its state and running its `mounted()` lifecycle hook.
40
40
 
41
41
 
42
42
  ## The Global Fallback
43
43
 
44
- If no route matches the current URL, LegoJS looks for a special fallback route. This is essential for handling **404 Not Found** states gracefully.
44
+ If no route matches the current URL, LegoDOM looks for a special fallback route. This is essential for handling **404 Not Found** states gracefully.
45
45
 
46
46
  ```js
47
47
  Lego.route('*', 'not-found-page');
@@ -50,14 +50,14 @@ Lego.route('*', 'not-found-page');
50
50
 
51
51
  ## Handling Parameters (`$params`)
52
52
 
53
- When you use a dynamic path like `/user/:id`, Lego automatically parses the URL and makes the data available to the component via the global `$route` object.
53
+ When you use a dynamic path like `/user/:id`, LegoDOM automatically parses the URL and makes the data available to the component via the global `$route` object.
54
54
 
55
55
  In your component template:
56
56
 
57
57
  ```html
58
58
  <template b-id="profile-page">
59
59
  <h1>User Profile</h1>
60
- <p>Viewing ID: {{ $route.params.id }}</p>
60
+ <p>Viewing ID: [[ $route.params.id ]]</p>
61
61
  </template>
62
62
 
63
63
  ```
@@ -83,7 +83,7 @@ mounted() {
83
83
 
84
84
  <template>
85
85
  <h1>User Profile</h1>
86
- <p>Viewing ID: {{ $params.id }}</p>
86
+ <p>Viewing ID: [[ $params.id ]]</p>
87
87
  </template>
88
88
 
89
89
  <script>
@@ -3,7 +3,7 @@
3
3
 
4
4
  In the previous section, we learned how to use `b-target` to surgically swap fragments while the app is running. But what happens when a user types `myapp.com/messaging/123` directly into the address bar or hits **Refresh (F5)**?
5
5
 
6
- In a traditional nested router, the framework handles this automatically. In LegoJS, we use a more powerful, explicit pattern called **Self-Healing Layouts**.
6
+ In a traditional nested router, the framework handles this automatically. In LegoDOM, we use a more powerful, explicit pattern called **Self-Healing Layouts**.
7
7
 
8
8
  ## The Cold Entry/Start Challenge
9
9
 
@@ -13,7 +13,7 @@ When a "Cold Start" occurs:
13
13
 
14
14
  2. The server returns the base `index.html`.
15
15
 
16
- 3. LegoJS matches the route `/messaging/:id` to the `messaging-shell` component.
16
+ 3. LegoDOM matches the route `/messaging/:id` to the `messaging-shell` component.
17
17
 
18
18
  4. The `messaging-shell` mounts, but the `#chat-window` target is empty (or showing its default "Select a conversation" text).
19
19
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  One of the biggest frustrations in modern web development is "breaking the back button." When you use JavaScript to update only part of a page, the browser often doesn't realize a navigation event occurred. If the user hits "Back," they might be booted out of your app entirely.
5
5
 
6
- LegoJS solves this using a system called **Smart History**. It ensures that even surgical, fragment-level updates are recorded and reversible.
6
+ LegoDOM solves this using a system called **Smart History**. It ensures that even surgical, fragment-level updates are recorded and reversible.
7
7
 
8
8
  ## How Traditional Routers Fail
9
9
 
@@ -18,9 +18,9 @@ In a standard SPA, the router usually manages a single "current view." When you
18
18
 
19
19
  Because the whole page (or the main outlet) is replaced, the browser's history stack is simple: Page A -> Page B. But in a complex layout like LinkedIn, you might have changed the chat window 5 times while the sidebar stayed exactly the same. Users expect the "Back" button to cycle through those chats, not take them back to the login screen.
20
20
 
21
- ## The LegoJS Approach: Target Tracking
21
+ ## The LegoDOM Approach: Target Tracking
22
22
 
23
- When you use `b-link` with a `b-target`, LegoJS does two things simultaneously:
23
+ When you use `b-link` with a `b-target`, LegoDOM does two things simultaneously:
24
24
 
25
25
  1. It updates the browser URL using the History API.
26
26
 
@@ -29,7 +29,7 @@ When you use `b-link` with a `b-target`, LegoJS does two things simultaneously:
29
29
 
30
30
  ### Inside the History State
31
31
 
32
- Every time a surgical swap happens, LegoJS saves the target selector in the `history.state`. It looks something like this:
32
+ Every time a surgical swap happens, LegoDOM saves the target selector in the `history.state`. It looks something like this:
33
33
 
34
34
  ```js
35
35
  // Internal representation
@@ -41,9 +41,9 @@ history.pushState({
41
41
 
42
42
  ## The "Popstate" Magic
43
43
 
44
- When a user hits the **Back** or **Forward** button, the browser triggers a `popstate` event. LegoJS intercepts this event and checks if the incoming state contains `legoTargets`.
44
+ When a user hits the **Back** or **Forward** button, the browser triggers a `popstate` event. LegoDOM intercepts this event and checks if the incoming state contains `legoTargets`.
45
45
 
46
- - **If `legoTargets` exists:** LegoJS performs a surgical swap. It takes the URL the browser is moving to and renders it _only_ into the specified target (e.g., `#chat-window`).
46
+ - **If `legoTargets` exists:** LegoDOM performs a surgical swap. It takes the URL the browser is moving to and renders it _only_ into the specified target (e.g., `#chat-window`).
47
47
 
48
48
  - **If no target exists:** It performs a global swap in the `<lego-router>`.
49
49
 
@@ -66,4 +66,4 @@ Because the history state uses the same URLs as your standard links, a "Back" na
66
66
 
67
67
  Smart History is the "glue" that makes a multi-fragment interface feel like a single, cohesive application. It respects the user's intent by making the browser's navigation tools work for specific parts of the page, not just the whole page.
68
68
 
69
- Next, we'll dive into the mechanics of how LegoJS finds these targets in complex, nested DOM trees in **Target Resolver: Scoping and Logic**.
69
+ Next, we'll dive into the mechanics of how LegoDOM finds these targets in complex, nested DOM trees in **Target Resolver: Scoping and Logic**.
@@ -3,7 +3,7 @@
3
3
 
4
4
  Traditional Single Page Application (SPA) routers (like React Router, Vue Router, or Angular's Router) rely on a **Centralized Configuration Tree**. As your project grows, this JSON or JavaScript object becomes a "source of truth" that is fragile, hard to maintain, and forces a rigid hierarchy on your UI.
5
5
 
6
- **LegoJS breaks this pattern.**
6
+ **LegoDOM breaks this pattern.**
7
7
 
8
8
  In Lego, we don't nest routes in a config file. Instead, we use the **URL as the Data Source** and the **DOM as the Layout Engine**.
9
9