lego-dom 0.0.7 → 0.0.9

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 (147) hide show
  1. package/.github/workflows/deploy-docs.yml +56 -0
  2. package/LICENSE +21 -0
  3. package/README.md +52 -314
  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.CEznyRAY.js +3 -0
  18. package/docs/.vitepress/dist/assets/api_globals.md.CEznyRAY.lean.js +1 -0
  19. package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.js +1 -0
  20. package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.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.DC8Li09k.js +13 -0
  26. package/docs/.vitepress/dist/assets/api_vite-plugin.md.DC8Li09k.lean.js +1 -0
  27. package/docs/.vitepress/dist/assets/app.BfblNDJy.js +1 -0
  28. package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.Crdp7-Zp.js +1 -0
  29. package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.C18E44rY.js +9 -0
  30. package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +19 -0
  31. package/docs/.vitepress/dist/assets/chunks/theme.VX3itTW6.js +2 -0
  32. package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.js +34 -0
  33. package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.lean.js +1 -0
  34. package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.js +28 -0
  35. package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.lean.js +1 -0
  36. package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.js +338 -0
  37. package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.lean.js +1 -0
  38. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.js +13 -0
  39. package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.lean.js +1 -0
  40. package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.js +297 -0
  41. package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.lean.js +1 -0
  42. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.js +182 -0
  43. package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.lean.js +1 -0
  44. package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.js +174 -0
  45. package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.lean.js +1 -0
  46. package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.js +1 -0
  47. package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.lean.js +1 -0
  48. package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.js +140 -0
  49. package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.lean.js +1 -0
  50. package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.js +107 -0
  51. package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.lean.js +1 -0
  52. package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.js +2 -0
  53. package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.lean.js +1 -0
  54. package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.js +304 -0
  55. package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.lean.js +1 -0
  56. package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.js +33 -0
  57. package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.lean.js +1 -0
  58. package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.js +135 -0
  59. package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.lean.js +1 -0
  60. package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.js +193 -0
  61. package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.lean.js +1 -0
  62. package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.js +187 -0
  63. package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.lean.js +1 -0
  64. package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.js +119 -0
  65. package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.lean.js +1 -0
  66. package/docs/.vitepress/dist/assets/index.md.M4_o26kF.js +23 -0
  67. package/docs/.vitepress/dist/assets/index.md.M4_o26kF.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 +52 -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 +17 -0
  130. package/examples/vite-app/README.md +71 -0
  131. package/examples/vite-app/index.html +49 -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/components/todo-list.lego +242 -0
  136. package/examples/vite-app/src/main.js +11 -0
  137. package/examples/vite-app/vite.config.js +17 -0
  138. package/examples.js +99 -0
  139. package/go.html +117 -0
  140. package/lego.js +2 -0
  141. package/main.js +41 -35
  142. package/package.json +39 -6
  143. package/parse-lego.js +119 -0
  144. package/parse-lego.test.js +107 -0
  145. package/vite-plugin.js +133 -0
  146. package/.ignore/auto.html +0 -135
  147. package/.ignore/test.html +0 -73
