lego-dom 0.0.7 → 0.0.8

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 (143) hide show
  1. package/.github/workflows/deploy-docs.yml +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +122 -0
  4. package/docs/.vitepress/config.js +107 -0
  5. package/docs/.vitepress/dist/404.html +22 -0
  6. package/docs/.vitepress/dist/api/define.html +35 -0
  7. package/docs/.vitepress/dist/api/directives.html +32 -0
  8. package/docs/.vitepress/dist/api/globals.html +27 -0
  9. package/docs/.vitepress/dist/api/index.html +25 -0
  10. package/docs/.vitepress/dist/api/lifecycle.html +38 -0
  11. package/docs/.vitepress/dist/api/route.html +34 -0
  12. package/docs/.vitepress/dist/api/vite-plugin.html +37 -0
  13. package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.js +11 -0
  14. package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.lean.js +1 -0
  15. package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.js +8 -0
  16. package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.lean.js +1 -0
  17. package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.js +3 -0
  18. package/docs/.vitepress/dist/assets/api_globals.md.DOjt7AV0.lean.js +1 -0
  19. package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.js +1 -0
  20. package/docs/.vitepress/dist/assets/api_index.md.OS6h01ct.lean.js +1 -0
  21. package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.js +14 -0
  22. package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.lean.js +1 -0
  23. package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.js +10 -0
  24. package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.lean.js +1 -0
  25. package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.js +13 -0
  26. package/docs/.vitepress/dist/assets/api_vite-plugin.md.DNn9VhL5.lean.js +1 -0
  27. package/docs/.vitepress/dist/assets/app.BG5s3B0P.js +1 -0
  28. package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.DQmuWC2Z.js +1 -0
  29. package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.BO-PSxt1.js +9 -0
  30. package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +19 -0
  31. package/docs/.vitepress/dist/assets/chunks/theme.DA-iSa9B.js +2 -0
  32. package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.js +34 -0
  33. package/docs/.vitepress/dist/assets/examples_form.md.B3stGKbu.lean.js +1 -0
  34. package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.js +30 -0
  35. package/docs/.vitepress/dist/assets/examples_index.md.BDEG_D4J.lean.js +1 -0
  36. package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.js +338 -0
  37. package/docs/.vitepress/dist/assets/examples_routing.md.bqZ9DjDK.lean.js +1 -0
  38. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.js +13 -0
  39. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DLXaUiop.lean.js +1 -0
  40. package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.js +297 -0
  41. package/docs/.vitepress/dist/assets/examples_todo-app.md.D5RhZoo5.lean.js +1 -0
  42. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.js +182 -0
  43. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CAjf03Lr.lean.js +1 -0
  44. package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.js +174 -0
  45. package/docs/.vitepress/dist/assets/guide_components.md.BIFWF1Hc.lean.js +1 -0
  46. package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.js +1 -0
  47. package/docs/.vitepress/dist/assets/guide_contributing.md.BgbUN-Mr.lean.js +1 -0
  48. package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.js +140 -0
  49. package/docs/.vitepress/dist/assets/guide_directives.md.Bi3ynu1d.lean.js +1 -0
  50. package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.js +107 -0
  51. package/docs/.vitepress/dist/assets/guide_getting-started.md.2Nr1lp2z.lean.js +1 -0
  52. package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.js +2 -0
  53. package/docs/.vitepress/dist/assets/guide_index.md.GvZq_Yf2.lean.js +1 -0
  54. package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.js +304 -0
  55. package/docs/.vitepress/dist/assets/guide_lifecycle.md.B28j1OzS.lean.js +1 -0
  56. package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.js +33 -0
  57. package/docs/.vitepress/dist/assets/guide_quick-start.md.CNk3VGTF.lean.js +1 -0
  58. package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.js +135 -0
  59. package/docs/.vitepress/dist/assets/guide_reactivity.md.CVsaMaPv.lean.js +1 -0
  60. package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.js +193 -0
  61. package/docs/.vitepress/dist/assets/guide_routing.md.DSpDP25o.lean.js +1 -0
  62. package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.js +187 -0
  63. package/docs/.vitepress/dist/assets/guide_sfc.md.CVUP66tS.lean.js +1 -0
  64. package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.js +119 -0
  65. package/docs/.vitepress/dist/assets/guide_templating.md.BgCGe4aa.lean.js +1 -0
  66. package/docs/.vitepress/dist/assets/index.md.xV1taCED.js +23 -0
  67. package/docs/.vitepress/dist/assets/index.md.xV1taCED.lean.js +1 -0
  68. package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  69. package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  70. package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  71. package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  72. package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  73. package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  74. package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  75. package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  76. package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  77. package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  78. package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  79. package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  80. package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  81. package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  82. package/docs/.vitepress/dist/assets/style.eycE2Jhw.css +1 -0
  83. package/docs/.vitepress/dist/examples/form.html +58 -0
  84. package/docs/.vitepress/dist/examples/index.html +368 -0
  85. package/docs/.vitepress/dist/examples/routing.html +362 -0
  86. package/docs/.vitepress/dist/examples/sfc-showcase.html +37 -0
  87. package/docs/.vitepress/dist/examples/todo-app.html +321 -0
  88. package/docs/.vitepress/dist/guide/cdn-usage.html +206 -0
  89. package/docs/.vitepress/dist/guide/components.html +198 -0
  90. package/docs/.vitepress/dist/guide/contributing.html +25 -0
  91. package/docs/.vitepress/dist/guide/directives.html +164 -0
  92. package/docs/.vitepress/dist/guide/getting-started.html +131 -0
  93. package/docs/.vitepress/dist/guide/index.html +26 -0
  94. package/docs/.vitepress/dist/guide/lifecycle.html +328 -0
  95. package/docs/.vitepress/dist/guide/quick-start.html +57 -0
  96. package/docs/.vitepress/dist/guide/reactivity.html +159 -0
  97. package/docs/.vitepress/dist/guide/routing.html +217 -0
  98. package/docs/.vitepress/dist/guide/sfc.html +211 -0
  99. package/docs/.vitepress/dist/guide/templating.html +143 -0
  100. package/docs/.vitepress/dist/hashmap.json +1 -0
  101. package/docs/.vitepress/dist/index.html +47 -0
  102. package/docs/.vitepress/dist/logo.svg +38 -0
  103. package/docs/.vitepress/dist/vp-icons.css +1 -0
  104. package/docs/api/define.md +31 -0
  105. package/docs/api/directives.md +42 -0
  106. package/docs/api/globals.md +29 -0
  107. package/docs/api/index.md +29 -0
  108. package/docs/api/lifecycle.md +40 -0
  109. package/docs/api/route.md +37 -0
  110. package/docs/api/vite-plugin.md +58 -0
  111. package/docs/examples/form.md +42 -0
  112. package/docs/examples/index.md +104 -0
  113. package/docs/examples/routing.md +409 -0
  114. package/docs/examples/sfc-showcase.md +34 -0
  115. package/docs/examples/todo-app.md +383 -0
  116. package/docs/guide/cdn-usage.md +320 -0
  117. package/docs/guide/components.md +394 -0
  118. package/docs/guide/contributing.md +32 -0
  119. package/docs/guide/directives.md +430 -0
  120. package/docs/guide/getting-started.md +233 -0
  121. package/docs/guide/index.md +88 -0
  122. package/docs/guide/lifecycle.md +493 -0
  123. package/docs/guide/quick-start.md +46 -0
  124. package/docs/guide/reactivity.md +394 -0
  125. package/docs/guide/routing.md +373 -0
  126. package/docs/guide/sfc.md +381 -0
  127. package/docs/guide/templating.md +383 -0
  128. package/docs/index.md +126 -0
  129. package/docs/public/logo.svg +38 -0
  130. package/examples/vite-app/README.md +71 -0
  131. package/examples/vite-app/index.html +45 -0
  132. package/examples/vite-app/package.json +16 -0
  133. package/examples/vite-app/src/components/greeting-card.lego +41 -0
  134. package/examples/vite-app/src/components/sample-component.lego +75 -0
  135. package/examples/vite-app/src/main.js +11 -0
  136. package/examples/vite-app/vite.config.js +16 -0
  137. package/examples.js +99 -0
  138. package/package.json +33 -5
  139. package/parse-lego.js +119 -0
  140. package/parse-lego.test.js +107 -0
  141. package/vite-plugin.js +133 -0
  142. package/.ignore/auto.html +0 -135
  143. package/.ignore/test.html +0 -73
