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.
Files changed (93) hide show
  1. package/CHANGELOG.md +72 -1
  2. package/main.js +48 -17
  3. package/main.min.js +2 -2
  4. package/package.json +1 -1
  5. package/parse-lego.js +2 -2
  6. package/vite-plugin.js +0 -14
  7. package/.github/workflows/deploy-docs.yml +0 -56
  8. package/.legodom +0 -87
  9. package/docs/.vitepress/config.js +0 -161
  10. package/docs/api/config.md +0 -95
  11. package/docs/api/define.md +0 -58
  12. package/docs/api/directives.md +0 -50
  13. package/docs/api/globals.md +0 -29
  14. package/docs/api/index.md +0 -30
  15. package/docs/api/lifecycle.md +0 -40
  16. package/docs/api/route.md +0 -37
  17. package/docs/api/vite-plugin.md +0 -58
  18. package/docs/contributing/01-welcome.md +0 -38
  19. package/docs/contributing/02-registry.md +0 -133
  20. package/docs/contributing/03-batcher.md +0 -110
  21. package/docs/contributing/04-reactivity.md +0 -87
  22. package/docs/contributing/05-caching.md +0 -59
  23. package/docs/contributing/06-init.md +0 -136
  24. package/docs/contributing/07-observer.md +0 -72
  25. package/docs/contributing/08-snap.md +0 -140
  26. package/docs/contributing/09-diffing.md +0 -69
  27. package/docs/contributing/10-studs.md +0 -78
  28. package/docs/contributing/11-scanner.md +0 -117
  29. package/docs/contributing/12-render.md +0 -138
  30. package/docs/contributing/13-directives.md +0 -243
  31. package/docs/contributing/14-events.md +0 -57
  32. package/docs/contributing/15-router.md +0 -57
  33. package/docs/contributing/16-state.md +0 -47
  34. package/docs/contributing/17-legodom.md +0 -48
  35. package/docs/contributing/index.md +0 -24
  36. package/docs/examples/form.md +0 -42
  37. package/docs/examples/index.md +0 -104
  38. package/docs/examples/routing.md +0 -409
  39. package/docs/examples/sfc-showcase.md +0 -34
  40. package/docs/examples/todo-app.md +0 -383
  41. package/docs/guide/cdn-usage.md +0 -354
  42. package/docs/guide/components.md +0 -418
  43. package/docs/guide/directives.md +0 -539
  44. package/docs/guide/directory-structure.md +0 -248
  45. package/docs/guide/faq.md +0 -210
  46. package/docs/guide/getting-started.md +0 -262
  47. package/docs/guide/index.md +0 -88
  48. package/docs/guide/lifecycle.md +0 -525
  49. package/docs/guide/quick-start.md +0 -49
  50. package/docs/guide/reactivity.md +0 -415
  51. package/docs/guide/routing.md +0 -334
  52. package/docs/guide/server-side.md +0 -134
  53. package/docs/guide/sfc.md +0 -464
  54. package/docs/guide/templating.md +0 -388
  55. package/docs/index.md +0 -160
  56. package/docs/public/logo.svg +0 -17
  57. package/docs/router/basic-routing.md +0 -103
  58. package/docs/router/cold-entry.md +0 -91
  59. package/docs/router/history.md +0 -69
  60. package/docs/router/index.md +0 -73
  61. package/docs/router/resolver.md +0 -74
  62. package/docs/router/surgical-swaps.md +0 -134
  63. package/docs/tutorial/01-project-setup.md +0 -152
  64. package/docs/tutorial/02-your-first-component.md +0 -226
  65. package/docs/tutorial/03-adding-routes.md +0 -279
  66. package/docs/tutorial/04-multi-page-app.md +0 -329
  67. package/docs/tutorial/05-state-and-globals.md +0 -285
  68. package/docs/tutorial/index.md +0 -40
  69. package/examples/vite-app/README.md +0 -71
  70. package/examples/vite-app/index.html +0 -42
  71. package/examples/vite-app/package.json +0 -18
  72. package/examples/vite-app/src/app.css +0 -3
  73. package/examples/vite-app/src/app.js +0 -29
  74. package/examples/vite-app/src/components/app-navbar.lego +0 -34
  75. package/examples/vite-app/src/components/customers/customer-details.lego +0 -24
  76. package/examples/vite-app/src/components/customers/customer-orders.lego +0 -21
  77. package/examples/vite-app/src/components/customers/order-list.lego +0 -55
  78. package/examples/vite-app/src/components/greeting-card.lego +0 -41
  79. package/examples/vite-app/src/components/sample-component.lego +0 -75
  80. package/examples/vite-app/src/components/shells/customers-shell.lego +0 -21
  81. package/examples/vite-app/src/components/side-menu.lego +0 -46
  82. package/examples/vite-app/src/components/todo-list.lego +0 -239
  83. package/examples/vite-app/src/components/widgets/user-card.lego +0 -27
  84. package/examples/vite-app/vite.config.js +0 -22
  85. package/tests/error.test.js +0 -74
  86. package/tests/main.test.js +0 -103
  87. package/tests/memory.test.js +0 -68
  88. package/tests/monitoring.test.js +0 -74
  89. package/tests/naming.test.js +0 -74
  90. package/tests/parse-lego.test.js +0 -65
  91. package/tests/security.test.js +0 -67
  92. package/tests/server.test.js +0 -114
  93. 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