lego-dom 0.0.9 → 1.0.0

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 (166) hide show
  1. package/CHANGELOG.md +44 -0
  2. package/README.md +1 -0
  3. package/{go.html → cdn.html} +33 -26
  4. package/docs/.vitepress/config.js +39 -1
  5. package/docs/api/directives.md +3 -3
  6. package/docs/api/index.md +1 -1
  7. package/docs/contributing/01-welcome.md +36 -0
  8. package/docs/contributing/02-registry.md +99 -0
  9. package/docs/contributing/03-batcher.md +110 -0
  10. package/docs/contributing/04-reactivity.md +87 -0
  11. package/docs/contributing/05-caching.md +59 -0
  12. package/docs/contributing/06-init.md +125 -0
  13. package/docs/contributing/07-observer.md +69 -0
  14. package/docs/contributing/08-snap.md +126 -0
  15. package/docs/contributing/09-diffing.md +69 -0
  16. package/docs/contributing/10-studs.md +76 -0
  17. package/docs/contributing/11-scanner.md +104 -0
  18. package/docs/contributing/12-render.md +116 -0
  19. package/docs/contributing/13-directives.md +225 -0
  20. package/docs/contributing/14-events.md +57 -0
  21. package/docs/contributing/15-router.md +9 -0
  22. package/docs/contributing/16-state.md +48 -0
  23. package/docs/contributing/17-legodom.md +55 -0
  24. package/docs/contributing/index.md +5 -0
  25. package/docs/examples/form.md +1 -1
  26. package/docs/examples/index.md +1 -1
  27. package/docs/examples/routing.md +4 -4
  28. package/docs/examples/todo-app.md +1 -1
  29. package/docs/guide/cdn-usage.md +8 -0
  30. package/docs/guide/components.md +33 -15
  31. package/docs/guide/directives.md +22 -22
  32. package/docs/guide/getting-started.md +35 -10
  33. package/docs/guide/index.md +3 -3
  34. package/docs/guide/quick-start.md +4 -1
  35. package/docs/guide/reactivity.md +22 -1
  36. package/docs/guide/routing.md +189 -289
  37. package/docs/guide/sfc.md +1 -1
  38. package/docs/guide/templating.md +2 -2
  39. package/docs/index.md +41 -7
  40. package/docs/router/basic-routing.md +103 -0
  41. package/docs/router/cold-entry.md +91 -0
  42. package/docs/router/history.md +69 -0
  43. package/docs/router/index.md +73 -0
  44. package/docs/router/resolver.md +74 -0
  45. package/docs/router/surgical-swaps.md +134 -0
  46. package/examples/vite-app/index.html +4 -12
  47. package/examples/vite-app/package.json +4 -2
  48. package/examples/vite-app/src/app.css +3 -0
  49. package/examples/vite-app/src/app.js +29 -0
  50. package/examples/vite-app/src/components/app-navbar.lego +34 -0
  51. package/examples/vite-app/src/components/customers/customer-details.lego +24 -0
  52. package/examples/vite-app/src/components/customers/customer-orders.lego +21 -0
  53. package/examples/vite-app/src/components/customers/order-list.lego +55 -0
  54. package/examples/vite-app/src/components/greeting-card.lego +1 -1
  55. package/examples/vite-app/src/components/sample-component.lego +15 -15
  56. package/examples/vite-app/src/components/shells/customers-shell.lego +21 -0
  57. package/examples/vite-app/src/components/todo-list.lego +12 -15
  58. package/examples/vite-app/src/components/widgets/user-card.lego +27 -0
  59. package/examples/vite-app/vite.config.js +5 -1
  60. package/main.js +247 -56
  61. package/package.json +1 -1
  62. package/parse-lego.js +17 -8
  63. package/{main.test.js → tests/main.test.js} +34 -17
  64. package/tests/parse-lego.test.js +65 -0
  65. package/vite-plugin.js +60 -22
  66. package/docs/.vitepress/dist/404.html +0 -22
  67. package/docs/.vitepress/dist/api/define.html +0 -35
  68. package/docs/.vitepress/dist/api/directives.html +0 -32
  69. package/docs/.vitepress/dist/api/globals.html +0 -27
  70. package/docs/.vitepress/dist/api/index.html +0 -25
  71. package/docs/.vitepress/dist/api/lifecycle.html +0 -38
  72. package/docs/.vitepress/dist/api/route.html +0 -34
  73. package/docs/.vitepress/dist/api/vite-plugin.html +0 -37
  74. package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.js +0 -11
  75. package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.lean.js +0 -1
  76. package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.js +0 -8
  77. package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.lean.js +0 -1
  78. package/docs/.vitepress/dist/assets/api_globals.md.CEznyRAY.js +0 -3
  79. package/docs/.vitepress/dist/assets/api_globals.md.CEznyRAY.lean.js +0 -1
  80. package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.js +0 -1
  81. package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.lean.js +0 -1
  82. package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.js +0 -14
  83. package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.lean.js +0 -1
  84. package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.js +0 -10
  85. package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.lean.js +0 -1
  86. package/docs/.vitepress/dist/assets/api_vite-plugin.md.DC8Li09k.js +0 -13
  87. package/docs/.vitepress/dist/assets/api_vite-plugin.md.DC8Li09k.lean.js +0 -1
  88. package/docs/.vitepress/dist/assets/app.BfblNDJy.js +0 -1
  89. package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.Crdp7-Zp.js +0 -1
  90. package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.C18E44rY.js +0 -9
  91. package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +0 -19
  92. package/docs/.vitepress/dist/assets/chunks/theme.VX3itTW6.js +0 -2
  93. package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.js +0 -34
  94. package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.lean.js +0 -1
  95. package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.js +0 -28
  96. package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.lean.js +0 -1
  97. package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.js +0 -338
  98. package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.lean.js +0 -1
  99. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.js +0 -13
  100. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.lean.js +0 -1
  101. package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.js +0 -297
  102. package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.lean.js +0 -1
  103. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.js +0 -182
  104. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.lean.js +0 -1
  105. package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.js +0 -174
  106. package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.lean.js +0 -1
  107. package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.js +0 -1
  108. package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.lean.js +0 -1
  109. package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.js +0 -140
  110. package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.lean.js +0 -1
  111. package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.js +0 -107
  112. package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.lean.js +0 -1
  113. package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.js +0 -2
  114. package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.lean.js +0 -1
  115. package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.js +0 -304
  116. package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.lean.js +0 -1
  117. package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.js +0 -33
  118. package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.lean.js +0 -1
  119. package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.js +0 -135
  120. package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.lean.js +0 -1
  121. package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.js +0 -193
  122. package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.lean.js +0 -1
  123. package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.js +0 -187
  124. package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.lean.js +0 -1
  125. package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.js +0 -119
  126. package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.lean.js +0 -1
  127. package/docs/.vitepress/dist/assets/index.md.M4_o26kF.js +0 -23
  128. package/docs/.vitepress/dist/assets/index.md.M4_o26kF.lean.js +0 -1
  129. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  130. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  131. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  132. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  133. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  134. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  135. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  136. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  137. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  138. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  139. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  140. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  141. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  142. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  143. package/docs/.vitepress/dist/assets/style.eycE2Jhw.css +0 -1
  144. package/docs/.vitepress/dist/examples/form.html +0 -58
  145. package/docs/.vitepress/dist/examples/index.html +0 -52
  146. package/docs/.vitepress/dist/examples/routing.html +0 -362
  147. package/docs/.vitepress/dist/examples/sfc-showcase.html +0 -37
  148. package/docs/.vitepress/dist/examples/todo-app.html +0 -321
  149. package/docs/.vitepress/dist/guide/cdn-usage.html +0 -206
  150. package/docs/.vitepress/dist/guide/components.html +0 -198
  151. package/docs/.vitepress/dist/guide/contributing.html +0 -25
  152. package/docs/.vitepress/dist/guide/directives.html +0 -164
  153. package/docs/.vitepress/dist/guide/getting-started.html +0 -131
  154. package/docs/.vitepress/dist/guide/index.html +0 -26
  155. package/docs/.vitepress/dist/guide/lifecycle.html +0 -328
  156. package/docs/.vitepress/dist/guide/quick-start.html +0 -57
  157. package/docs/.vitepress/dist/guide/reactivity.html +0 -159
  158. package/docs/.vitepress/dist/guide/routing.html +0 -217
  159. package/docs/.vitepress/dist/guide/sfc.html +0 -211
  160. package/docs/.vitepress/dist/guide/templating.html +0 -143
  161. package/docs/.vitepress/dist/hashmap.json +0 -1
  162. package/docs/.vitepress/dist/index.html +0 -47
  163. package/docs/.vitepress/dist/logo.svg +0 -38
  164. package/docs/.vitepress/dist/vp-icons.css +0 -1
  165. package/examples/vite-app/src/main.js +0 -11
  166. package/examples.js +0 -99
