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
@@ -1,7 +1,7 @@
1
1
 
2
2
  # 06. Target Resolver: Scoping and Logic
3
3
 
4
- In the previous chapters, we used `b-target` to send content to different parts of the page. But how does LegoJS actually find those "holes" in a complex, nested DOM? This is where the **Target Resolver** comes in.
4
+ In the previous chapters, we used `b-target` to send content to different parts of the page. But how does LegoDOM actually find those "holes" in a complex, nested DOM? This is where the **Target Resolver** comes in.
5
5
 
6
6
  The Target Resolver is a prioritized logic engine that ensures your links always find the correct destination, even in massive applications with thousands of components.
7
7
 
@@ -16,11 +16,11 @@ In traditional JavaScript, if you use `document.querySelector('#detail-view')`,
16
16
 
17
17
  ## The Resolver Hierarchy
18
18
 
19
- When you click a `b-link` with a `b-target`, LegoJS follows a strict search order to resolve the target:
19
+ When you click a `b-link` with a `b-target`, LegoDOM follows a strict search order to resolve the target:
20
20
 
21
21
  ### 1. Local Component Scope (The Primary Search)
22
22
 
23
- LegoJS first looks for the target **inside the component that contains the link**.
23
+ LegoDOM first looks for the target **inside the component that contains the link**.
24
24
 
25
25
  If you use `b-target="email-view"`, Lego looks for an `<email-view>` tag _within the current parent shell_. This allows you to have multiple instances of the same layout on one screen without them interfering with each other.
26
26
 
@@ -58,7 +58,7 @@ For highly dynamic UIs, `b-target` can even be a function or a dynamic expressio
58
58
 
