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