@@ -1,373 +1,273 @@
1
- # Routing
1
+ # Surgical Routing
2
2
 
3
- Lego includes a built-in client-side router for building single-page applications.
3
+ LegoDOM features a powerful "Surgical Router" that sets it apart from typical SPA routers. Instead of just replacing a single `<router-outlet>`, Lego allows you to swap **any** part of your page from **any** link, giving you the feel of a complex SPA with the simplicity of old-school HTML frames.
4
4
 
5
- ## Basic Setup
5
+ ## The Concept
6
6
 
7
- ### 1. Add Router Outlet
7
+ In traditional SPAs, you have one `RouterView` that swaps out entire pages.
8
+ In Lego, every link can be a router trigger, and every element can be a target.
8
9
 
9
- ```html
10
- <lego-router></lego-router>
11
- ```
10
+ - **`b-target`**: "Where should this content go?"
11
+ - **`b-link`**: "Should this update the URL history?"
12
12
 
13
- This is where your routed components will render.
13
+ ---
14
14
 
15
- ### 2. Define Routes
15
+ ## 1. Declarative Routing
16
16
 
17
- ```js
18
- Lego.route('/', 'home-page');
19
- Lego.route('/about', 'about-page');
20
- Lego.route('/contact', 'contact-page');
21
- ```
17
+ The most common way to route is using standard `<a>` tags enriched with Lego attributes.
22
18
 
