lego-dom 1.3.3 → 1.4.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 (92) hide show
  1. package/CHANGELOG.md +61 -0
  2. package/main.js +24 -3
  3. package/main.min.js +7 -0
  4. package/package.json +3 -1
  5. package/vite-plugin.js +0 -14
  6. package/.github/workflows/deploy-docs.yml +0 -56
  7. package/.legodom +0 -87
  8. package/docs/.vitepress/config.js +0 -162
  9. package/docs/api/config.md +0 -95
  10. package/docs/api/define.md +0 -58
  11. package/docs/api/directives.md +0 -50
  12. package/docs/api/globals.md +0 -29
  13. package/docs/api/index.md +0 -30
  14. package/docs/api/lifecycle.md +0 -40
  15. package/docs/api/route.md +0 -37
  16. package/docs/api/vite-plugin.md +0 -58
  17. package/docs/contributing/01-welcome.md +0 -38
  18. package/docs/contributing/02-registry.md +0 -133
  19. package/docs/contributing/03-batcher.md +0 -110
  20. package/docs/contributing/04-reactivity.md +0 -87
  21. package/docs/contributing/05-caching.md +0 -59
  22. package/docs/contributing/06-init.md +0 -136
  23. package/docs/contributing/07-observer.md +0 -72
  24. package/docs/contributing/08-snap.md +0 -140
  25. package/docs/contributing/09-diffing.md +0 -69
  26. package/docs/contributing/10-studs.md +0 -78
  27. package/docs/contributing/11-scanner.md +0 -117
  28. package/docs/contributing/12-render.md +0 -138
  29. package/docs/contributing/13-directives.md +0 -243
  30. package/docs/contributing/14-events.md +0 -57
  31. package/docs/contributing/15-router.md +0 -57
  32. package/docs/contributing/16-state.md +0 -47
  33. package/docs/contributing/17-legodom.md +0 -48
  34. package/docs/contributing/index.md +0 -24
  35. package/docs/examples/form.md +0 -42
  36. package/docs/examples/index.md +0 -104
  37. package/docs/examples/routing.md +0 -409
  38. package/docs/examples/sfc-showcase.md +0 -34
  39. package/docs/examples/todo-app.md +0 -383
  40. package/docs/guide/cdn-usage.md +0 -328
  41. package/docs/guide/components.md +0 -412
  42. package/docs/guide/directives.md +0 -539
  43. package/docs/guide/directory-structure.md +0 -248
  44. package/docs/guide/faq.md +0 -210
  45. package/docs/guide/getting-started.md +0 -262
  46. package/docs/guide/index.md +0 -88
  47. package/docs/guide/lifecycle.md +0 -525
  48. package/docs/guide/quick-start.md +0 -49
  49. package/docs/guide/reactivity.md +0 -415
  50. package/docs/guide/routing.md +0 -334
  51. package/docs/guide/server-side.md +0 -134
  52. package/docs/guide/sfc.md +0 -420
  53. package/docs/guide/templating.md +0 -388
  54. package/docs/index.md +0 -160
  55. package/docs/public/logo.svg +0 -17
  56. package/docs/router/basic-routing.md +0 -103
  57. package/docs/router/cold-entry.md +0 -91
  58. package/docs/router/history.md +0 -69
  59. package/docs/router/index.md +0 -73
  60. package/docs/router/resolver.md +0 -74
  61. package/docs/router/surgical-swaps.md +0 -134
  62. package/docs/tutorial/01-project-setup.md +0 -152
  63. package/docs/tutorial/02-your-first-component.md +0 -226
  64. package/docs/tutorial/03-adding-routes.md +0 -279
  65. package/docs/tutorial/04-multi-page-app.md +0 -329
  66. package/docs/tutorial/05-state-and-globals.md +0 -285
  67. package/docs/tutorial/index.md +0 -40
  68. package/examples/vite-app/README.md +0 -71
  69. package/examples/vite-app/index.html +0 -42
  70. package/examples/vite-app/package.json +0 -18
  71. package/examples/vite-app/src/app.css +0 -3
  72. package/examples/vite-app/src/app.js +0 -29
  73. package/examples/vite-app/src/components/app-navbar.lego +0 -34
  74. package/examples/vite-app/src/components/customers/customer-details.lego +0 -24
  75. package/examples/vite-app/src/components/customers/customer-orders.lego +0 -21
  76. package/examples/vite-app/src/components/customers/order-list.lego +0 -55
  77. package/examples/vite-app/src/components/greeting-card.lego +0 -41
  78. package/examples/vite-app/src/components/sample-component.lego +0 -75
  79. package/examples/vite-app/src/components/shells/customers-shell.lego +0 -21
  80. package/examples/vite-app/src/components/side-menu.lego +0 -46
  81. package/examples/vite-app/src/components/todo-list.lego +0 -239
  82. package/examples/vite-app/src/components/widgets/user-card.lego +0 -27
  83. package/examples/vite-app/vite.config.js +0 -22
  84. package/tests/error.test.js +0 -74
  85. package/tests/main.test.js +0 -103
  86. package/tests/memory.test.js +0 -68
  87. package/tests/monitoring.test.js +0 -74
  88. package/tests/naming.test.js +0 -74
  89. package/tests/parse-lego.test.js +0 -65
  90. package/tests/security.test.js +0 -67
  91. package/tests/server.test.js +0 -114
  92. package/tests/syntax.test.js +0 -67