59
59
  ```
60
60
  <!-- Logic decides the target based on screen size -->
61
- <a href="/settings" b-link b-target="{{ isMobile ? '#main' : 'settings-pane' }}">
61
+ <a href="/settings" b-link b-target="[[ isMobile ? '#main' : 'settings-pane' ]]">
62
62
  Settings
63
63
  </a>
64
64
 
@@ -66,7 +66,7 @@ For highly dynamic UIs, `b-target` can even be a function or a dynamic expressio
66
66
 
67
67
  ## Why This Matters
68
68
 
69
- By prioritizing local tags over global IDs, LegoJS encourages **Encapsulation**. Your components become "Black Boxes" that manage their own internal routing targets. This means you can take a complex "Messaging Shell" and drop it into a "Dashboard Shell" without changing a single line of routing code—the targets will still resolve correctly because they are scoped to their parents.
69
+ By prioritizing local tags over global IDs, LegoDOM encourages **Encapsulation**. Your components become "Black Boxes" that manage their own internal routing targets. This means you can take a complex "Messaging Shell" and drop it into a "Dashboard Shell" without changing a single line of routing code—the targets will still resolve correctly because they are scoped to their parents.
70
70
 
71
71
  ## Summary
72
72
 
@@ -1,6 +1,6 @@
1
1
  # Surgical Swaps: Mastering b-target
2
2
 
3
- The true power of LegoJS lies in its ability to perform **Surgical Swaps**. In a traditional application, clicking a link often causes the entire page to re-render, destroying the state of your sidebar, header, or scroll position.
3
+ The true power of LegoDOM lies in its ability to perform **Surgical Swaps**. In a traditional application, clicking a link often causes the entire page to re-render, destroying the state of your sidebar, header, or scroll position.
4
4
 
5
5
  With `b-target` (and optionally `b-link`), we can choose to update only a specific "fragment" of the page.
6
6
 
@@ -80,8 +80,8 @@ You can tell Lego to find a specific element by its ID and replace its contents.
80
80
  <aside class="sidebar">
81
81
  <div b-for="chat in threads">
82
82
  <!-- Parent component (this shell) binds data to these links -->
83
- <a href="/messaging/{{chat.id}}" b-target="#chat-window">
84
- {{chat.userName}}
83
+ <a href="/messaging/[[chat.id]]" b-target="#chat-window">
84
+ [[chat.userName]]
85
85
  </a>
86
86
  </div>
87
87
  </aside>
@@ -110,7 +110,7 @@ Because Lego is built on Custom Elements, you can target a component tag directl
110
110
 
111
111
  ## How the Target Resolver Works
112
112
 
113
- When you click a link with a `b-target`, the LegoJS **Target Resolver** follows a specific hierarchy:
113
+ When you click a link with a `b-target`, the LegoDOM **Target Resolver** follows a specific hierarchy:
114
114
 
115
115
  1. **Local Scope**: It looks for the target inside the current component first. This prevents "ID collisions" if you have multiple instances of a layout.
116
116
 
@@ -123,7 +123,7 @@ When you click a link with a `b-target`, the LegoJS **Target Resolver** follows
123
123
 
124
124
  ## Smart History
125
125
 
126
- Even though we are only swapping a small part of the DOM, LegoJS is smart enough to update the browser's address bar.
126
+ Even though we are only swapping a small part of the DOM, LegoDOM is smart enough to update the browser's address bar.
127
127
 
128
128
  When a surgical swap happens, Lego saves the "target" information into the browser's history state (`history.state.legoTargets`). This means that when a user hits the **Back Button**, Lego knows exactly which fragment needs to be swapped back to its previous state.
129
129
 
@@ -0,0 +1,152 @@
1
+ # Step 1: Project Setup
2
+
3
+ Let's create a new LegoDOM project from scratch. By the end of this page, you'll have a fully configured development environment ready to build components.
4
+
5
+ ## Create a New Project
6
+
7
+ Open your terminal and run:
8
+
9
+ ```bash
10
+ # Create a new Vite project
11
+ npm create vite@latest my-lego-app -- --template vanilla
12
+
13
+ # Enter the project
14
+ cd my-lego-app
15
+
16
+ # Install LegoDOM
17
+ npm install lego-dom
18
+
19
+ # Install dependencies
20
+ npm install
21
+ ```
22
+
23
+ ## Configure Vite
24
+
25
+ Create or replace `vite.config.js` in your project root:
26
+
27
+ ```javascript
28
+ import { defineConfig } from 'vite';
29
+ import legoPlugin from 'lego-dom/vite-plugin';
30
+
31
+ export default defineConfig({
32
+ plugins: [
33
+ legoPlugin({
34
+ componentsDir: './src/components', // Where your .lego files live
35
+ include: ['**/*.lego'] // File pattern to match
36
+ })
37
+ ]
38
+ });
39
+ ```
40
+
41
+ ## Project Structure
42
+
43
+ Create this folder structure:
44
+
45
+ ```
46
+ my-lego-app/
47
+ ├── index.html ← Your app's entry HTML
48
+ ├── src/
49
+ │ ├── app.js ← Your app's entry JavaScript ⭐
50
+ │ └── components/ ← Your .lego files go here
51
+ │ └── (empty for now)
52
+ ├── vite.config.js ← Vite configuration
53
+ └── package.json
54
+ ```
55
+
56
+ ::: warning The Magic File: `app.js`
57
+ This is where **everything comes together**. Your routes, global state, and initialization all happen here. We'll build it in the next section.
58
+ :::
59
+
60
+ ## Set Up Your Entry Point
61
+
62
+ Replace the contents of `src/app.js` (create it if it doesn't exist):
63
+
64
+ ```javascript
65
+ // 1. Import the Lego core
66
+ import { Lego } from 'lego-dom';
67
+
68
+ // 2. Import the virtual module that auto-discovers .lego files
69
+ import registerComponents from 'virtual:lego-components';
70
+
71
+ // 3. Register all discovered components
72
+ registerComponents();
73
+
74
+ // 4. Define your routes (we'll add these soon!)
75
+ // Lego.route('/', 'home-page');
76
+ // Lego.route('/login', 'login-page');
77
+
78
+ // 5. Initialize the engine
79
+ await Lego.init();
80
+ ```
81
+
82
+ > **What's happening here?**
83
+ > - Lines 1-3: Import LegoDOM and auto-register every `.lego` file in your `components/` folder
84
+ > - Line 4: Routes map URLs to components (commented out until we create them)
85
+ > - Line 5: `Lego.init()` starts the reactivity engine, routing, and DOM observation
86
+
87
+ ## Set Up Your HTML
88
+
89
+ Replace `index.html`:
90
+
91
+ ```html
92
+ <!DOCTYPE html>
93
+ <html lang="en">
94
+ <head>
95
+ <meta charset="UTF-8">
96
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
97
+ <title>My Lego App</title>
98
+ <style>
99
+ * { margin: 0; padding: 0; box-sizing: border-box; }
100
+ body {
101
+ font-family: system-ui, -apple-system, sans-serif;
102
+ background: #f5f5f5;
103
+ min-height: 100vh;
104
+ }
105
+ </style>
106
+ </head>
107
+ <body>
108
+ <!-- The router renders your page components here -->
109
+ <lego-router></lego-router>
110
+
111
+ <!-- Load your app -->
112
+ <script type="module" src="/src/app.js"></script>
113
+ </body>
114
+ </html>
115
+ ```
116
+
117
+ ## Run It
118
+
119
+ ```bash
120
+ npm run dev
121
+ ```
122
+
123
+ Open `http://localhost:5173` in your browser. You'll see a blank page—that's expected! We haven't created any components yet.
124
+
125
+ ## What You've Done
126
+
127
+ ✅ Created a Vite project
128
+ ✅ Installed LegoDOM
129
+ ✅ Configured the Vite plugin
130
+ ✅ Set up `app.js` with the Lego initialization pattern
131
+ ✅ Added `<lego-router>` to your HTML
132
+
133
+ ## The Key Insight
134
+
135
+ ::: tip Where Config Goes: The Golden Rule
136
+ **Everything related to your app's setup goes in `app.js`:**
137
+ - Component registration → `registerComponents()`
138
+ - Route definitions → `Lego.route(...)`
139
+ - Global state → `Lego.globals.user = ...`
140
+ - Initialization → `Lego.init()`
141
+
142
+ Your `index.html` just needs `<lego-router>` and a script tag. That's it.
143
+ :::
144
+
145
+ ---
146
+
147
+ <div style="display: flex; justify-content: space-between; margin-top: 3rem;">
148
+ <span></span>
149
+ <a href="./02-your-first-component" style="display: inline-block; background: #4CAF50; color: white; padding: 0.75rem 1.5rem; border-radius: 6px; text-decoration: none; font-weight: 600;">
150
+ Next: Your First Component →
151
+ </a>
152
+ </div>
@@ -0,0 +1,226 @@
1
+ # Step 2: Your First Component
2
+
3
+ Now let's create a component! By the end of this page, you'll understand the `.lego` file format and have a working home page.
4
+
5
+ ## Create Your First `.lego` File
6
+
7
+ Create `src/components/home-page.lego`:
8
+
9
+ ```html
10
+ <template>
11
+ <div class="hero">
12
+ <h1>[[ title ]]</h1>
13
+ <p>[[ subtitle ]]</p>
14
+ <button @click="handleClick()">[[ buttonText ]]</button>
15
+ </div>
16
+
17
+ <div class="features">
18
+ <div class="feature" b-for="feature in features">
19
+ <span class="icon">[[ feature.icon ]]</span>
20
+ <h3>[[ feature.title ]]</h3>
21
+ <p>[[ feature.description ]]</p>
22
+ </div>
23
+ </div>
24
+ </template>
25
+
26
+ <style>
27
+ self {
28
+ display: block;
29
+ min-height: 100vh;
30
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
31
+ color: white;
32
+ padding: 4rem 2rem;
33
+ }
34
+
35
+ .hero {
36
+ text-align: center;
37
+ max-width: 600px;
38
+ margin: 0 auto 4rem;
39
+ }
40
+
41
+ .hero h1 {
42
+ font-size: 3rem;
43
+ margin-bottom: 1rem;
44
+ }
45
+
46
+ .hero p {
47
+ font-size: 1.25rem;
48
+ opacity: 0.9;
49
+ margin-bottom: 2rem;
50
+ }
51
+
52
+ .hero button {
53
+ background: white;
54
+ color: #667eea;
55
+ border: none;
56
+ padding: 1rem 2.5rem;
57
+ font-size: 1.1rem;
58
+ font-weight: 600;
59
+ border-radius: 50px;
60
+ cursor: pointer;
61
+ transition: transform 0.2s, box-shadow 0.2s;
62
+ }
63
+
64
+ .hero button:hover {
65
+ transform: translateY(-2px);
66
+ box-shadow: 0 10px 20px rgba(0,0,0,0.2);
67
+ }
68
+
69
+ .features {
70
+ display: grid;
71
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
72
+ gap: 2rem;
73
+ max-width: 900px;
74
+ margin: 0 auto;
75
+ }
76
+
77
+ .feature {
78
+ background: rgba(255,255,255,0.1);
79
+ padding: 2rem;
80
+ border-radius: 16px;
81
+ text-align: center;
82
+ backdrop-filter: blur(10px);
83
+ }
84
+
85
+ .feature .icon {
86
+ font-size: 3rem;
87
+ display: block;
88
+ margin-bottom: 1rem;
89
+ }
90
+
91
+ .feature h3 {
92
+ margin-bottom: 0.5rem;
93
+ }
94
+
95
+ .feature p {
96
+ opacity: 0.8;
97
+ font-size: 0.9rem;
98
+ }
99
+ </style>
100
+
101
+ <script>
102
+ export default {
103
+ title: 'Welcome to My App',
104
+ subtitle: 'Built with LegoDOM – the tiny framework that loves developers',
105
+ buttonText: 'Get Started',
106
+
107
+ features: [
108
+ { icon: '⚡', title: 'Lightning Fast', description: 'No virtual DOM overhead' },
109
+ { icon: '🧩', title: 'Component-Based', description: 'Reusable building blocks' },
110
+ { icon: '🎨', title: 'Scoped Styles', description: 'CSS that never leaks' }
111
+ ],
112
+
113
+ handleClick() {
114
+ // We'll wire this up to navigation soon!
115
+ alert('Clicked! Next: we\'ll navigate to /login');
116
+ },
117
+
118
+ mounted() {
119
+ console.log('Home page mounted!');
120
+ }
121
+ }
122
+ </script>
123
+ ```
124
+
125
+ ## Understanding the Structure
126
+
127
+ Every `.lego` file has three sections:
128
+
129
+ ### 1. `<template>` – Your HTML
130
+
131
+ ```html
132
+ <template>
133
+ <h1>[[ title ]]</h1> <!-- Reactive text -->
134
+ <button @click="doSomething()"> <!-- Event binding -->
135
+ <div b-for="item in items"> <!-- Loop directive -->
136
+ </template>
137
+ ```
138
+
139
+ ### 2. `<style>` – Scoped CSS
140
+
141
+ ```html
142
+ <style>
143
+ self {
144
+ /* 'self' targets the component root (like :host) */
145
+ display: block;
146
+ }
147
+
148
+ button {
149
+ /* These styles ONLY affect this component */
150
+ }
151
+ </style>
152
+ ```
153
+
154
+ ### 3. `<script>` – Logic & State
155
+
156
+ ```html
157
+ <script>
158
+ export default {
159
+ // Reactive properties
160
+ title: 'Hello',
161
+ count: 0,
162
+ items: [],
163
+
164
+ // Methods
165
+ doSomething() {
166
+ this.count++; // Mutation triggers re-render!
167
+ },
168
+
169
+ // Lifecycle
170
+ mounted() {
171
+ console.log('Component is ready');
172
+ }
173
+ }
174
+ </script>
175
+ ```
176
+
177
+ ## Register the Route
178
+
179
+ Now update `src/app.js` to show your component:
180
+
181
+ ```javascript{7-8}
182
+ import { Lego } from 'lego-dom';
183
+ import registerComponents from 'virtual:lego-components';
184
+
185
+ registerComponents();
186
+
187
+ // Add this line:
188
+ Lego.route('/', 'home-page');
189
+
190
+ await Lego.init();
191
+ ```
192
+
193
+ ## See It Live
194
+
195
+ ```bash
196
+ npm run dev
197
+ ```
198
+
199
+ Open `http://localhost:5173` and you'll see your beautiful home page!
200
+
201
+ ## What You've Learned
202
+
203
+ ✅ The three-section `.lego` file structure
204
+ ✅ Template syntax: `[[ ]]` for data, `@click` for events, `b-for` for loops
205
+ ✅ The `self` keyword for component root styling
206
+ ✅ How to export state and methods from `<script>`
207
+ ✅ Connecting a component to a route
208
+
209
+ ## Key Pattern: Component → Route → Display
210
+
211
+ ```
212
+ home-page.lego → Lego.route('/', 'home-page') → <lego-router> shows it
213
+ ```
214
+
215
+ The filename (minus `.lego`) becomes the component name. Routes map URLs to component names. The router displays the matched component.
216
+
217
+ ---
218
+
219
+ <div style="display: flex; justify-content: space-between; margin-top: 3rem;">
220
+ <a href="./01-project-setup" style="display: inline-block; background: #eee; color: #333; padding: 0.75rem 1.5rem; border-radius: 6px; text-decoration: none; font-weight: 600;">
221
+ ← Previous: Project Setup
222
+ </a>
223
+ <a href="./03-adding-routes" style="display: inline-block; background: #4CAF50; color: white; padding: 0.75rem 1.5rem; border-radius: 6px; text-decoration: none; font-weight: 600;">
224
+ Next: Adding Routes →
225
+ </a>
226
+ </div>