23
- ### 3. Create Page Components
19
+ ### `b-target`
20
+ Specifies the CSS selector of the element to replace.
24
21
 
25
22
  ```html
26
- <template b-id="home-page">
27
- <h1>Home</h1>
28
- <p>Welcome to the homepage!</p>
29
- </template>
30
-
31
- <template b-id="about-page">
32
- <h1>About</h1>
33
- <p>Learn more about us.</p>
34
- </template>
23
+ <!-- Swaps content into <div id="main-content"> -->
24
+ <a href="/profile" b-target="#main-content">Go to Profile</a>
25
+
26
+ <!-- Example of using route params in a template -->
27
+ <main>
28
+ <blog-posts b-show="$route.params.section === 'posts'"></blog-posts>
29
+ <blog-authors b-show="$route.params.section === 'authors'"></blog-authors>
30
+ </main>
35
31
  ```
36
32
 
37
- ### 4. Add Navigation
33
+ ### `b-link`
34
+ Controls browser history behavior.
35
+ - `b-link` (or just `b-target`): Defaults to `true` (updates URL, pushes history).
36
+ - `b-link="false"`: Does **not** update the URL. Great for tabs, modals, or side-panels.
38
37
 
39
38
  ```html
40
- <nav>
41
- <a href="/" b-link>Home</a>
42
- <a href="/about" b-link>About</a>
43
- <a href="/contact" b-link>Contact</a>
44
- </nav>
39
+ <!-- Updates URL to /settings, swaps #main -->
40
+ <a href="/settings" b-target="#main">Settings</a>
45
41
 
46
- <lego-router></lego-router>
42
+ <!-- Keeps URL same, just swaps the sidebar context -->
43
+ <a href="/sidebar/tools" b-target="#sidebar" b-link="false">Open Tools</a>
47
44
  ```
48
45
 
49
- The `b-link` attribute hijacks clicks to prevent page reloads.
46
+ ### Deep Linking & Defaults
47
+ If a user refreshes the page, surgical targets (like `#sidebar`) usually won't have content because the `b-target` click never happened.
50
48
 
51
- ## Complete Example
49
+ **The Golden Rule:** Always have a `<lego-router>` as your default "Main" outlet.
50
+ When the page loads, Lego looks for `<lego-router>` to render the URL's matching component.
52
51
 