@@ -0,0 +1,394 @@
1
+ # Reactivity
2
+
3
+ Understand how Lego makes your UI automatically update when data changes.
4
+
5
+ ## The Core Concept
6
+
7
+ When you change an object, the DOM updates automatically:
8
+
9
+ ```js
10
+ component._studs.count = 5; // DOM updates!
11
+ component._studs.items.push('new item'); // DOM updates!
12
+ ```
13
+
14
+ No `setState()`, no `dispatch()`, no special syntax. Just mutate the data.
15
+
16
+ ## How It Works
17
+
18
+ Lego uses **ES6 Proxies** to track changes:
19
+
20
+ ```js
21
+ const reactive = (obj, el) => {
22
+ return new Proxy(obj, {
23
+ set(target, key, value) {
24
+ const oldValue = target[key];
25
+ target[key] = value;
26
+
27
+ if (oldValue !== value) {
28
+ // Schedule re-render
29
+ render(el);
30
+ }
31
+
32
+ return true;
33
+ }
34
+ });
35
+ };
36
+ ```
37
+
38
+ When you set a property, the proxy intercepts it and schedules a re-render.
39
+
40
+ ## What's Reactive
41
+
42
+ ### ✅ Direct Property Assignment
43
+
44
+ ```js
45
+ this.count = 10; // ✅ Reactive
46
+ this.user.name = 'Alice'; // ✅ Reactive
47
+ this.items[0] = 'updated'; // ✅ Reactive
48
+ ```
49
+
50
+ ### ✅ Array Methods
51
+
52
+ ```js
53
+ this.items.push('new'); // ✅ Reactive
54
+ this.items.pop(); // ✅ Reactive
55
+ this.items.splice(0, 1); // ✅ Reactive
56
+ this.items.sort(); // ✅ Reactive
57
+ ```
58
+
59
+ ### ✅ Nested Objects
60
+
61
+ ```js
62
+ this.user.profile.age = 30; // ✅ Reactive
63
+ ```
64
+
65
+ Lego recursively wraps nested objects in proxies.
66
+
67
+ ### ✅ Object Deletion
68
+
69
+ ```js
70
+ delete this.user.email; // ✅ Reactive
71
+ ```
72
+
73
+ ### ⚠️ Limitations
74
+
75
+ #### Replacing Arrays
76
+
77
+ Don't replace the entire array reference:
78
+
79
+ ```js
80
+ this.items = newItems; // ⚠️ Might not be reactive
81
+ ```
82
+
83
+ Instead, mutate in place:
84
+
85
+ ```js
86
+ this.items.length = 0;
87
+ this.items.push(...newItems); // ✅ Better
88
+ ```
89
+
90
+ #### Adding New Root Properties
91
+
92
+ Adding properties after initialization won't be reactive:
93
+
94
+ ```js
95
+ // Initial state
96
+ {
97
+ count: 0
98
+ }
99
+
100
+ // Later...
101
+ this.newProp = 'value'; // ⚠️ Not reactive
102
+ ```
103
+
104
+ Initialize all properties upfront:
105
+
106
+ ```js
107
+ {
108
+ count: 0,
109
+ newProp: null // ✅ Initialize with default
110
+ }
111
+ ```
112
+
113
+ ## Batching Updates
114
+
115
+ Lego batches updates using `requestAnimationFrame`:
116
+
117
+ ```js
118
+ this.count = 1;
119
+ this.count = 2;
120
+ this.count = 3;
121
+ // Only one re-render happens!
122
+ ```
123
+
124
+ This prevents unnecessary DOM updates and improves performance.
125
+
126
+ ## Update Lifecycle
127
+
128
+ 1. **State Change** - You mutate data
129
+ 2. **Proxy Intercepts** - Change is detected
130
+ 3. **Batch Queue** - Component added to update queue
131
+ 4. **requestAnimationFrame** - Browser schedules render
132
+ 5. **Re-render** - DOM is updated
133
+ 6. **updated() Hook** - Called after render
134
+
135
+ ```js
136
+ {
137
+ count: 0,
138
+
139
+ increment() {
140
+ console.log('Before:', this.count);
141
+ this.count++;
142
+ console.log('After:', this.count);
143
+ // DOM not updated yet!
144
+ },
145
+
146
+ updated() {
147
+ console.log('DOM updated with:', this.count);
148
+ // DOM is updated now!
149
+ }
150
+ }
151
+ ```
152
+
153
+ ## Deep Reactivity
154
+
155
+ Nested objects are automatically reactive:
156
+
157
+ ```js
158
+ {
159
+ user: {
160
+ profile: {
161
+ settings: {
162
+ theme: 'dark'
163
+ }
164
+ }
165
+ }
166
+ }
167
+ ```
168
+
169
+ ```html
170
+ <!-- All reactive -->
171
+ <p>{{ user.profile.settings.theme }}</p>
172
+ ```
173
+
174
+ ```js
175
+ this.user.profile.settings.theme = 'light'; // ✅ Updates DOM
176
+ ```
177
+
178
+ ## Arrays and Objects
179
+
180
+ ### Array Mutations
181
+
182
+ All mutating methods trigger updates:
183
+
184
+ ```js
185
+ this.items.push(newItem);
186
+ this.items.pop();
187
+ this.items.shift();
188
+ this.items.unshift(item);
189
+ this.items.splice(index, 1);
190
+ this.items.sort();
191
+ this.items.reverse();
192
+ ```
193
+
194
+ ### Non-Mutating Methods
195
+
196
+ These don't trigger updates (they return new arrays):
197
+
198
+ ```js
199
+ const filtered = this.items.filter(x => x.active); // No update
200
+ const mapped = this.items.map(x => x.name); // No update
201
+ ```
202
+
203
+ To make them reactive, assign back:
204
+
205
+ ```js
206
+ this.items = this.items.filter(x => x.active); // ✅ Triggers update
207
+ ```
208
+
209
+ Or use mutating equivalents:
210
+
211
+ ```js
212
+ // Instead of filter
213
+ for (let i = this.items.length - 1; i >= 0; i--) {
214
+ if (!this.items[i].active) {
215
+ this.items.splice(i, 1); // ✅ Reactive
216
+ }
217
+ }
218
+ ```
219
+
220
+ ## Object Changes
221
+
222
+ ### Adding Properties to Nested Objects
223
+
224
+ ```js
225
+ this.user.newProp = 'value'; // ✅ Reactive (nested object)
226
+ ```
227
+
228
+ ### Object.assign()
229
+
230
+ ```js
231
+ Object.assign(this.user, { name: 'Alice', age: 30 }); // ✅ Reactive
232
+ ```
233
+
234
+ ## Performance Considerations
235
+
236
+ ### Minimize Unnecessary Updates
237
+
238
+ Group related changes:
239
+
240
+ ```js
241
+ // ❌ Bad - 3 separate updates
242
+ this.user.name = 'Alice';
243
+ this.user.age = 30;
244
+ this.user.email = 'alice@example.com';
245
+
246
+ // ✅ Better - 1 update
247
+ Object.assign(this.user, {
248
+ name: 'Alice',
249
+ age: 30,
250
+ email: 'alice@example.com'
251
+ });
252
+ ```
253
+
254
+ ### Avoid Reactive Overhead for Static Data
255
+
256
+ Don't make everything reactive:
257
+
258
+ ```js
259
+ {
260
+ // Reactive data
261
+ count: 0,
262
+
263
+ // Constants (not reactive, but that's fine)
264
+ MAX_COUNT: 100,
265
+ API_URL: 'https://api.example.com'
266
+ }
267
+ ```
268
+
269
+ ## Debugging Reactivity
270
+
271
+ ### Check if Value Changed
272
+
273
+ ```js
274
+ {
275
+ count: 0,
276
+
277
+ updated() {
278
+ console.log('Count changed to:', this.count);
279
+ }
280
+ }
281
+ ```
282
+
283
+ ### Inspect Proxy
284
+
285
+ ```js
286
+ console.log(component._studs); // Proxy object
287
+ console.log(component._studs.count); // Actual value
288
+ ```
289
+
290
+ ## Comparing with Other Frameworks
291
+
292
+ ### Vue 3
293
+
294
+ ```js
295
+ // Vue 3
296
+ const count = ref(0);
297
+ count.value++;
298
+
299
+ // Lego
300
+ this.count++;
301
+ ```
302
+
303
+ ### React
304
+
305
+ ```js
306
+ // React
307
+ const [count, setCount] = useState(0);
308
+ setCount(count + 1);
309
+
310
+ // Lego
311
+ this.count++;
312
+ ```
313
+
314
+ ### Svelte
315
+
316
+ ```js
317
+ // Svelte
318
+ let count = 0;
319
+ count++;
320
+
321
+ // Lego
322
+ this.count++;
323
+ ```
324
+
325
+ Lego is closest to Svelte's model but uses Proxies instead of compilation.
326
+
327
+ ## Advanced Patterns
328
+
329
+ ### Watching for Changes
330
+
331
+ Use `updated()` hook:
332
+
333
+ ```js
334
+ {
335
+ count: 0,
336
+ previousCount: 0,
337
+
338
+ updated() {
339
+ if (this.count !== this.previousCount) {
340
+ console.log('Count changed from', this.previousCount, 'to', this.count);
341
+ this.previousCount = this.count;
342
+ }
343
+ }
344
+ }
345
+ ```
346
+
347
+ ### Computed Properties
348
+
349
+ Use methods:
350
+
351
+ ```js
352
+ {
353
+ firstName: 'John',
354
+ lastName: 'Doe',
355
+
356
+ fullName() {
357
+ return `${this.firstName} ${this.lastName}`;
358
+ }
359
+ }
360
+ ```
361
+
362
+ ```html
363
+ <p>{{ fullName() }}</p>
364
+ ```
365
+
366
+ ### Debouncing Updates
367
+
368
+ ```js
369
+ {
370
+ searchQuery: '',
371
+ timer: null,
372
+
373
+ onInput() {
374
+ clearTimeout(this.timer);
375
+ this.timer = setTimeout(() => {
376
+ this.performSearch();
377
+ }, 300);
378
+ }
379
+ }
380
+ ```
381
+
382
+ ## Best Practices
383
+
384
+ 1. **Initialize all properties** - Define them upfront
385
+ 2. **Use array methods** - push(), splice(), etc.
386
+ 3. **Batch related changes** - Use Object.assign()
387
+ 4. **Keep state flat when possible** - Shallow is faster
388
+ 5. **Use methods for computed values** - They're called on every render
389
+
390
+ ## Next Steps
391
+
392
+ - Learn about [Templating](/guide/templating)
393
+ - Explore [Directives](/guide/directives)
394
+ - See [reactivity examples](/examples/)