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.
- package/CHANGELOG.md +61 -0
- package/main.js +24 -3
- package/main.min.js +7 -0
- package/package.json +3 -1
- package/vite-plugin.js +0 -14
- package/.github/workflows/deploy-docs.yml +0 -56
- package/.legodom +0 -87
- package/docs/.vitepress/config.js +0 -162
- 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 -328
- package/docs/guide/components.md +0 -412
- 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 -420
- 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
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
# Chaos Tends To A Minimum
|
|
2
|
-
|
|
3
|
-
> [!NOTE] This is a Recommendation, Not a Bible
|
|
4
|
-
> This page is one person's take on how to structure large LegoDOM applications. It is not enforced by the framework. You are encouraged to adapt, improve, or completely ignore it. If you find a better pattern, please share it.
|
|
5
|
-
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
In LegoDOM land everything is a `.lego`. A `block` is a lego, a `widget` is a lego, a `component` is a lego, a `page` is a lego.
|
|
9
|
-
|
|
10
|
-
But what do they *mean*?
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
## The Four Levels
|
|
14
|
-
|
|
15
|
-
| Level | Role | Knows About | Example |
|
|
16
|
-
| :--- | :--- | :--- | :--- |
|
|
17
|
-
| **Block** | Identity | Its own visuals | `<block-avatar>`, `<block-button>` |
|
|
18
|
-
| **Widget** | Intent | How an interaction works | `<widget-file-trigger>`, `<widget-dropdown>` |
|
|
19
|
-
| **Component** | Computation | Business data & API calls | `<comp-profile-settings>`, `<comp-checkout-form>` |
|
|
20
|
-
| **Page** | Coordination | Layout & Routing | `<page-dashboard>`, `<page-login>` |
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
## The Litmus Test: The Avatar Upload
|
|
24
|
-
|
|
25
|
-
**The Question:**
|
|
26
|
-
> I have an avatar. When I click it, it opens a file picker. When the file changes, it POSTs to `/v1/avatars`. What is it? A Block? A Widget? A Component?
|
|
27
|
-
|
|
28
|
-
**The Technical Answer:** `main.js` allows all of this in one file. It will work.
|
|
29
|
-
|
|
30
|
-
**The Architectural Answer:** You have conflated three distinct responsibilities into one:
|
|
31
|
-
1. **Identity** Looking like an avatar.
|
|
32
|
-
2. **Intent** Picking a file.
|
|
33
|
-
3. **Computation** Saving to *your specific server*.
|
|
34
|
-
|
|
35
|
-
**The Consequence:**
|
|
36
|
-
If you later want to display that avatar in a read-only user list, you *cannot reuse this component* because clicking it triggers unwanted upload logic. You will be forced to create a new, duplicate `<block-avatar>` just for display.
|
|
37
|
-
|
|
38
|
-
### The "Lego Way" Solution
|
|
39
|
-
|
|
40
|
-
Split this into its three atomic truths to maximize reusability.
|
|
41
|
-
|
|
42
|
-
#### 1. The Block (Identity)
|
|
43
|
-
|
|
44
|
-
```html
|
|
45
|
-
<!-- block-avatar.lego -->
|
|
46
|
-
<template>
|
|
47
|
-
<img class="avatar" src="[[ src ]]" alt="[[ alt ]]">
|
|
48
|
-
</template>
|
|
49
|
-
|
|
50
|
-
<style>
|
|
51
|
-
.avatar { width: 48px; height: 48px; border-radius: 50%; object-fit: cover; }
|
|
52
|
-
</style>
|
|
53
|
-
|
|
54
|
-
<script>
|
|
55
|
-
export default {
|
|
56
|
-
src: '/default-avatar.png',
|
|
57
|
-
alt: 'User'
|
|
58
|
-
}
|
|
59
|
-
</script>
|
|
60
|
-
```
|
|
61
|
-
- **Role:** Just the visuals. Circular crop, fallback, size classes.
|
|
62
|
-
- **Logic:** None. Zero business knowledge.
|
|
63
|
-
- **Reusability:** Used *everywhere* e.g. Navbar, User List, Profile Page, Comments.
|
|
64
|
-
|
|
65
|
-
#### 2. The Widget (Intent)
|
|
66
|
-
|
|
67
|
-
```html
|
|
68
|
-
<!-- widget-file-trigger.lego -->
|
|
69
|
-
<template>
|
|
70
|
-
<div @click="openPicker()">
|
|
71
|
-
<slot></slot>
|
|
72
|
-
<input type="file" style="display:none" b-var="avatarFileElement" @change="onFileChange">
|
|
73
|
-
</div>
|
|
74
|
-
</template>
|
|
75
|
-
|
|
76
|
-
<script>
|
|
77
|
-
export default {
|
|
78
|
-
openPicker() {
|
|
79
|
-
this.$vars.avatarFileElement.click();
|
|
80
|
-
},
|
|
81
|
-
onFileChange(event) {
|
|
82
|
-
// It doesn't know about /v1/avatars. It just hands you the file.
|
|
83
|
-
this.$emit('file-selected', { file: event.target.files[0] });
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
</script>
|
|
87
|
-
```
|
|
88
|
-
- **Role:** The mechanic. Wraps any slotted content and makes it clickable to open a file dialog.
|
|
89
|
-
- **Logic:** Handles the hidden `<input type="file">`, listens for `change`, and **emits an event**.
|
|
90
|
-
- **Boundary:** It uses `$emit` (from `main.js`) to broadcast what happened. It never makes API calls.
|
|
91
|
-
|
|
92
|
-
#### 3. The Component (Computation a.k.a. Context)
|
|
93
|
-
|
|
94
|
-
```html
|
|
95
|
-
<!-- comp-profile-settings.lego -->
|
|
96
|
-
<template>
|
|
97
|
-
<h2>Your Profile</h2>
|
|
98
|
-
<widget-file-trigger @file-selected="uploadAvatar">
|
|
99
|
-
<block-avatar src="[[ user.avatarUrl ]]"></block-avatar>
|
|
100
|
-
</widget-file-trigger>
|
|
101
|
-
<p>Click avatar to change</p>
|
|
102
|
-
</template>
|
|
103
|
-
|
|
104
|
-
<script>
|
|
105
|
-
export default {
|
|
106
|
-
user: { avatarUrl: '/me.jpg' },
|
|
107
|
-
|
|
108
|
-
async uploadAvatar(event) {
|
|
109
|
-
const file = event.detail.file;
|
|
110
|
-
// BUSINESS LOGIC LIVES HERE
|
|
111
|
-
const formData = new FormData();
|
|
112
|
-
formData.append('avatar', file);
|
|
113
|
-
const res = await fetch('/v1/avatars', { method: 'POST', body: formData });
|
|
114
|
-
const data = await res.json();
|
|
115
|
-
this.user.avatarUrl = data.url; // Reactivity updates the block-avatar
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
</script>
|
|
119
|
-
```
|
|
120
|
-
- **Role:** The boss. Assembles the parts and owns the API call.
|
|
121
|
-
- **Logic:** Knows about `user`, knows about `/v1/avatars`, handles the business outcome.
|
|
122
|
-
- **Boundary:** This is the *only* place that knows about your specific backend.
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
## The Definitions
|
|
126
|
-
|
|
127
|
-
### Blocks (Atoms)
|
|
128
|
-
|
|
129
|
-
> **TL;DR** A Block is an irreducible thing. A UI with identity, but no narrative intent.
|
|
130
|
-
|
|
131
|
-
A Block cannot be broken down into smaller Blocks. It is self-contained.
|
|
132
|
-
|
|
133
|
-
- **State:** Visual only. It can track "Is my mouse over me?" or "Am I spinning?". It never knows about User IDs, Auth tokens, or business data.
|
|
134
|
-
- **Naming:** `block-avatar`, `block-button`, `block-spinner`, `block-card`.
|
|
135
|
-
- **Rule:** If you find yourself nesting Blocks inside other Blocks, you have graduated to a Widget.
|
|
136
|
-
|
|
137
|
-
> [!WARNING] Don't Confuse Styling with Blocks
|
|
138
|
-
> You can use CSS to style many `<h1>` elements. That doesn't mean you need a `<block-title-header>`. Only create a Block when it has distinct *behavior* or *identity* beyond mere styling.
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
### Widgets (Molecules)
|
|
142
|
-
|
|
143
|
-
> **TL;DR** A Widget is an interaction, not a thing.
|
|
144
|
-
|
|
145
|
-
A Widget gives Blocks a reason to exist together. It defines *how* an interaction works without embedding *who* it's for or *what* business outcome it serves.
|
|
146
|
-
|
|
147
|
-
- **State:** Internal UI state only. "Is the dropdown open?" "Which tab is active?"
|
|
148
|
-
- **Naming:** `widget-dropdown`, `widget-modal`, `widget-datepicker`, `widget-file-trigger`.
|
|
149
|
-
- **Rule:** Widgets are portable. You should be able to copy a Widget to a completely different project and it should still work.
|
|
150
|
-
- **Communication:** Uses `$emit()` to broadcast events. Never makes API calls itself.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
### Components (Organisms)
|
|
154
|
-
|
|
155
|
-
> **TL;DR** Components are where your app features come to life.
|
|
156
|
-
|
|
157
|
-
A Component is a Widget (or set of Widgets) bound to specific data, rules, and responsibility. It's where interaction becomes meaningful to *this* application.
|
|
158
|
-
|
|
159
|
-
- **State:** Domain-specific. Owns data fetched from APIs. Knows about the current user.
|
|
160
|
-
- **Naming:** `comp-profile-settings`, `comp-order-history`, `comp-payroll-table`.
|
|
161
|
-
- **Rule:** A Component knows *who* it is for, *what* data it owns, and *what* outcome it must produce.
|
|
162
|
-
- **Communication:** Listens to Widget events (like `@file-selected`) and performs business transactions.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
### Pages (Coordination)
|
|
166
|
-
|
|
167
|
-
> **TL;DR** A Page is the top-level host that routing targets.
|
|
168
|
-
|
|
169
|
-
Pages are the uppermost hosts. They orchestrate the layout of Components within the context of a LegoDOM application.
|
|
170
|
-
|
|
171
|
-
- **Role:** Define the grid. Orchestrate Components. Handle route parameters.
|
|
172
|
-
- **Naming:** `page-dashboard`, `page-login`, `page-user-profile`.
|
|
173
|
-
- **Rule:** Pages are the *only* UI units directly known to `<lego-router>`. While a Component owns the *logic* of a feature, a Page owns the *real estate*.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
## Recommended Directory Structure
|
|
177
|
-
|
|
178
|
-
```text
|
|
179
|
-
src/
|
|
180
|
-
├── blocks/ # Design System primitives
|
|
181
|
-
│ ├── block-avatar.lego
|
|
182
|
-
│ ├── block-button.lego
|
|
183
|
-
│ └── block-input.lego
|
|
184
|
-
├── widgets/ # Generic, portable UI tools
|
|
185
|
-
│ ├── widget-dropdown.lego
|
|
186
|
-
│ ├── widget-modal.lego
|
|
187
|
-
│ └── widget-file-trigger.lego
|
|
188
|
-
├── components/ # Domain-specific features
|
|
189
|
-
│ ├── comp-profile-settings.lego
|
|
190
|
-
│ └── comp-order-history.lego
|
|
191
|
-
├── pages/ # Route targets
|
|
192
|
-
│ ├── page-dashboard.lego
|
|
193
|
-
│ └── page-login.lego
|
|
194
|
-
└── main.js # App entry, routes, globals
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
## Scaling to Multi-Domain Apps
|
|
198
|
-
|
|
199
|
-
For large enterprise apps with multiple business domains (HRIS, Finance, Planning, Messages), the flat structure breaks down. Use a **Domain-First** approach.
|
|
200
|
-
|
|
201
|
-
### Domain-First Structure
|
|
202
|
-
|
|
203
|
-
```text
|
|
204
|
-
src/
|
|
205
|
-
├── shared/ # Truly universal (used by 3+ domains)
|
|
206
|
-
│ ├── blocks/
|
|
207
|
-
│ │ ├── block-button.lego
|
|
208
|
-
│ │ └── block-avatar.lego
|
|
209
|
-
│ └── widgets/
|
|
210
|
-
│ ├── widget-datepicker.lego
|
|
211
|
-
│ └── widget-modal.lego
|
|
212
|
-
│
|
|
213
|
-
├── hris/ # Human Resources domain
|
|
214
|
-
│ ├── blocks/
|
|
215
|
-
│ ├── widgets/
|
|
216
|
-
│ │ └── widget-leave-calendar.lego
|
|
217
|
-
│ ├── components/
|
|
218
|
-
│ │ └── comp-employee-list.lego
|
|
219
|
-
│ └── pages/
|
|
220
|
-
│ └── page-employees.lego
|
|
221
|
-
│
|
|
222
|
-
├── finance/ # Finance domain
|
|
223
|
-
│ ├── widgets/
|
|
224
|
-
│ ├── components/
|
|
225
|
-
│ └── pages/
|
|
226
|
-
│
|
|
227
|
-
├── planning/ # Planning domain
|
|
228
|
-
│ ├── widgets/
|
|
229
|
-
│ ├── components/
|
|
230
|
-
│ └── pages/
|
|
231
|
-
│
|
|
232
|
-
└── main.js
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### Rules for Multi-Domain
|
|
236
|
-
|
|
237
|
-
1. **Shared** = Only what is used by 3+ domains. Be ruthless.
|
|
238
|
-
2. **Domain folders** = Each domain owns its own `blocks/`, `widgets/`, `components/`, `pages/`.
|
|
239
|
-
3. **No cross-domain Component imports.** If HRIS needs Finance data, go through a shared service or global state, not by importing `finance/components/...`.
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
## Summary
|
|
243
|
-
|
|
244
|
-
| If you keep it all in one file... | The "Enterprise" Standard |
|
|
245
|
-
| :--- | :--- |
|
|
246
|
-
| Name it `<comp-avatar-upload>` and accept it is not reusable. | Let the **Widget** handle the interaction. Let the **Component** handle the transaction. |
|
|
247
|
-
|
|
248
|
-
**This is a recommendation.** If you find a pattern that works better for your team, use it. The goal is clarity, reusability, and reducing arguments - not rigid adherence to a doctrine.
|
package/docs/guide/faq.md
DELETED
|
@@ -1,210 +0,0 @@
|
|
|
1
|
-
# Frequently Asked Questions
|
|
2
|
-
|
|
3
|
-
Quick answers to the most common LegoDOM questions.
|
|
4
|
-
|
|
5
|
-
## Project Setup
|
|
6
|
-
|
|
7
|
-
### Where do I define my routes?
|
|
8
|
-
|
|
9
|
-
**In your entry file (`app.js` or `main.js`), before `Lego.init()`.**
|
|
10
|
-
|
|
11
|
-
```javascript
|
|
12
|
-
// src/app.js
|
|
13
|
-
import { Lego } from 'lego-dom';
|
|
14
|
-
import registerComponents from 'virtual:lego-components';
|
|
15
|
-
|
|
16
|
-
registerComponents();
|
|
17
|
-
|
|
18
|
-
// Define routes HERE ⭐
|
|
19
|
-
Lego.route('/', 'home-page');
|
|
20
|
-
Lego.route('/login', 'login-page');
|
|
21
|
-
Lego.route('/users/:id', 'user-profile');
|
|
22
|
-
|
|
23
|
-
await Lego.init(); // Must come AFTER routes
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Where does my config go?
|
|
27
|
-
|
|
28
|
-
Everything related to app configuration belongs in your entry file:
|
|
29
|
-
|
|
30
|
-
| What | Where |
|
|
31
|
-
|------|-------|
|
|
32
|
-
| Component registration | `registerComponents()` |
|
|
33
|
-
| Route definitions | `Lego.route(...)` |
|
|
34
|
-
| Global state init | `Lego.globals.user = null` |
|
|
35
|
-
| Engine start | `Lego.init()` |
|
|
36
|
-
|
|
37
|
-
### Should I use `main.js` or `app.js`?
|
|
38
|
-
|
|
39
|
-
Either works! It's just a naming convention. Use whatever your Vite template created, or rename it. Just make sure your `index.html` points to it:
|
|
40
|
-
|
|
41
|
-
```html
|
|
42
|
-
<script type="module" src="/src/app.js"></script>
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
---
|
|
46
|
-
|
|
47
|
-
## Components
|
|
48
|
-
|
|
49
|
-
### Why isn't my component showing?
|
|
50
|
-
|
|
51
|
-
Check these common issues:
|
|
52
|
-
|
|
53
|
-
1. **No route defined** – Did you add `Lego.route('/', 'my-component')`?
|
|
54
|
-
2. **Missing `<lego-router>`** – Your HTML needs `<lego-router></lego-router>`
|
|
55
|
-
3. **Wrong component name** – Filename `user-card.lego` → component `<user-card>`
|
|
56
|
-
4. **Not registered** – Did you call `registerComponents()` before `init()`?
|
|
57
|
-
|
|
58
|
-
### Why do component names need hyphens?
|
|
59
|
-
|
|
60
|
-
It's a Web Components standard! Custom elements must contain a hyphen to avoid conflicts with future HTML elements.
|
|
61
|
-
|
|
62
|
-
✅ Valid: `user-card`, `app-nav`, `my-button`
|
|
63
|
-
❌ Invalid: `usercard`, `Card`, `button`
|
|
64
|
-
|
|
65
|
-
### Can I use PascalCase filenames?
|
|
66
|
-
|
|
67
|
-
Yes! LegoDOM automatically converts:
|
|
68
|
-
- `UserCard.lego` → `<user-card>`
|
|
69
|
-
- `AppNav.lego` → `<app-nav>`
|
|
70
|
-
- `my_component.lego` → `<my-component>`
|
|
71
|
-
|
|
72
|
-
---
|
|
73
|
-
|
|
74
|
-
## Navigation
|
|
75
|
-
|
|
76
|
-
### How do I navigate between pages?
|
|
77
|
-
|
|
78
|
-
**Option 1: Declarative (in templates)**
|
|
79
|
-
```html
|
|
80
|
-
<a href="/login" b-link>Go to Login</a>
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
**Option 2: Programmatic (in JavaScript)**
|
|
84
|
-
```javascript
|
|
85
|
-
this.$go('/login').get();
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### What's the difference between `b-link` and `b-target`?
|
|
89
|
-
|
|
90
|
-
| Attribute | What it does |
|
|
91
|
-
|-----------|--------------|
|
|
92
|
-
| `b-link` | SPA navigation, updates URL, swaps `<lego-router>` |
|
|
93
|
-
| `b-target="#id"` | Swaps content of specific element, updates URL |
|
|
94
|
-
| `b-target="#id" b-link="false"` | Swaps content, does NOT update URL |
|
|
95
|
-
|
|
96
|
-
### How do I pass data when navigating?
|
|
97
|
-
|
|
98
|
-
Use global state:
|
|
99
|
-
|
|
100
|
-
```javascript
|
|
101
|
-
// Before navigating
|
|
102
|
-
Lego.globals.selectedUser = { id: 42, name: 'John' };
|
|
103
|
-
this.$go('/user-details').get();
|
|
104
|
-
|
|
105
|
-
// In the target component
|
|
106
|
-
mounted() {
|
|
107
|
-
console.log(Lego.globals.selectedUser.name); // 'John'
|
|
108
|
-
}
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
Or use route parameters:
|
|
112
|
-
|
|
113
|
-
```javascript
|
|
114
|
-
// Route: Lego.route('/users/:id', 'user-profile')
|
|
115
|
-
this.$go('/users/42').get();
|
|
116
|
-
|
|
117
|
-
// In user-profile component
|
|
118
|
-
mounted() {
|
|
119
|
-
const userId = this.$route.params.id; // '42'
|
|
120
|
-
}
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
---
|
|
124
|
-
|
|
125
|
-
## State
|
|
126
|
-
|
|
127
|
-
### How do I share data between components?
|
|
128
|
-
|
|
129
|
-
Use `Lego.globals`:
|
|
130
|
-
|
|
131
|
-
```javascript
|
|
132
|
-
// Component A sets it
|
|
133
|
-
Lego.globals.user = { name: 'John' };
|
|
134
|
-
|
|
135
|
-
// Component B reads it
|
|
136
|
-
console.log(Lego.globals.user.name); // 'John'
|
|
137
|
-
|
|
138
|
-
// In templates
|
|
139
|
-
<p>Hello, [[ global.user.name ]]!</p>
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Why isn't my data updating the view?
|
|
143
|
-
|
|
144
|
-
Make sure you're mutating the reactive object, not replacing references:
|
|
145
|
-
|
|
146
|
-
```javascript
|
|
147
|
-
// ✅ This works - mutating property
|
|
148
|
-
this.items.push(newItem);
|
|
149
|
-
this.user.name = 'Jane';
|
|
150
|
-
|
|
151
|
-
// ❌ This might not work - reassigning local variable
|
|
152
|
-
let items = this.items;
|
|
153
|
-
items.push(newItem); // Won't trigger re-render!
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Styling
|
|
159
|
-
|
|
160
|
-
### What is `self` in styles?
|
|
161
|
-
|
|
162
|
-
`self` is a special keyword that targets the component's root element (like `:host` in Shadow DOM):
|
|
163
|
-
|
|
164
|
-
```html
|
|
165
|
-
<style>
|
|
166
|
-
self {
|
|
167
|
-
display: block;
|
|
168
|
-
padding: 1rem;
|
|
169
|
-
}
|
|
170
|
-
</style>
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
LegoDOM automatically transforms this to `:host` for Shadow DOM.
|
|
174
|
-
|
|
175
|
-
### Do styles leak to other components?
|
|
176
|
-
|
|
177
|
-
No! Styles are scoped via Shadow DOM. Your `.button` class won't affect buttons in other components.
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## Build & Development
|
|
182
|
-
|
|
183
|
-
### Can I use LegoDOM without Vite?
|
|
184
|
-
|
|
185
|
-
Yes! Use the CDN approach:
|
|
186
|
-
|
|
187
|
-
```html
|
|
188
|
-
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
189
|
-
<template b-id="my-component">...</template>
|
|
190
|
-
<my-component></my-component>
|
|
191
|
-
<script>Lego.init();</script>
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
See [CDN Usage](/guide/cdn-usage) for details.
|
|
195
|
-
|
|
196
|
-
### Why use Vite?
|
|
197
|
-
|
|
198
|
-
Benefits of Vite + `.lego` files:
|
|
199
|
-
- **Hot reload** – Changes appear instantly
|
|
200
|
-
- **Auto-discovery** – No manual component registration
|
|
201
|
-
- **Better organization** – One file per component
|
|
202
|
-
- **Syntax highlighting** – Editor support for `.lego` files
|
|
203
|
-
|
|
204
|
-
---
|
|
205
|
-
|
|
206
|
-
## Still Stuck?
|
|
207
|
-
|
|
208
|
-
- 📖 [Complete Tutorial](/tutorial/) – Build an app step-by-step
|
|
209
|
-
- 💬 [GitHub Discussions](https://github.com/rayattack/LegoDOM/discussions)
|
|
210
|
-
- 🐛 [Report Issues](https://github.com/rayattack/LegoDOM/issues)
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
# Getting Started
|
|
2
|
-
|
|
3
|
-
Get up and running with Lego in under 5 minutes.
|
|
4
|
-
|
|
5
|
-
::: tip 🚀 Want a Complete Walkthrough?
|
|
6
|
-
Check out our **[Step-by-Step Tutorial](/tutorial/)** – build a full multi-page app from scratch in 15 minutes!
|
|
7
|
-
:::
|
|
8
|
-
|
|
9
|
-
## Installation
|
|
10
|
-
|
|
11
|
-
### Option 1: CDN (No Build Tools)
|
|
12
|
-
|
|
13
|
-
The fastest way to try Lego is via CDN:
|
|
14
|
-
|
|
15
|
-
```html
|
|
16
|
-
<!DOCTYPE html>
|
|
17
|
-
<html>
|
|
18
|
-
<head>
|
|
19
|
-
<title>My Lego App</title>
|
|
20
|
-
</head>
|
|
21
|
-
<body>
|
|
22
|
-
<my-component></my-component>
|
|
23
|
-
|
|
24
|
-
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
25
|
-
<template b-id="my-component" b-data="{ count: 0 }">
|
|
26
|
-
<h1>Hello Lego!</h1>
|
|
27
|
-
<button @click="count++">Click me</button>
|
|
28
|
-
<p>Count: [[ count ]]</p>
|
|
29
|
-
</template>
|
|
30
|
-
</body>
|
|
31
|
-
</html>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
That's it! Open this HTML file in any browser and it works.
|
|
35
|
-
|
|
36
|
-
### Option 2: npm
|
|
37
|
-
|
|
38
|
-
For projects using npm:
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
npm install lego-dom
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Then import it:
|
|
45
|
-
|
|
46
|
-
```js
|
|
47
|
-
import { Lego } from 'lego-dom';
|
|
48
|
-
|
|
49
|
-
Lego.define('my-component', `
|
|
50
|
-
<h1>Hello Lego!</h1>
|
|
51
|
-
<button @click="count++">Click me</button>
|
|
52
|
-
<p>Count: [[ count ]]</p>
|
|
53
|
-
`, {
|
|
54
|
-
count: 0,
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Option 3: With Vite (Recommended for Larger Projects)
|
|
59
|
-
|
|
60
|
-
For the best development experience with `.lego` Single File Components:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
npm create vite@latest my-lego-app
|
|
64
|
-
cd my-lego-app
|
|
65
|
-
npm install lego-dom
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
Configure `vite.config.js`:
|
|
69
|
-
|
|
70
|
-
```js
|
|
71
|
-
import { defineConfig } from 'vite';
|
|
72
|
-
import legoPlugin from 'lego-dom/vite-plugin';
|
|
73
|
-
|
|
74
|
-
export default defineConfig({
|
|
75
|
-
plugins: [legoPlugin()]
|
|
76
|
-
});
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### The Runtime Engine
|
|
80
|
-
|
|
81
|
-
Crucially, you must initialize the Lego background engine in your entry file (`src/main.js`):
|
|
82
|
-
|
|
83
|
-
```js
|
|
84
|
-
import { Lego } from 'lego-dom';
|
|
85
|
-
import registerComponents from 'virtual:lego-components';
|
|
86
|
-
|
|
87
|
-
// 1. Register SFCs
|
|
88
|
-
registerComponents();
|
|
89
|
-
|
|
90
|
-
// 2. Start the Engine (Async)
|
|
91
|
-
await Lego.init();
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
## Your First Component
|
|
95
|
-
|
|
96
|
-
Let's create a simple counter component.
|
|
97
|
-
|
|
98
|
-
### Using HTML Templates
|
|
99
|
-
|
|
100
|
-
```html
|
|
101
|
-
<template b-id="click-counter" b-data="{ message: 'Welcome!', count: 0 }">
|
|
102
|
-
<style>
|
|
103
|
-
self {
|
|
104
|
-
display: block;
|
|
105
|
-
padding: 2rem;
|
|
106
|
-
text-align: center;
|
|
107
|
-
background: #f0f0f0;
|
|
108
|
-
border-radius: 8px;
|
|
109
|
-
}
|
|
110
|
-
button {
|
|
111
|
-
font-size: 1.2rem;
|
|
112
|
-
padding: 0.5rem 1.5rem;
|
|
113
|
-
background: #4CAF50;
|
|
114
|
-
color: white;
|
|
115
|
-
border: none;
|
|
116
|
-
border-radius: 4px;
|
|
117
|
-
cursor: pointer;
|
|
118
|
-
}
|
|
119
|
-
button:hover {
|
|
120
|
-
background: #45a049;
|
|
121
|
-
}
|
|
122
|
-
</style>
|
|
123
|
-
|
|
124
|
-
<template b-id="click-counter" b-data="{ message: 'Welcome!', count: 0 }">
|
|
125
|
-
... markup ...
|
|
126
|
-
</template>
|
|
127
|
-
|
|
128
|
-
<!-- Uses defaults: message="Welcome!", count=0 -->
|
|
129
|
-
<click-counter></click-counter>
|
|
130
|
-
|
|
131
|
-
<!-- Overrides message, keeps count=0 -->
|
|
132
|
-
<click-counter b-data="{ message: 'Bienvenido!' }"></click-counter>
|
|
133
|
-
|
|
134
|
-
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
135
|
-
```
|
|
136
|
-
|
|
137
|
-
### Using JavaScript
|
|
138
|
-
|
|
139
|
-
```js
|
|
140
|
-
import { Lego } from 'lego-dom';
|
|
141
|
-
|
|
142
|
-
Lego.define('click-counter', `
|
|
143
|
-
<style>
|
|
144
|
-
self {
|
|
145
|
-
display: block;
|
|
146
|
-
padding: 2rem;
|
|
147
|
-
text-align: center;
|
|
148
|
-
}
|
|
149
|
-
</style>
|
|
150
|
-
|
|
151
|
-
<h2>[[ message ]]</h2>
|
|
152
|
-
<p>Count: [[ count ]]</p>
|
|
153
|
-
<button @click="increment()">Click Me!</button>
|
|
154
|
-
`, {
|
|
155
|
-
message: 'Welcome!',
|
|
156
|
-
count: 0,
|
|
157
|
-
increment() {
|
|
158
|
-
this.count++;
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Then use it in your HTML:
|
|
164
|
-
|
|
165
|
-
```html
|
|
166
|
-
<click-counter></click-counter>
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Using .lego Files (with Vite)
|
|
170
|
-
|
|
171
|
-
Create `src/components/click-counter.lego`:
|
|
172
|
-
|
|
173
|
-
```html
|
|
174
|
-
<template>
|
|
175
|
-
<style>
|
|
176
|
-
self {
|
|
177
|
-
display: block;
|
|
178
|
-
padding: 2rem;
|
|
179
|
-
}
|
|
180
|
-
</style>
|
|
181
|
-
|
|
182
|
-
<h2>[[ message ]]</h2>
|
|
183
|
-
<p>Count: [[ count ]]</p>
|
|
184
|
-
<button @click="increment()">Click Me!</button>
|
|
185
|
-
</template>
|
|
186
|
-
|
|
187
|
-
<script>
|
|
188
|
-
export default {
|
|
189
|
-
message: 'Welcome!',
|
|
190
|
-
count: 0,
|
|
191
|
-
increment() {
|
|
192
|
-
this.count++;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
</script>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
The Vite plugin automatically discovers and registers it!
|
|
199
|
-
|
|
200
|
-
## Understanding the Basics
|
|
201
|
-
|
|
202
|
-
### 1. Templates
|
|
203
|
-
|
|
204
|
-
Templates define what your component looks like. Use `[[ ]]` for dynamic content:
|
|
205
|
-
|
|
206
|
-
```html
|
|
207
|
-
<h1>Hello [[ name ]]!</h1>
|
|
208
|
-
<p>[[ calculateAge() ]] years old</p>
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### 2. State (Studs)
|
|
212
|
-
|
|
213
|
-
Each component has reactive state called "studs":
|
|
214
|
-
|
|
215
|
-
```js
|
|
216
|
-
{
|
|
217
|
-
name: 'Alice',
|
|
218
|
-
age: 25,
|
|
219
|
-
calculateAge() {
|
|
220
|
-
return new Date().getFullYear() - 1999;
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
### 3. Events
|
|
226
|
-
|
|
227
|
-
Use `@eventname` to handle events:
|
|
228
|
-
|
|
229
|
-
```html
|
|
230
|
-
<button @click="handleClick()">Click</button>
|
|
231
|
-
<input @input="handleInput()" />
|
|
232
|
-
<form @submit="handleSubmit(event)">
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
### 4. Directives
|
|
236
|
-
|
|
237
|
-
Special attributes for common patterns:
|
|
238
|
-
|
|
239
|
-
- `b-show` - Conditional rendering
|
|
240
|
-
- `b-for` - List rendering
|
|
241
|
-
- `b-sync` - Two-way binding
|
|
242
|
-
|
|
243
|
-
```html
|
|
244
|
-
<p b-show="isLoggedIn">Welcome back!</p>
|
|
245
|
-
<li b-for="item in items">[[ item.name ]]</li>
|
|
246
|
-
<input b-sync="username" />
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
## What You've Learned
|
|
250
|
-
|
|
251
|
-
- ✅ Three different ways to install Lego
|
|
252
|
-
- ✅ How to create your first component
|
|
253
|
-
- ✅ The basics of templates, state, and events
|
|
254
|
-
- ✅ Available directives
|
|
255
|
-
- ✅ The importance of the `Lego.init()` engine
|
|
256
|
-
|
|
257
|
-
## Next Steps
|
|
258
|
-
|
|
259
|
-
- Learn about [Components](/guide/components) in depth
|
|
260
|
-
- Explore [Reactivity](/guide/reactivity) and how it works
|
|
261
|
-
- Check out [Templating](/guide/templating) features
|
|
262
|
-
- See [Examples](/examples/) of real applications
|