53
52
  ```html
54
- <!DOCTYPE html>
55
- <html>
56
- <head>
57
- <title>My SPA</title>
58
- <style>
59
- nav { padding: 1rem; background: #f0f0f0; }
60
- nav a { margin-right: 1rem; text-decoration: none; }
61
- nav a.active { font-weight: bold; }
62
- </style>
63
- </head>
64
53
  <body>
65
- <nav>
66
- <a href="/" b-link>Home</a>
67
- <a href="/blog" b-link>Blog</a>
68
- <a href="/about" b-link>About</a>
69
- </nav>
54
+ <nav>...</nav>
70
55
 
71
- <lego-router></lego-router>
72
-
73
- <template b-id="home-page">
74
- <h1>Welcome Home</h1>
75
- <p>This is the homepage.</p>
76
- </template>
56
+ <!-- Default Outlet: Renders /home, /about, etc. -->
57
+ <lego-router id="main-app"></lego-router>
77
58
 
78
- <template b-id="blog-page">
79
- <h1>Blog</h1>
80
- <ul>
81
- <li><a href="/blog/1" b-link>First Post</a></li>
82
- <li><a href="/blog/2" b-link>Second Post</a></li>
83
- </ul>
84
- </template>
85
-
86
- <template b-id="about-page">
87
- <h1>About Us</h1>
88
- <p>We build awesome things.</p>
89
- </template>
90
-
91
- <script src="https://unpkg.com/lego-dom/main.js"></script>
92
- <script>
93
- Lego.route('/', 'home-page');
94
- Lego.route('/blog', 'blog-page');
95
- Lego.route('/about', 'about-page');
96
- </script>
59
+ <!-- Surgical Outlet: Only updated when specifically targeted -->
60
+ <aside id="sidebar"></aside>
97
61
  </body>
98
- </html>
99
62
  ```
100
63
 
101
- ## Dynamic Routes
64
+ ## 2. The `$go` API
102
65
 
103
- Use `:param` syntax for URL parameters:
66
+ For full programmatic control, use the globally available `$go` helper. It allows for surgical updates from your JavaScript logic.
104
67
 
105
- ```js
106
- Lego.route('/user/:id', 'user-profile');
107
- Lego.route('/blog/:slug', 'blog-post');
108
- Lego.route('/category/:cat/item/:id', 'product-detail');
109
- ```
68
+ ### Syntax
69
+ `Lego.globals.$go(path, ...targets)`
110
70
 
111
- ### Accessing Parameters
71
+ - **path**: The URL to navigate to (e.g., `/user/1`).
72
+ - **targets**: A list of selectors (e.g., `#main`, `#sidebar`). Passing nothing defaults to `lego-router`.
112
73
 
113
- Route parameters are available in `global.params`:
74
+ ### Methods
75
+ The `$go` function returns an object with HTTP verb methods, primarily only `.get()` is relevant for routing, but others exist for consistency.
114
76
 
115
- ```html
116
- <template b-id="user-profile">
117
- <h1>User Profile</h1>
118
- <p>User ID: {{ global.params.id }}</p>
119
- <button @click="loadUser()">Load User</button>
120
- </template>
121
-
122
- <script>
123
- Lego.define('user-profile',
124
- Lego.registry['user-profile'].innerHTML, {
125
- async loadUser() {
126
- const userId = Lego.globals.params.id;
127
- const user = await fetch(`/api/users/${userId}`).then(r => r.json());
128
- this.username = user.name;
129
- }
130
- });
131
- </script>
132
- ```
77
+ ```javascript
78
+ // 1. Standard Navigation (pushes to history)
79
+ Lego.globals.$go('/profile').get();
133
80
 
134
- ## Programmatic Navigation
81
+ // 2. Surgical Navigation (updates #sidebar, pushes to history)
82
+ Lego.globals.$go('/widgets/clock', '#sidebar').get();
135
83
 
136
- Navigate programmatically using the History API:
84
+ // 3. Silent Update (updates #modal, NO history change)
85
+ // Pass `false` as the first argument to .get()
86
+ Lego.globals.$go('/modals/login', '#modal').get(false);
87
+ ```
137
88
 
138
- ```js
139
- // Navigate to a new route
140
- history.pushState({}, '', '/about');
141
- window.dispatchEvent(new PopStateEvent('popstate'));
89
+ ### Interactive Example: "The Shell"
90
+ You can update **multiple** targets at once (future feature) or chain them.
91
+ Commonly, you use `$go` inside your component logic:
142
92
 
143
- // Or in a component method:
144
- {
145
- goToAbout() {
146
- history.pushState({}, '', '/about');
147
- window.dispatchEvent(new PopStateEvent('popstate'));
93
+ ```html
94
+ <script>
95
+ export default {
96
+ methods: {
97
+ async loadUser() {
98
+ const userId = Lego.globals.$route.params.id; // Access in JS logic
99
+ const user = await fetch(`/api/users/${userId}`).then(r => r.json());
100
+ this.username = user.name;
101
+ },
102
+ openSettings() {
103
+ // Open settings in the sidebar without losing the main page context
104
+ this.global.$go('/settings-panel', '#sidebar').get(false);
105
+ }
106
+ }
148
107
  }