@@ -0,0 +1,373 @@
1
+ # Routing
2
+
3
+ LegoJS includes a built-in client-side router for building single-page applications.
4
+
5
+ ## Basic Setup
6
+
7
+ ### 1. Add Router Outlet
8
+
9
+ ```html
10
+ <lego-router></lego-router>
11
+ ```
12
+
13
+ This is where your routed components will render.
14
+
15
+ ### 2. Define Routes
16
+
17
+ ```js
18
+ Lego.route('/', 'home-page');
19
+ Lego.route('/about', 'about-page');
20
+ Lego.route('/contact', 'contact-page');
21
+ ```
22
+
23
+ ### 3. Create Page Components
24
+
25
+ ```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>
35
+ ```
36
+
37
+ ### 4. Add Navigation
38
+
39
+ ```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>
45
+
46
+ <lego-router></lego-router>
47
+ ```
48
+
49
+ The `b-link` attribute hijacks clicks to prevent page reloads.
50
+
51
+ ## Complete Example
52
+
53
+ ```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
+ <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>
70
+
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>
77
+
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>
97
+ </body>
98
+ </html>
99
+ ```
100
+
101
+ ## Dynamic Routes
102
+
103
+ Use `:param` syntax for URL parameters:
104
+
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
+ ```
110
+
111
+ ### Accessing Parameters
112
+
113
+ Route parameters are available in `global.params`:
114
+
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
+ ```
133
+
134
+ ## Programmatic Navigation
135
+
136
+ Navigate programmatically using the History API:
137
+
138
+ ```js
139
+ // Navigate to a new route
140
+ history.pushState({}, '', '/about');
141
+ window.dispatchEvent(new PopStateEvent('popstate'));
142
+
143
+ // Or in a component method:
144
+ {
145
+ goToAbout() {
146
+ history.pushState({}, '', '/about');
147
+ window.dispatchEvent(new PopStateEvent('popstate'));
148
+ }
149
+ }
150
+ ```
151
+
152
+ ## Route Middleware
153
+
154
+ Add middleware for authentication, logging, etc:
155
+
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
+ ```
171
+
172
+ ### Middleware Example
173
+
174
+ ```js
175
+ // Logging middleware
176
+ const logger = (params) => {
177
+ console.log('Navigating to:', params);
178
+ return true;
179
+ };
180
+
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
+ };
188
+
189
+ // Apply
190
+ Lego.route('/products/:id', 'product-page', (params, globals) => {
191
+ logger(params);
192
+ analytics(params);
193
+ return true;
194
+ });
195
+ ```
196
+
197
+ ## Active Link Styling
198
+
199
+ Style active navigation links:
200
+
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
+ });
209
+ ```
210
+
211
+ ## 404 / Not Found
212
+
213
+ Handle unknown routes:
214
+
215
+ ```js
216
+ // Define all your routes
217
+ Lego.route('/', 'home-page');
218
+ Lego.route('/about', 'about-page');
219
+
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
233
+ ```
234
+
235
+ ## Nested Routes
236
+
237
+ While LegoJS doesn't have built-in nested routing, you can implement it:
238
+
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
+ ```
251
+
252
+ ```js
253
+ Lego.route('/blog/:section', 'blog-layout');
254
+ ```
255
+
256
+ ## Query Strings
257
+
258
+ Access query parameters using URLSearchParams:
259
+
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;
266
+ }
267
+ }
268
+ ```
269
+
270
+ Example: `/search?q=legojs&page=2`
271
+
272
+ ## Hash vs History Mode
273
+
274
+ LegoJS uses History API (pushState) by default, giving you clean URLs:
275
+
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
+ }
293
+ ```
294
+
295
+ **Apache (.htaccess):**
296
+ ```apache
297
+ RewriteEngine On
298
+ RewriteCond %{REQUEST_FILENAME} !-f
299
+ RewriteCond %{REQUEST_FILENAME} !-d
300
+ RewriteRule ^ index.html [L]
301
+ ```
302
+
303
+ **Node.js/Express:**
304
+ ```js
305
+ app.get('*', (req, res) => {
306
+ res.sendFile(path.join(__dirname, 'index.html'));
307
+ });
308
+ ```
309
+
310
+ ## Best Practices
311
+
312
+ ### 1. Centralize Route Definitions
313
+
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
+ };
323
+
324
+ Object.entries(routes).forEach(([path, component]) => {
325
+ Lego.route(path, component);
326
+ });
327
+ ```
328
+
329
+ ### 2. Loading States
330
+
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>
339
+ ```
340
+
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
+ ```
359
+
360
+ ## Limitations
361
+
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)
366
+
367
+ For complex routing needs, consider integrating a dedicated router library.
368
+
369
+ ## Next Steps
370
+
371
+ - See [routing examples](/examples/routing)
372
+ - Learn about [lifecycle hooks](/guide/lifecycle)
373
+ - Explore [state management patterns](/guide/reactivity)