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.
- package/.github/workflows/deploy-docs.yml +56 -0
- package/LICENSE +21 -0
- package/README.md +52 -314
- package/docs/.vitepress/config.js +107 -0
- package/docs/.vitepress/dist/404.html +22 -0
- package/docs/.vitepress/dist/api/define.html +35 -0
- package/docs/.vitepress/dist/api/directives.html +32 -0
- package/docs/.vitepress/dist/api/globals.html +27 -0
- package/docs/.vitepress/dist/api/index.html +25 -0
- package/docs/.vitepress/dist/api/lifecycle.html +38 -0
- package/docs/.vitepress/dist/api/route.html +34 -0
- package/docs/.vitepress/dist/api/vite-plugin.html +37 -0
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.js +11 -0
- package/docs/.vitepress/dist/assets/api_define.md.UA-ygUnQ.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.js +8 -0
- package/docs/.vitepress/dist/assets/api_directives.md.BV-D251p.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_globals.md.CEznyRAY.js +3 -0
- package/docs/.vitepress/dist/assets/api_globals.md.CEznyRAY.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.js +1 -0
- package/docs/.vitepress/dist/assets/api_index.md.IEYUxUIr.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.js +14 -0
- package/docs/.vitepress/dist/assets/api_lifecycle.md.Ccm5xw6-.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.js +10 -0
- package/docs/.vitepress/dist/assets/api_route.md.CAHf_KNp.lean.js +1 -0
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DC8Li09k.js +13 -0
- package/docs/.vitepress/dist/assets/api_vite-plugin.md.DC8Li09k.lean.js +1 -0
- package/docs/.vitepress/dist/assets/app.BfblNDJy.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/@localSearchIndexroot.Crdp7-Zp.js +1 -0
- package/docs/.vitepress/dist/assets/chunks/VPLocalSearchBox.C18E44rY.js +9 -0
- package/docs/.vitepress/dist/assets/chunks/framework.B7OFBR9X.js +19 -0
- package/docs/.vitepress/dist/assets/chunks/theme.VX3itTW6.js +2 -0
- package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.js +34 -0
- package/docs/.vitepress/dist/assets/examples_form.md.DQoAgbLR.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.js +28 -0
- package/docs/.vitepress/dist/assets/examples_index.md.CVJJjXXE.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.js +338 -0
- package/docs/.vitepress/dist/assets/examples_routing.md.sRnA5RXw.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.js +13 -0
- package/docs/.vitepress/dist/assets/examples_sfc-showcase.md.DPf9Wm99.lean.js +1 -0
- package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.js +297 -0
- package/docs/.vitepress/dist/assets/examples_todo-app.md.CqF4JaWn.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.js +182 -0
- package/docs/.vitepress/dist/assets/guide_cdn-usage.md.CjIjusre.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.js +174 -0
- package/docs/.vitepress/dist/assets/guide_components.md.CMU3iM6R.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.js +1 -0
- package/docs/.vitepress/dist/assets/guide_contributing.md.Crrv3T_0.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.js +140 -0
- package/docs/.vitepress/dist/assets/guide_directives.md.DFwqvqOv.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.js +107 -0
- package/docs/.vitepress/dist/assets/guide_getting-started.md.DtaJPe0i.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.js +2 -0
- package/docs/.vitepress/dist/assets/guide_index.md.DtJVpLI9.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.js +304 -0
- package/docs/.vitepress/dist/assets/guide_lifecycle.md.CfY3jlU1.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.js +33 -0
- package/docs/.vitepress/dist/assets/guide_quick-start.md.CwdNNA21.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.js +135 -0
- package/docs/.vitepress/dist/assets/guide_reactivity.md.DgTH0MTn.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.js +193 -0
- package/docs/.vitepress/dist/assets/guide_routing.md.nMB0QOBR.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.js +187 -0
- package/docs/.vitepress/dist/assets/guide_sfc.md.BUkWma1z.lean.js +1 -0
- package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.js +119 -0
- package/docs/.vitepress/dist/assets/guide_templating.md.XI3uUlYI.lean.js +1 -0
- package/docs/.vitepress/dist/assets/index.md.M4_o26kF.js +23 -0
- package/docs/.vitepress/dist/assets/index.md.M4_o26kF.lean.js +1 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/docs/.vitepress/dist/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/docs/.vitepress/dist/assets/style.eycE2Jhw.css +1 -0
- package/docs/.vitepress/dist/examples/form.html +58 -0
- package/docs/.vitepress/dist/examples/index.html +52 -0
- package/docs/.vitepress/dist/examples/routing.html +362 -0
- package/docs/.vitepress/dist/examples/sfc-showcase.html +37 -0
- package/docs/.vitepress/dist/examples/todo-app.html +321 -0
- package/docs/.vitepress/dist/guide/cdn-usage.html +206 -0
- package/docs/.vitepress/dist/guide/components.html +198 -0
- package/docs/.vitepress/dist/guide/contributing.html +25 -0
- package/docs/.vitepress/dist/guide/directives.html +164 -0
- package/docs/.vitepress/dist/guide/getting-started.html +131 -0
- package/docs/.vitepress/dist/guide/index.html +26 -0
- package/docs/.vitepress/dist/guide/lifecycle.html +328 -0
- package/docs/.vitepress/dist/guide/quick-start.html +57 -0
- package/docs/.vitepress/dist/guide/reactivity.html +159 -0
- package/docs/.vitepress/dist/guide/routing.html +217 -0
- package/docs/.vitepress/dist/guide/sfc.html +211 -0
- package/docs/.vitepress/dist/guide/templating.html +143 -0
- package/docs/.vitepress/dist/hashmap.json +1 -0
- package/docs/.vitepress/dist/index.html +47 -0
- package/docs/.vitepress/dist/logo.svg +38 -0
- package/docs/.vitepress/dist/vp-icons.css +1 -0
- package/docs/api/define.md +31 -0
- package/docs/api/directives.md +42 -0
- package/docs/api/globals.md +29 -0
- package/docs/api/index.md +29 -0
- package/docs/api/lifecycle.md +40 -0
- package/docs/api/route.md +37 -0
- package/docs/api/vite-plugin.md +58 -0
- package/docs/examples/form.md +42 -0
- package/docs/examples/index.md +104 -0
- package/docs/examples/routing.md +409 -0
- package/docs/examples/sfc-showcase.md +34 -0
- package/docs/examples/todo-app.md +383 -0
- package/docs/guide/cdn-usage.md +320 -0
- package/docs/guide/components.md +394 -0
- package/docs/guide/contributing.md +32 -0
- package/docs/guide/directives.md +430 -0
- package/docs/guide/getting-started.md +233 -0
- package/docs/guide/index.md +88 -0
- package/docs/guide/lifecycle.md +493 -0
- package/docs/guide/quick-start.md +46 -0
- package/docs/guide/reactivity.md +394 -0
- package/docs/guide/routing.md +373 -0
- package/docs/guide/sfc.md +381 -0
- package/docs/guide/templating.md +383 -0
- package/docs/index.md +126 -0
- package/docs/public/logo.svg +17 -0
- package/examples/vite-app/README.md +71 -0
- package/examples/vite-app/index.html +49 -0
- package/examples/vite-app/package.json +16 -0
- package/examples/vite-app/src/components/greeting-card.lego +41 -0
- package/examples/vite-app/src/components/sample-component.lego +75 -0
- package/examples/vite-app/src/components/todo-list.lego +242 -0
- package/examples/vite-app/src/main.js +11 -0
- package/examples/vite-app/vite.config.js +17 -0
- package/examples.js +99 -0
- package/go.html +117 -0
- package/lego.js +2 -0
- package/main.js +41 -35
- package/package.json +39 -6
- package/parse-lego.js +119 -0
- package/parse-lego.test.js +107 -0
- package/vite-plugin.js +133 -0
- package/.ignore/auto.html +0 -135
- package/.ignore/test.html +0 -73
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Directives
|
|
2
|
+
|
|
3
|
+
Directives are special attributes that add reactive behavior to elements.
|
|
4
|
+
|
|
5
|
+
## b-if
|
|
6
|
+
|
|
7
|
+
Conditional rendering using `display: none`.
|
|
8
|
+
|
|
9
|
+
### Basic Usage
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<p b-if="isLoggedIn">Welcome back!</p>
|
|
13
|
+
<p b-if="!isLoggedIn">Please log in</p>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
### With Expressions
|
|
17
|
+
|
|
18
|
+
```html
|
|
19
|
+
<div b-if="count > 0">Count is {{ count }}</div>
|
|
20
|
+
<div b-if="items.length === 0">No items</div>
|
|
21
|
+
<div b-if="user && user.role === 'admin'">Admin panel</div>
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Multiple Conditions
|
|
25
|
+
|
|
26
|
+
```html
|
|
27
|
+
<p b-if="isLoggedIn && isPremium">Premium content</p>
|
|
28
|
+
<p b-if="age >= 18 || hasParentConsent">Access granted</p>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
::: tip How it Works
|
|
32
|
+
`b-if` sets `display: none` when the condition is false. The element stays in the DOM but is hidden.
|
|
33
|
+
:::
|
|
34
|
+
|
|
35
|
+
## b-for
|
|
36
|
+
|
|
37
|
+
List rendering.
|
|
38
|
+
|
|
39
|
+
### Basic Syntax
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<ul>
|
|
43
|
+
<li b-for="item in items">{{ item }}</li>
|
|
44
|
+
</ul>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### With Objects
|
|
48
|
+
|
|
49
|
+
```html
|
|
50
|
+
<ul>
|
|
51
|
+
<li b-for="todo in todos">
|
|
52
|
+
{{ todo.text }} - {{ todo.done ? 'Done' : 'Pending' }}
|
|
53
|
+
</li>
|
|
54
|
+
</ul>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Accessing Index
|
|
58
|
+
|
|
59
|
+
Use `$index` (implicit variable):
|
|
60
|
+
|
|
61
|
+
```html
|
|
62
|
+
<ul>
|
|
63
|
+
<li b-for="item in items">
|
|
64
|
+
#{{ $index + 1 }}: {{ item.name }}
|
|
65
|
+
</li>
|
|
66
|
+
</ul>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Nested Loops
|
|
70
|
+
|
|
71
|
+
```html
|
|
72
|
+
<div b-for="category in categories">
|
|
73
|
+
<h3>{{ category.name }}</h3>
|
|
74
|
+
<ul>
|
|
75
|
+
<li b-for="product in category.products">
|
|
76
|
+
{{ product.name }}
|
|
77
|
+
</li>
|
|
78
|
+
</ul>
|
|
79
|
+
</div>
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### With Conditionals
|
|
83
|
+
|
|
84
|
+
```html
|
|
85
|
+
<li b-for="user in users">
|
|
86
|
+
<span b-if="user.active">✅ {{ user.name }}</span>
|
|
87
|
+
<span b-if="!user.active">❌ {{ user.name }}</span>
|
|
88
|
+
</li>
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## b-sync
|
|
92
|
+
|
|
93
|
+
Two-way data binding for form inputs.
|
|
94
|
+
|
|
95
|
+
### Text Input
|
|
96
|
+
|
|
97
|
+
```html
|
|
98
|
+
<input b-sync="username" placeholder="Enter username">
|
|
99
|
+
<p>Hello, {{ username }}!</p>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Checkbox
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<input type="checkbox" b-sync="agreed">
|
|
106
|
+
<p b-if="agreed">You agreed to the terms</p>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Radio Buttons
|
|
110
|
+
|
|
111
|
+
```html
|
|
112
|
+
<input type="radio" name="size" value="small" b-sync="selectedSize">
|
|
113
|
+
<input type="radio" name="size" value="medium" b-sync="selectedSize">
|
|
114
|
+
<input type="radio" name="size" value="large" b-sync="selectedSize">
|
|
115
|
+
<p>Selected: {{ selectedSize }}</p>
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
### Select Dropdown
|
|
119
|
+
|
|
120
|
+
```html
|
|
121
|
+
<select b-sync="country">
|
|
122
|
+
<option value="us">United States</option>
|
|
123
|
+
<option value="uk">United Kingdom</option>
|
|
124
|
+
<option value="ca">Canada</option>
|
|
125
|
+
</select>
|
|
126
|
+
<p>Country: {{ country }}</p>
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Textarea
|
|
130
|
+
|
|
131
|
+
```html
|
|
132
|
+
<textarea b-sync="message" rows="4"></textarea>
|
|
133
|
+
<p>{{ message.length }} characters</p>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### In b-for Loops
|
|
137
|
+
|
|
138
|
+
```html
|
|
139
|
+
<li b-for="todo in todos">
|
|
140
|
+
<input type="checkbox" b-sync="todo.done">
|
|
141
|
+
<span class="{{ todo.done ? 'done' : '' }}">{{ todo.text }}</span>
|
|
142
|
+
</li>
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## @event
|
|
146
|
+
|
|
147
|
+
Event handlers.
|
|
148
|
+
|
|
149
|
+
### Common Events
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<!-- Click -->
|
|
153
|
+
<button @click="handleClick()">Click Me</button>
|
|
154
|
+
|
|
155
|
+
<!-- Input -->
|
|
156
|
+
<input @input="handleInput()">
|
|
157
|
+
|
|
158
|
+
<!-- Change -->
|
|
159
|
+
<select @change="handleChange()">...</select>
|
|
160
|
+
|
|
161
|
+
<!-- Submit -->
|
|
162
|
+
<form @submit="handleSubmit(event)">...</form>
|
|
163
|
+
|
|
164
|
+
<!-- Focus/Blur -->
|
|
165
|
+
<input @focus="onFocus()" @blur="onBlur()">
|
|
166
|
+
|
|
167
|
+
<!-- Mouse Events -->
|
|
168
|
+
<div @mouseenter="onHover()" @mouseleave="onLeave()">Hover me</div>
|
|
169
|
+
|
|
170
|
+
<!-- Keyboard -->
|
|
171
|
+
<input @keyup="onKeyUp(event)" @keydown="onKeyDown(event)">
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Event Object
|
|
175
|
+
|
|
176
|
+
Access the native event object:
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<button @click="handleClick(event)">Click</button>
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```js
|
|
183
|
+
{
|
|
184
|
+
handleClick(event) {
|
|
185
|
+
console.log('Target:', event.target);
|
|
186
|
+
console.log('Type:', event.type);
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
event.stopPropagation();
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Inline Expressions
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<button @click="count++">Increment</button>
|
|
197
|
+
<button @click="items.push('new item')">Add Item</button>
|
|
198
|
+
<button @click="$emit('save', { id: 123 })">Save</button>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Key Events
|
|
202
|
+
|
|
203
|
+
```html
|
|
204
|
+
<input @keyup="event.key === 'Enter' && submit()">
|
|
205
|
+
<input @keydown="event.key === 'Escape' && cancel()">
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## b-link
|
|
209
|
+
|
|
210
|
+
Client-side navigation (prevents page reload).
|
|
211
|
+
|
|
212
|
+
### Basic Usage
|
|
213
|
+
|
|
214
|
+
```html
|
|
215
|
+
<a href="/" b-link>Home</a>
|
|
216
|
+
<a href="/about" b-link>About</a>
|
|
217
|
+
<a href="/contact" b-link>Contact</a>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### With Dynamic Routes
|
|
221
|
+
|
|
222
|
+
```html
|
|
223
|
+
<a href="/user/{{ userId }}" b-link>View Profile</a>
|
|
224
|
+
<a href="/product/{{ productId }}" b-link>{{ productName }}</a>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
::: tip Router Required
|
|
228
|
+
`b-link` only works if you've set up routing with `Lego.route()`.
|
|
229
|
+
:::
|
|
230
|
+
|
|
231
|
+
## b-data
|
|
232
|
+
|
|
233
|
+
Initialize component state.
|
|
234
|
+
|
|
235
|
+
### Basic Usage
|
|
236
|
+
|
|
237
|
+
```html
|
|
238
|
+
<my-component b-data="{ count: 0, name: 'Alice' }"></my-component>
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
### With Complex Data
|
|
242
|
+
|
|
243
|
+
```html
|
|
244
|
+
<todo-list b-data="{
|
|
245
|
+
todos: [
|
|
246
|
+
{ text: 'Learn Lego', done: true },
|
|
247
|
+
{ text: 'Build app', done: false }
|
|
248
|
+
],
|
|
249
|
+
filter: 'all'
|
|
250
|
+
}"></todo-list>
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
### Merging with Defaults
|
|
254
|
+
|
|
255
|
+
```js
|
|
256
|
+
// Component definition
|
|
257
|
+
Lego.define('user-card', `...`, {
|
|
258
|
+
name: 'Guest', // Default
|
|
259
|
+
role: 'user' // Default
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```html
|
|
264
|
+
<!-- Only name is overridden -->
|
|
265
|
+
<user-card b-data="{ name: 'Alice' }"></user-card>
|
|
266
|
+
<!-- role remains 'user' -->
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
## Combining Directives
|
|
270
|
+
|
|
271
|
+
### b-if + b-for
|
|
272
|
+
|
|
273
|
+
```html
|
|
274
|
+
<li b-for="item in items" b-if="item.visible">
|
|
275
|
+
{{ item.name }}
|
|
276
|
+
</li>
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### b-for + b-sync
|
|
280
|
+
|
|
281
|
+
```html
|
|
282
|
+
<li b-for="todo in todos">
|
|
283
|
+
<input type="checkbox" b-sync="todo.done">
|
|
284
|
+
{{ todo.text }}
|
|
285
|
+
</li>
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
### Multiple Events
|
|
289
|
+
|
|
290
|
+
```html
|
|
291
|
+
<input
|
|
292
|
+
@input="handleInput()"
|
|
293
|
+
@focus="onFocus()"
|
|
294
|
+
@blur="onBlur()">
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
## Best Practices
|
|
298
|
+
|
|
299
|
+
### 1. Use b-if for Show/Hide
|
|
300
|
+
|
|
301
|
+
```html
|
|
302
|
+
<!-- ✅ Clean -->
|
|
303
|
+
<div b-if="showPanel">Panel content</div>
|
|
304
|
+
|
|
305
|
+
<!-- ❌ Verbose -->
|
|
306
|
+
<div style="display: {{ showPanel ? 'block' : 'none' }}">Panel content</div>
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### 2. Keep Event Handlers Simple
|
|
310
|
+
|
|
311
|
+
```html
|
|
312
|
+
<!-- ✅ Good -->
|
|
313
|
+
<button @click="increment()">+1</button>
|
|
314
|
+
|
|
315
|
+
<!-- ❌ Too much logic -->
|
|
316
|
+
<button @click="count++; total = count * price; updateDisplay()">Calculate</button>
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Move complex logic to methods.
|
|
320
|
+
|
|
321
|
+
### 3. Use b-sync for Forms
|
|
322
|
+
|
|
323
|
+
```html
|
|
324
|
+
<!-- ✅ Declarative -->
|
|
325
|
+
<input b-sync="username">
|
|
326
|
+
|
|
327
|
+
<!-- ❌ Imperative -->
|
|
328
|
+
<input @input="username = event.target.value">
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
### 4. Avoid Deep Nesting in b-for
|
|
332
|
+
|
|
333
|
+
```html
|
|
334
|
+
<!-- ❌ Hard to read -->
|
|
335
|
+
<div b-for="cat in categories">
|
|
336
|
+
<div b-for="sub in cat.subcategories">
|
|
337
|
+
<div b-for="item in sub.items">...</div>
|
|
338
|
+
</div>
|
|
339
|
+
</div>
|
|
340
|
+
|
|
341
|
+
<!-- ✅ Break into components -->
|
|
342
|
+
<category-list></category-list>
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## Performance Tips
|
|
346
|
+
|
|
347
|
+
### b-if vs CSS
|
|
348
|
+
|
|
349
|
+
`b-if` is fine for most cases, but for frequently toggled elements, use CSS:
|
|
350
|
+
|
|
351
|
+
```html
|
|
352
|
+
<!-- For frequent toggling -->
|
|
353
|
+
<div class="{{ visible ? '' : 'hidden' }}">Content</div>
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
```css
|
|
357
|
+
.hidden {
|
|
358
|
+
display: none;
|
|
359
|
+
}
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
### Limit b-for Items
|
|
363
|
+
|
|
364
|
+
Paginate large lists:
|
|
365
|
+
|
|
366
|
+
```js
|
|
367
|
+
{
|
|
368
|
+
allItems: [...], // 1000 items
|
|
369
|
+
currentPage: 1,
|
|
370
|
+
itemsPerPage: 20,
|
|
371
|
+
|
|
372
|
+
visibleItems() {
|
|
373
|
+
const start = (this.currentPage - 1) * this.itemsPerPage;
|
|
374
|
+
return this.allItems.slice(start, start + this.itemsPerPage);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
```html
|
|
380
|
+
<li b-for="item in visibleItems()">{{ item.name }}</li>
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
## Common Patterns
|
|
384
|
+
|
|
385
|
+
### Toggle
|
|
386
|
+
|
|
387
|
+
```html
|
|
388
|
+
<button @click="visible = !visible">Toggle</button>
|
|
389
|
+
<div b-if="visible">Content</div>
|
|
390
|
+
```
|
|
391
|
+
|
|
392
|
+
### Counter
|
|
393
|
+
|
|
394
|
+
```html
|
|
395
|
+
<button @click="count--">-</button>
|
|
396
|
+
<span>{{ count }}</span>
|
|
397
|
+
<button @click="count++">+</button>
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
### Todo List
|
|
401
|
+
|
|
402
|
+
```html
|
|
403
|
+
<input b-sync="newTodo" @keyup="event.key === 'Enter' && addTodo()">
|
|
404
|
+
<ul>
|
|
405
|
+
<li b-for="todo in todos">
|
|
406
|
+
<input type="checkbox" b-sync="todo.done">
|
|
407
|
+
<span class="{{ todo.done ? 'done' : '' }}">{{ todo.text }}</span>
|
|
408
|
+
</li>
|
|
409
|
+
</ul>
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Tabs
|
|
413
|
+
|
|
414
|
+
```html
|
|
415
|
+
<nav>
|
|
416
|
+
<button @click="activeTab = 'home'">Home</button>
|
|
417
|
+
<button @click="activeTab = 'profile'">Profile</button>
|
|
418
|
+
<button @click="activeTab = 'settings'">Settings</button>
|
|
419
|
+
</nav>
|
|
420
|
+
|
|
421
|
+
<div b-if="activeTab === 'home'">Home content</div>
|
|
422
|
+
<div b-if="activeTab === 'profile'">Profile content</div>
|
|
423
|
+
<div b-if="activeTab === 'settings'">Settings content</div>
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
## Next Steps
|
|
427
|
+
|
|
428
|
+
- See [directive examples](/examples/)
|
|
429
|
+
- Learn about [event handling](/guide/directives#event)
|
|
430
|
+
- Explore [form patterns](/examples/form)
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
Get up and running with Lego in under 5 minutes.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
### Option 1: CDN (No Build Tools)
|
|
8
|
+
|
|
9
|
+
The fastest way to try Lego is via CDN:
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<!DOCTYPE html>
|
|
13
|
+
<html>
|
|
14
|
+
<head>
|
|
15
|
+
<title>My Lego App</title>
|
|
16
|
+
</head>
|
|
17
|
+
<body>
|
|
18
|
+
<my-component></my-component>
|
|
19
|
+
|
|
20
|
+
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
21
|
+
<template b-id="my-component">
|
|
22
|
+
<h1>Hello Lego!</h1>
|
|
23
|
+
</template>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
That's it! Open this HTML file in any browser and it works.
|
|
29
|
+
|
|
30
|
+
### Option 2: npm
|
|
31
|
+
|
|
32
|
+
For projects using npm:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
npm install lego-dom
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Then import it:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
import { Lego } from 'lego-dom';
|
|
42
|
+
|
|
43
|
+
Lego.define('my-component', `
|
|
44
|
+
<h1>Hello Lego!</h1>
|
|
45
|
+
`);
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Option 3: With Vite (Recommended for Larger Projects)
|
|
49
|
+
|
|
50
|
+
For the best development experience with `.lego` Single File Components:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
npm create vite@latest my-lego-app
|
|
54
|
+
cd my-lego-app
|
|
55
|
+
npm install lego-dom
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Configure `vite.config.js`:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import { defineConfig } from 'vite';
|
|
62
|
+
import legoPlugin from 'lego-dom/vite-plugin';
|
|
63
|
+
|
|
64
|
+
export default defineConfig({
|
|
65
|
+
plugins: [legoPlugin()]
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Your First Component
|
|
70
|
+
|
|
71
|
+
Let's create a simple counter component.
|
|
72
|
+
|
|
73
|
+
### Using HTML Templates
|
|
74
|
+
|
|
75
|
+
```html
|
|
76
|
+
<template b-id="click-counter">
|
|
77
|
+
<style>
|
|
78
|
+
self {
|
|
79
|
+
display: block;
|
|
80
|
+
padding: 2rem;
|
|
81
|
+
text-align: center;
|
|
82
|
+
background: #f0f0f0;
|
|
83
|
+
border-radius: 8px;
|
|
84
|
+
}
|
|
85
|
+
button {
|
|
86
|
+
font-size: 1.2rem;
|
|
87
|
+
padding: 0.5rem 1.5rem;
|
|
88
|
+
background: #4CAF50;
|
|
89
|
+
color: white;
|
|
90
|
+
border: none;
|
|
91
|
+
border-radius: 4px;
|
|
92
|
+
cursor: pointer;
|
|
93
|
+
}
|
|
94
|
+
button:hover {
|
|
95
|
+
background: #45a049;
|
|
96
|
+
}
|
|
97
|
+
</style>
|
|
98
|
+
|
|
99
|
+
<h2>{{ message }}</h2>
|
|
100
|
+
<p>Count: <strong>{{ count }}</strong></p>
|
|
101
|
+
<button @click="count++">Click Me!</button>
|
|
102
|
+
</template>
|
|
103
|
+
|
|
104
|
+
<click-counter b-data="{ message: 'Welcome!', count: 0 }"></click-counter>
|
|
105
|
+
|
|
106
|
+
<script src="https://unpkg.com/lego-dom/main.js"></script>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Using JavaScript
|
|
110
|
+
|
|
111
|
+
```js
|
|
112
|
+
import { Lego } from 'lego-dom';
|
|
113
|
+
|
|
114
|
+
Lego.define('click-counter', `
|
|
115
|
+
<style>
|
|
116
|
+
self {
|
|
117
|
+
display: block;
|
|
118
|
+
padding: 2rem;
|
|
119
|
+
text-align: center;
|
|
120
|
+
}
|
|
121
|
+
</style>
|
|
122
|
+
|
|
123
|
+
<h2>{{ message }}</h2>
|
|
124
|
+
<p>Count: {{ count }}</p>
|
|
125
|
+
<button @click="increment()">Click Me!</button>
|
|
126
|
+
`, {
|
|
127
|
+
message: 'Welcome!',
|
|
128
|
+
count: 0,
|
|
129
|
+
increment() {
|
|
130
|
+
this.count++;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Then use it in your HTML:
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<click-counter></click-counter>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Using .lego Files (with Vite)
|
|
142
|
+
|
|
143
|
+
Create `src/components/click-counter.lego`:
|
|
144
|
+
|
|
145
|
+
```html
|
|
146
|
+
<template>
|
|
147
|
+
<style>
|
|
148
|
+
self {
|
|
149
|
+
display: block;
|
|
150
|
+
padding: 2rem;
|
|
151
|
+
}
|
|
152
|
+
</style>
|
|
153
|
+
|
|
154
|
+
<h2>{{ message }}</h2>
|
|
155
|
+
<p>Count: {{ count }}</p>
|
|
156
|
+
<button @click="increment()">Click Me!</button>
|
|
157
|
+
</template>
|
|
158
|
+
|
|
159
|
+
<script>
|
|
160
|
+
export default {
|
|
161
|
+
message: 'Welcome!',
|
|
162
|
+
count: 0,
|
|
163
|
+
increment() {
|
|
164
|
+
this.count++;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
</script>
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
The Vite plugin automatically discovers and registers it!
|
|
171
|
+
|
|
172
|
+
## Understanding the Basics
|
|
173
|
+
|
|
174
|
+
### 1. Templates
|
|
175
|
+
|
|
176
|
+
Templates define what your component looks like. Use `{{ }}` for dynamic content:
|
|
177
|
+
|
|
178
|
+
```html
|
|
179
|
+
<h1>Hello {{ name }}!</h1>
|
|
180
|
+
<p>{{ calculateAge() }} years old</p>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 2. State (Studs)
|
|
184
|
+
|
|
185
|
+
Each component has reactive state called "studs":
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
{
|
|
189
|
+
name: 'Alice',
|
|
190
|
+
age: 25,
|
|
191
|
+
calculateAge() {
|
|
192
|
+
return new Date().getFullYear() - 1999;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### 3. Events
|
|
198
|
+
|
|
199
|
+
Use `@eventname` to handle events:
|
|
200
|
+
|
|
201
|
+
```html
|
|
202
|
+
<button @click="handleClick()">Click</button>
|
|
203
|
+
<input @input="handleInput()" />
|
|
204
|
+
<form @submit="handleSubmit(event)">
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### 4. Directives
|
|
208
|
+
|
|
209
|
+
Special attributes for common patterns:
|
|
210
|
+
|
|
211
|
+
- `b-if` - Conditional rendering
|
|
212
|
+
- `b-for` - List rendering
|
|
213
|
+
- `b-sync` - Two-way binding
|
|
214
|
+
|
|
215
|
+
```html
|
|
216
|
+
<p b-if="isLoggedIn">Welcome back!</p>
|
|
217
|
+
<li b-for="item in items">{{ item.name }}</li>
|
|
218
|
+
<input b-sync="username" />
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
## What You've Learned
|
|
222
|
+
|
|
223
|
+
- ✅ Three different ways to install Lego
|
|
224
|
+
- ✅ How to create your first component
|
|
225
|
+
- ✅ The basics of templates, state, and events
|
|
226
|
+
- ✅ Available directives
|
|
227
|
+
|
|
228
|
+
## Next Steps
|
|
229
|
+
|
|
230
|
+
- Learn about [Components](/guide/components) in depth
|
|
231
|
+
- Explore [Reactivity](/guide/reactivity) and how it works
|
|
232
|
+
- Check out [Templating](/guide/templating) features
|
|
233
|
+
- See [Examples](/examples/) of real applications
|