149
- }
108
+ </script>
150
109
  ```
151
110
 
152
- ## Route Middleware
111
+ ---
153
112
 
154
- Add middleware for authentication, logging, etc:
113
+ ## 3. Advanced Patterns
155
114
 
156
- ```js
157
- // Define middleware function
158
- const authMiddleware = (params, globals) => {
159
- if (!globals.isLoggedIn) {
160
- history.pushState({}, '', '/login');
161
- window.dispatchEvent(new PopStateEvent('popstate'));
162
- return false; // Block navigation
163
- }
164
- return true; // Allow navigation
165
- };
166
-
167
- // Apply to routes
168
- Lego.route('/dashboard', 'dashboard-page', authMiddleware);
169
- Lego.route('/profile', 'profile-page', authMiddleware);
170
- ```
115
+ ### The "Sidebar" Pattern
116
+ Keep a persistent Main Content while swapping sidebars.
171
117
 
172
- ### Middleware Example
118
+ ```html
119
+ <nav>
120
+ <!-- Main Nav: Updates URL and main view -->
121
+ <a href="/dashboard" b-target="#main">Dashboard</a>
122
+ <a href="/files" b-target="#main">Files</a>
123
+ </nav>
173
124
 
174
- ```js
175
- // Logging middleware
176
- const logger = (params) => {
177
- console.log('Navigating to:', params);
178
- return true;
179
- };
125
+ <main id="main">
126
+ <!-- Dashboard or Files render here -->
127
+ </main>
180
128
 
181
- // Analytics middleware
182
- const analytics = (params) => {
183
- if (window.gtag) {
184
- gtag('event', 'page_view', { page_path: window.location.pathname });
185
- }
186
- return true;
187
- };
129
+ <aside id="context-pane">
130
+ <!-- Context specific tools render here -->
131
+ <template b-id="user-profile">
132
+ <h1>User Profile</h1>
133
+ <p>User ID: {{ $route.params.id }}</p>
134
+ <button @click="loadUser()">Load User</button>
135
+ </template>
136
+ </aside>
188
137
 
189
- // Apply
190
- Lego.route('/products/:id', 'product-page', (params, globals) => {
191
- logger(params);
192
- analytics(params);
193
- return true;
194
- });
138
+ <!-- Inside Dashboard Component -->
139
+ <button onclick="Lego.globals.$go('/tools/chart-config', '#context-pane').get(false)">
140
+ Configure Chart
141
+ </button>
195
142
  ```
196
143
 
197
- ## Active Link Styling
144
+ ### The "Modal" Pattern
145
+ Render a route into a modal dialog container.
198
146
 
199
- Style active navigation links:
147
+ ```html
148
+ <dialog id="modal-container"></dialog>
200
149
 
201
- ```js
202
- // Update active class on navigation
203
- window.addEventListener('popstate', () => {
204
- document.querySelectorAll('[b-link]').forEach(link => {
205
- const isActive = link.getAttribute('href') === window.location.pathname;
206
- link.classList.toggle('active', isActive);
207
- });
208
- });
150
+ <a href="/login" b-target="#modal-container"
151
+ onclick="document.getElementById('modal-container').showModal()">
152
+ Login
153
+ </a>
209
154
  ```
210
155
 
211
- ## 404 / Not Found
156
+ ### The "Persistent Layout" Pattern (The Holy Grail)
157
+ This is where LegoDOM outshines traditional routers. You can have static sidebars that **never** reload, while the center content changes dynamically.
212
158
 
213
- Handle unknown routes:
159
+ ```html
160
+ <body>
161
+ <!-- LEFT: Never reloads. Keeps scroll position & expanded folders. -->
162
+ <aside id="static-left">
163
+ <file-tree></file-tree>
164
+ </aside>
214
165
 