@@ -1,412 +0,0 @@
1
- # Components
2
-
3
- Learn how to create and use components in Lego.
4
-
5
- ## What is a Component?
6
-
7
- A component is a reusable, self-contained piece of UI with its own template, styles, and logic.
8
-
9
- ```html
10
- <template b-id="user-badge">
11
- <style>
12
- self {
13
- display: inline-flex;
14
- align-items: center;
15
- gap: 0.5rem;
16
- padding: 0.5rem 1rem;
17
- background: #f0f0f0;
18
- border-radius: 20px;
19
- }
20
- .avatar {
21
- width: 32px;
22
- height: 32px;
23
- border-radius: 50%;
24
- }
25
- </style>
26
-
27
- <img class="avatar" src="[[ avatarUrl ]]" alt="[[ name ]]">
28
- <span>[[ name ]]</span>
29
- </template>
30
- ```
31
-
32
- ## Creating Components
33
-
34
- ### Method 1: HTML Templates
35
-
36
- Define components directly in your HTML with `<template b-id>`:
37
-
38
- ```html
39
- <template b-id="hello-world" b-data="{ name: 'Default User' }">
40
- <h1>Hello [[ name ]]!</h1>
41
- </template>
42
-
43
- <!-- Uses the default "Default User" -->
44
- <hello-world></hello-world>
45
-
46
- <!-- Overrides the default with "Alice" -->
47
- <hello-world b-data="{ name: 'Alice' }"></hello-world>
48
- ```
49
-
50
- ### Method 2: JavaScript
51
-
52
- Use `Lego.define()` for programmatic component creation:
53
-
54
- ```js
55
- Lego.define('hello-world', `
56
- <h1>Hello [[ name ]]!</h1>
57
- `, {
58
- name: 'Alice'
59
- });
60
- ```
61
-
62
- ### Method 3: Single File Components (.lego)
63
-
64
- With Vite, use `.lego` files:
65
-
66
- ```html
67
- <!-- hello-world.lego -->
68
- <template>
69
- <h1>Hello [[ name ]]!</h1>
70
- </template>
71
-
72
- <script>
73
- export default {
74
- name: 'Alice'
75
- }
76
- </script>
77
- ```
78
-
79
- ## Component State
80
-
81
- State is defined in the component's logic object:
82
-
83
- ```js
84
- {
85
- // Data properties
86
- count: 0,
87
- username: 'Alice',
88
- items: ['apple', 'banana'],
89
-
90
- // Methods
91
- increment() {
92
- this.count++;
93
- },
94
-
95
- addItem(item) {
96
- this.items.push(item);
97
- }
98
- }
99
- ```
100
-
101
- Access state in templates using `[[ ]]`:
102
-
103
- ```html
104
- <p>Count: [[ count ]]</p>
105
- <button @click="increment()">+1</button>
106
- ```
107
-
108
- ## Passing Data
109
-
110
- ### Via b-data Attribute
111
-
112
- ```html
113
- <user-card b-data="{
114
- name: 'Bob',
115
- email: 'bob@example.com',
116
- role: 'admin'
117
- }"></user-card>
118
- ```
119
-
120
- ### Data Merging (The Three Tiers)
121
-
122
- Lego uses a sophisticated three-tier merging strategy to initialize component state. This allows you to define defaults at the library level, customize them for a component type, and then override them for specific instances.
123
-
124
- The priority is as follows (**last one wins**):
125
-
126
- 1. **Tier 1: Script Logic** - Data defined in `Lego.define()` or exported from a `.lego` SFC.
127
- 2. **Tier 2: Template Defaults** - Data defined on the `<template b-data="...">` attribute.
128
- 3. **Tier 3: Instance Overrides** - Data defined on the actual component tag `<my-comp b-data="...">`.
129
-
130
- ### Example of Merging
131
-
132
- ```html
133
- <!-- 1. Script Logic (Defined in JS) -->
134
- <script>
135
- Lego.define('user-card', `...`, { role: 'guest', theme: 'light' });
136
- </script>
137
-
138
- <!-- 2. Template Defaults (Defined in HTML) -->
139
- <template b-id="user-card" b-data="{ role: 'member', name: 'Anonymous' }">
140
- ...
141
- </template>
142
-
143
- <!-- 3. Instance Overrides -->
144
- <user-card b-data="{ name: 'Alice' }"></user-card>
145
- ```
146
-
147
- In the example above, the final state for the component will be:
148
- - `role`: `'member'` (Template override beats Script)
149
- - `theme`: `'light'` (Only defined in Script)
150
- - `name`: `'Alice'` (Instance override beats Template)
151
-
152
- ## Component Communication
153
-
154
- ### Parent → Child (Props)
155
-
156
- Pass data via `b-data`:
157
-
158
- ```html
159
- <child-component b-data="{ title: parentData.title }"></child-component>
160
- ```
161
-
162
- ### Child → Parent (Events)
163
-
164
- Use `$emit()` to dispatch custom events:
165
-
166
- ```html
167
- <!-- Child component -->
168
- <button @click="$emit('save', { id: 123 })">Save</button>
169
- ```
170
-
171
- ```js
172
- // Parent listens
173
- document.querySelector('child-component')
174
- .addEventListener('save', (e) => {
175
- console.log('Saved:', e.detail); // { id: 123 }
176
- });
177
- ```
178
-
179
- ### Accessing Ancestors
180
-
181
- Use `$ancestors()` to read parent component state:
182
-
183
- ```html
184
- <!-- In nested component -->
185
- <p>App title: [[ $ancestors('app-root').title ]]</p>
186
- ```
187
-
188
- ::: warning Read-Only
189
- `$ancestors()` is for reading parent state, not mutating it.
190
- :::
191
-
192
- ## Component Composition
193
-
194
- ### Nesting Components
195
-
196
- ```html
197
- <template b-id="app-layout">
198
- <header>
199
- <app-header></app-header>
200
- </header>
201
- <main>
202
- <app-sidebar></app-sidebar>
203
- <app-content></app-content>
204
- </main>
205
- </template>
206
- ```
207
-
208
- ### Using Slots
209
-
210
- Standard Web Components slots work:
211
-
212
- ```html
213
- <template b-id="card-container">
214
- <div class="card">
215
- <slot name="header"></slot>
216
- <slot></slot>
217
- <slot name="footer"></slot>
218
- </div>
219
- </template>
220
-
221
- <!-- Usage -->
222
- <card-container>
223
- <h2 slot="header">Title</h2>
224
- <p>Main content</p>
225
- <button slot="footer">Action</button>
226
- </card-container>
227
- ```
228
-
229
- ## Shadow DOM
230
-
231
- All components use Shadow DOM for style encapsulation.
232
-
233
- ### Benefits
234
-
235
- ✅ **Scoped Styles** - CSS doesn't leak in or out
236
- ✅ **No Naming Conflicts** - ID/class names are isolated
237
- ✅ **Composability** - Components work without side effects
238
-
239
- ### Styling the Host
240
-
241
- Use `self` keyword (converts to `:host`):
242
-
243
- ```html
244
- <style>
245
- self {
246
- display: block;
247
- padding: 1rem;
248
- }
249
-
250
- self:hover {
251
- background: #f5f5f5;
252
- }
253
- </style>
254
- ```
255
-
256
- ## Lifecycle
257
-
258
- Components have three lifecycle hooks:
259
-
260
- ```js
261
- {
262
- mounted() {
263
- // Component added to DOM
264
- this.fetchData();
265
- },
266
-
267
- updated() {
268
- // State changed and re-rendered
269
- console.log('New count:', this.count);
270
- },
271
-
272
- unmounted() {
273
- // Component removed from DOM
274
- clearInterval(this.timer);
275
- }
276
- }
277
- ```
278
-
279
- See [Lifecycle Hooks](/guide/lifecycle) for details.
280
-
281
- ## Best Practices
282
-
283
- ### 1. Keep Components Small
284
-
285
- Each component should have a single responsibility.
286
-
287
- ✅ Good: `user-avatar`, `user-name`, `user-bio`
288
- ❌ Bad: `entire-user-profile-page`
289
-
290
- ### 2. Use Semantic Names
291
-
292
- Name components after what they represent:
293
-
294
- ✅ Good: `product-card`, `search-bar`
295
- ❌ Bad: `blue-box`, `flex-container`
296
-
297
- ### 3. Avoid Deep Nesting
298
-
299
- Keep component trees shallow (3-4 levels max):
300
-
301
- ```html
302
- app-root
303
- ├── app-header
304
- │ └── nav-menu
305
- ├── app-main
306
- │ └── content-area
307
- └── app-footer
308
- ```
309
-
310
- ### 4. Initialize State in mounted()
311
-
312
- Fetch data or set up timers in `mounted()`:
313
-
314
- ```js
315
- {
316
- data: null,
317
- mounted() {
318
- this.fetchData();
319
- },
320
- async fetchData() {
321
- this.data = await fetch('/api/data').then(r => r.json());
322
- }
323
- }
324
- ```
325
-
326
- ### 5. Clean Up in unmounted()
327
-
328
- Clear timers, remove listeners:
329
-
330
- ```js
331
- {
332
- timer: null,
333
- mounted() {
334
- this.timer = setInterval(() => this.tick(), 1000);
335
- },
336
- unmounted() {
337
- clearInterval(this.timer);
338
- }
339
- }
340
- ```
341
-
342
- ## Common Patterns
343
-
344
- ### Loading States
345
-
346
- ```html
347
- <div b-show="loading">Loading...</div>
348
- <div b-show="!loading && data">
349
- <h2>[[ data.title ]]</h2>
350
- <p>[[ data.content ]]</p>
351
- </div>
352
- <div b-show="!loading && error">
353
- Error: [[ error ]]
354
- </div>
355
- ```
356
-
357
- ### Form Components
358
-
359
- ```js
360
- {
361
- form: {
362
- username: '',
363
- email: '',
364
- password: ''
365
- },
366
- errors: {},
367
-
368
- validate() {
369
- this.errors = {};
370
- if (!this.form.username) {
371
- this.errors.username = 'Required';
372
- }
373
- if (!this.form.email.includes('@')) {
374
- this.errors.email = 'Invalid email';
375
- }
376
- return Object.keys(this.errors).length === 0;
377
- },
378
-
379
- submit() {
380
- if (this.validate()) {
381
- // Submit form
382
- }
383
- }
384
- }
385
- ```
386
-
387
- ### Computed Values
388
-
389
- Use methods for computed values:
390
-
391
- ```js
392
- {
393
- items: [
394
- { name: 'Apple', price: 1.20 },
395
- { name: 'Banana', price: 0.80 }
396
- ],
397
-
398
- total() {
399
- return this.items.reduce((sum, item) => sum + item.price, 0);
400
- }
401
- }
402
- ```
403
-
404
- ```html
405
- <p>Total: $[[ total().toFixed(2) ]]</p>
406
- ```
407
-
408
- ## Next Steps
409
-
410
- - Learn about [Reactivity](/guide/reactivity) in depth
411
- - Explore [Templating](/guide/templating) features
412
- - See [complete examples](/examples/)