215
- ```js
216
- // Define all your routes
217
- Lego.route('/', 'home-page');
218
- Lego.route('/about', 'about-page');
166
+ <!-- CENTER: The main router outlet -->
167
+ <lego-router id="main-content"></lego-router>
219
168
 
220
- // Catch-all for 404
221
- const matchRoute = () => {
222
- const path = window.location.pathname;
223
- const routes = ['/', '/about']; // Your known routes
224
-
225
- if (!routes.includes(path)) {
226
- // Show 404
227
- document.querySelector('lego-router').innerHTML = '<not-found></not-found>';
228
- }
229
- };
230
-
231
- window.addEventListener('popstate', matchRoute);
232
- matchRoute(); // Initial check
169
+ <!-- RIGHT: Context panel for tools/details -->
170
+ <aside id="static-right"></aside>
171
+ </body>
233
172
  ```
173
+ * **Main Links:** `<a href="/page" b-target="#main-content">`
174
+ * **Tool Links:** `<a href="/tool" b-target="#static-right">`
234
175
 
235
- ## Nested Routes
176
+ ---
236
177
 
237
- While Lego doesn't have built-in nested routing, you can implement it:
178
+ ## 4. Deep Routing Strategies
238
179
 
239
- ```html
240
- <template b-id="blog-layout">
241
- <aside>
242
- <a href="/blog/posts" b-link>Posts</a>
243
- <a href="/blog/authors" b-link>Authors</a>
244
- </aside>
245
- <main>
246
- <blog-posts b-if="global.params.section === 'posts'"></blog-posts>
247
- <blog-authors b-if="global.params.section === 'authors'"></blog-authors>
248
- </main>
249
- </template>
250
- ```
180
+ When handling deep routes like `/customers/:id/orders/:orderId`, you have two architectural choices.
251
181
 
252
- ```js
253
- Lego.route('/blog/:section', 'blog-layout');
254
- ```
182
+ ### Option A: The Shell Strategy (Self-Healing)
183
+ Map everything to a single "Shell" component. The Shell determines what to show in its sub-outlets based on the URL params.
255
184
 
256
- ## Query Strings
185
+ * **Pros:** Highly surgical. The Shell never re-renders, only its children do.
186
+ * **Cons:** Requires logic in `mounted()` to "heal" the state on page load.
257
187
 
258
- Access query parameters using URLSearchParams:
188
+ ```javascript
189
+ // Route Configuration
190
+ Lego.route('/customers/:id', 'customers-shell');
191
+ Lego.route('/customers/:id/orders/:orderId', 'customers-shell');
259
192
 
260
- ```js
261
- {
262
- mounted() {
263
- const params = new URLSearchParams(window.location.search);
264
- this.searchQuery = params.get('q') || '';
265
- this.page = parseInt(params.get('page')) || 1;
193
+ // Component Logic (Self-Healing)
194
+ mounted() {
195
+ if (this.$route.params.orderId) {
196
+ this.$go(window.location.pathname, '#details-pane').get();
266
197
  }
267
198
  }
268
199
  ```
269
200
 
270
- Example: `/search?q=legojs&page=2`
271
-
272
- ## Hash vs History Mode
201
+ ### Option B: The Page Strategy (Component Nesting)
202
+ Map deep routes to specific "Page" components. Each page imports and wraps itself in a shared Layout.
273
203
 
274
- Lego uses History API (pushState) by default, giving you clean URLs:
204
+ * **Pros:** Simpler logic. No "healing" code required.
205
+ * **Cons:** The Layout is technically re-created on every route change (though diffing makes it cheap).
275
206
 
276
- ✅ `/about`
277
- `/user/123`
278
- `/blog/my-post`
279
-
280
- Not hash-based:
281
- ❌ `#/about`
282
- ❌ `#/user/123`
283
-
284
- ### Server Configuration
285
-
286
- For clean URLs to work, configure your server to serve `index.html` for all routes:
287
-
288
- **nginx:**
289
- ```nginx
290
- location / {
291
- try_files $uri $uri/ /index.html;
292
- }
207
+ ```javascript
208
+ // Route Configuration
209
+ Lego.route('/customers/:id/orders/:orderId', 'order-details-page');
293
210
  ```
294
211
 
295
- **Apache (.htaccess):**
296
- ```apache
297
- RewriteEngine On
298
- RewriteCond %{REQUEST_FILENAME} !-f
299
- RewriteCond %{REQUEST_FILENAME} !-d
300
- RewriteRule ^ index.html [L]
212
+ ```html
213
+ <!-- order-details-page.lego -->
214
+ <template>
215
+ <customers-layout>
216
+ <order-info id="{{ $route.params.orderId }}"></order-info>
217
+ </customers-layout>
218
+ </template>
301
219
  ```
302
220
 
303
- **Node.js/Express:**
304
- ```js
305
- app.get('*', (req, res) => {
306
- res.sendFile(path.join(__dirname, 'index.html'));
307
- });
308
- ```
221
+ ---
309
222
 
310
- ## Best Practices
223
+ ## 5. Middleware & Guards
311
224
 
312
- ### 1. Centralize Route Definitions
225
+ Middleware runs **before** the surgical swap happens. It### Accessing Parameters
226
+ Route parameters are available directly via `$route.params` in templates.
313
227
 
314
- ```js
315
- // routes.js
316
- const routes = {
317
- '/': 'home-page',
318
- '/blog': 'blog-page',
319
- '/blog/:slug': 'blog-post',
320
- '/user/:id': 'user-profile',
321
- '/about': 'about-page'
322
- };
228
+ > **Note:** `$route` is a global helper available in all templates.
323
229
 
324
- Object.entries(routes).forEach(([path, component]) => {
325
- Lego.route(path, component);
326
- });
327
- ```
230
+ ```javascript
231
+ /*
232
+ * Middleware Signature:
233
+ * (params: Object, globals: Object) => boolean | Promise<boolean>
234
+ * Return `true` to allow navigation, `false` to block.
235
+ */
328
236
 
329
- ### 2. Loading States
237
+ // Example: Auth Guard
238
+ const requireAuth = (params, globals) => {
239
+ if (!globals.user) {
240
+ // Redirect to login using surgical routing!
241
+ globals.$go('/login', '#main').get();
242
+ return false; // Stop original navigation
243
+ }
244
+ return true;
245
+ };
330
246
 
331
- ```html
332
- <template b-id="user-profile">
333
- <div b-if="loading">Loading...</div>
334
- <div b-if="!loading">
335
- <h1>{{ user.name }}</h1>
336
- <p>{{ user.bio }}</p>
337
- </div>
338
- </template>
247
+ Lego.route('/admin', 'admin-panel', requireAuth);
339
248
  ```
340
249
 
341
- ### 3. Error Handling
342
-
343
- ```js
344
- {
345
- async loadData() {
346
- this.loading = true;
347
- this.error = null;
348
- try {
349
- const data = await fetch('/api/data').then(r => r.json());
350
- this.data = data;
351
- } catch (err) {
352
- this.error = 'Failed to load data';
353
- } finally {
354
- this.loading = false;
355
- }
356
- }
357
- }
358
- ```
250
+ ## 5. Smart History
359
251
 
360
- ## Limitations
252
+ Lego's router is "History Aware".
253
+ When you use `b-target`, Lego stores the target selectors in the browser's History State.
361
254
 
362
- - No nested router outlets (single level only)
363
- - No route guards (use middleware instead)
364
- - No automatic scroll restoration
365
- - Routes must be defined upfront (not lazy-loaded)
255
+ **What this means:**
256
+ 1. You click "Open Sidebar" (Surgical update to `#sidebar`).
257
+ 2. You click "Home" (Main update to `#main`).
258
+ 3. You click **Back**.
259
+ 4. Lego automatically knows to reverse the "Home" navigation.
260
+ 5. You click **Back** again.
261
+ 6. Lego knows the previous state was a surgical update to `#sidebar` and restores it correctly!
366
262
 
367
- For complex routing needs, consider integrating a dedicated router library.
263
+ ## Summary Table
368
264
 
369
- ## Next Steps
265
+ | Feature | Code | Description |
266
+ | :--- | :--- | :--- |
267
+ | **Standard Link** | `<a href="/x">` | Standard browser navigation (full reload). |
268
+ | **SPA Link** | `<a href="/x" b-target>` | Default SPA nav. Swaps `<lego-router>`. |
269
+ | **Surgical Link** | `<a href="/x" b-target="#id">` | Swaps content of `#id`. Updates URL. |
270
+ | **Silent Link** | `... b-link="false">` | Swaps content. **No** URL update. |
271
+ | **JS Nav** | `$go('/x').get()` | Programmatic navigation. |
272
+ | **Silent JS** | `$go('/x').get(false)` | Programmatic silent swap. |
370
273
 
371
- - See [routing examples](/examples/routing)
372
- - Learn about [lifecycle hooks](/guide/lifecycle)
373
- - Explore [state management patterns](/guide/reactivity)
package/docs/guide/sfc.md CHANGED
@@ -215,7 +215,7 @@ Contains your component's HTML markup with Lego directives:
215
215
  ```html
216
216
  <template>
217
217
  <h1>{{ title }}</h1>
218
- <p b-if="showContent">{{ content }}</p>
218
+ <p b-show="showContent">{{ content }}</p>
219
219
  <ul>
220
220
  <li b-for="item in items">{{ item }}</li>
221
221
  </ul>
@@ -343,8 +343,8 @@ If a calculation is expensive, cache it:
343
343
  ### Show/Hide Based on Condition
344
344
 
345
345
  ```html
346
- <p b-if="user">Welcome, {{ user.name }}!</p>
347
- <p b-if="!user">Please log in</p>
346
+ <p b-show="user">Welcome, {{ user.name }}!</p>
347
+ <p b-show="!user">Please log in</p>
348
348
  ```
349
349
 
350
350
  ### List with Index
package/docs/index.md CHANGED
@@ -57,11 +57,35 @@ features:
57
57
  details: Battle-tested patterns from Vue and React, adapted for pure Web Components. No framework lock-in.
58
58
  ---
59
59
 
60
- ## Quick Example
60
+ ## Components & Naming
61
+
62
+ How you name your components depends on how you use Lego:
63
+
64
+ ### 1. Vite / Build Tools (Recommended)
65
+ **Convention over Configuration.** The filename *is* the tag name.
66
+ - `user-card.lego` → `<user-card></user-card>`
67
+ - `app-nav.lego` → `<app-nav></app-nav>`
68
+
69
+ You do not need `b-id` inside `.lego` files; the build system handles registration automatically.
70
+
71
+ ### 2. CDN / Script Tags
72
+ Since there are no files, you must explicitly name your components using the `b-id` attribute on the `<template>` tag.
73
+
74
+ ```html
75
+ <!-- Only needed for CDN usage -->
76
+ <template b-id="user-profile">
77
+ <h1>User Profile</h1>
78
+ </template>
79
+ ```
80
+
81
+ ## Quick Start (CDN)
61
82
 
62
83
  ```html
63
84
  <!-- Define a component -->
64
- <template b-id="counter-button">
85
+ <template b-id="counter-button" b-data="{
86
+ title: 'My counter',
87
+ count: 0
88
+ }">
65
89
  <style>
66
90
  self {
67
91
  display: block;
@@ -80,13 +104,25 @@ features:
80
104
  </template>
81
105
 
82
106
  <!-- Use it -->
83
- <counter-button b-data="{ title: 'My Counter', count: 0 }"></counter-button>
107
+ <counter-button b-data="{ title: 'Override b-data title' }"></counter-button>
84
108
 
85
109
  <script src="https://unpkg.com/lego-dom/main.js"></script>
110
+ <script>
111
+ // Complete the initialization
112
+ Lego.init();
113
+ </script>
86
114
  ```
87
115
 
88
116
  That's it. No build step, no npm, no configuration.
89
117
 
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:
121
+ > - **Reactivity** to data changes won't work.
122
+ > - **Mustaches** (<code v-pre>{{...}}</code>) outside of components won't hydrate.
123
+ > - **Single Page Routing** won't be activated.
124
+ > - **New components** added to the DOM dynamically won't be auto-initialized.
125
+
90
126
  ## Why Lego?
91
127
 
92
128
  **For small projects**, you get reactive components without the overhead of a full framework.
@@ -119,8 +155,6 @@ Lego works in all modern browsers that support:
119
155
  This includes Chrome 63+, Firefox 63+, Safari 11.1+, and Edge 79+.
120
156
 
121
157
  ## Community
122
-
123
- - 📖 [Documentation](https://rayattack.github.io/Lego/)
124
- - 💬 [Discussions](https://github.com/rayattack/Lego/discussions)
125
- - 🐛 [Issue Tracker](https://github.com/rayattack/Lego/issues)
158
+ - 💬 [Discussions](https://github.com/rayattack/LegoDOM/discussions)
159
+ - 🐛 [Issue Tracker](https://github.com/rayattack/LegoDOM/issues)
126
160
  - 📦 [npm Package](https://www.npmjs.com/package/lego-dom)