native-document 1.0.10 → 1.0.12
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/dist/native-document.dev.js +2671 -0
- package/dist/native-document.min.js +1 -0
- package/docs/anchor.md +212 -0
- package/docs/conditional-rendering.md +628 -0
- package/docs/contributing.md +51 -0
- package/docs/core-concepts.md +513 -0
- package/docs/elements.md +383 -0
- package/docs/getting-started.md +403 -0
- package/docs/lifecycle-events.md +106 -0
- package/docs/memory-management.md +90 -0
- package/docs/observables.md +265 -0
- package/docs/routing.md +817 -0
- package/docs/state-management.md +423 -0
- package/docs/validation.md +193 -0
- package/elements.js +3 -1
- package/index.js +1 -0
- package/package.json +1 -1
- package/readme.md +189 -425
- package/router.js +2 -0
- package/src/data/MemoryManager.js +15 -5
- package/src/data/Observable.js +15 -2
- package/src/data/ObservableChecker.js +3 -0
- package/src/data/ObservableItem.js +4 -0
- package/src/data/Store.js +6 -6
- package/src/elements/anchor.js +1 -1
- package/src/router/Router.js +13 -13
- package/src/router/link.js +8 -5
- package/src/utils/prototypes.js +13 -0
- package/src/utils/validator.js +16 -0
- package/src/wrappers/AttributesWrapper.js +11 -1
- package/src/wrappers/HtmlElementWrapper.js +4 -1
|
@@ -0,0 +1,513 @@
|
|
|
1
|
+
# Core Concepts
|
|
2
|
+
|
|
3
|
+
This guide covers the fundamental concepts and philosophy behind NativeDocument. Understanding these principles will help you build better applications and make the most of the framework's capabilities.
|
|
4
|
+
|
|
5
|
+
## Philosophy
|
|
6
|
+
|
|
7
|
+
NativeDocument was designed with several core principles in mind:
|
|
8
|
+
|
|
9
|
+
### Native-First Approach
|
|
10
|
+
Unlike frameworks that abstract away the DOM, NativeDocument embraces it. Every element you create is a real DOM node, and every interaction happens through native browser APIs. This means:
|
|
11
|
+
|
|
12
|
+
- No virtual DOM overhead
|
|
13
|
+
- Direct access to all browser features
|
|
14
|
+
- Familiar debugging experience
|
|
15
|
+
- Better performance for DOM-heavy applications
|
|
16
|
+
|
|
17
|
+
### Reactive by Design
|
|
18
|
+
Reactivity is built into the core of NativeDocument through observables. When data changes, the UI updates automatically without manual DOM manipulation:
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const { Div } = NativeDocument.elements;
|
|
22
|
+
const { Observable } = NativeDocument;
|
|
23
|
+
|
|
24
|
+
const message = Observable('Hello World');
|
|
25
|
+
const display = Div(message);
|
|
26
|
+
|
|
27
|
+
// UI updates automatically
|
|
28
|
+
message.set('Hello NativeDocument!');
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Zero Build Requirement
|
|
32
|
+
While you can use build tools, NativeDocument works perfectly without them. Load it from a CDN and start building immediately:
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<script src="https://cdn.jsdelivr.net/gh/afrocodeur/native-document@latest/dist/native-document.min.js"></script>
|
|
36
|
+
<script>
|
|
37
|
+
// Start building immediately
|
|
38
|
+
const { Div } = NativeDocument.elements;
|
|
39
|
+
// Your app here
|
|
40
|
+
</script>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Core Architecture
|
|
44
|
+
|
|
45
|
+
### Observables - The Reactive Foundation
|
|
46
|
+
|
|
47
|
+
Observables are the heart of NativeDocument's reactivity system. They wrap values and notify subscribers when changes occur.
|
|
48
|
+
|
|
49
|
+
#### Basic Observable
|
|
50
|
+
```javascript
|
|
51
|
+
const count = Observable(0);
|
|
52
|
+
|
|
53
|
+
// Subscribe to changes
|
|
54
|
+
count.subscribe(newValue => {
|
|
55
|
+
console.log('Count changed to:', newValue);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// Update the value
|
|
59
|
+
count.set(5); // Logs: "Count changed to: 5"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Observable Objects
|
|
63
|
+
```javascript
|
|
64
|
+
const user = Observable({ name: 'John', age: 25 });
|
|
65
|
+
|
|
66
|
+
// Access values
|
|
67
|
+
console.log(user.val().name); // "John"
|
|
68
|
+
console.log(user.$value.name); // "John" (proxy syntax)
|
|
69
|
+
|
|
70
|
+
// Update object - replaces entire value
|
|
71
|
+
user.set({ ...user.val(), name: 'Jane' });
|
|
72
|
+
|
|
73
|
+
// This won't trigger reactivity (common mistake)
|
|
74
|
+
// user.name = 'Jane'; // Wrong!
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### Observable Arrays
|
|
78
|
+
```javascript
|
|
79
|
+
const todos = Observable.array([]);
|
|
80
|
+
|
|
81
|
+
// Array methods trigger reactivity
|
|
82
|
+
todos.push({ text: 'Learn NativeDocument', done: false });
|
|
83
|
+
todos.pop();
|
|
84
|
+
todos.sort((a, b) => a.text.localeCompare(b.text));
|
|
85
|
+
|
|
86
|
+
// Access like normal array
|
|
87
|
+
console.log(todos.val().length);
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
#### Computed Observables
|
|
91
|
+
```javascript
|
|
92
|
+
const firstName = Observable('John');
|
|
93
|
+
const lastName = Observable('Doe');
|
|
94
|
+
|
|
95
|
+
const fullName = Observable.computed(() => {
|
|
96
|
+
return `${firstName.val()} ${lastName.val()}`;
|
|
97
|
+
}, [firstName, lastName]);
|
|
98
|
+
|
|
99
|
+
// Updates automatically when dependencies change
|
|
100
|
+
firstName.set('Jane'); // fullName becomes "Jane Doe"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Elements - Building the UI
|
|
104
|
+
|
|
105
|
+
Elements in NativeDocument are functions that create and return DOM nodes. They follow a consistent pattern:
|
|
106
|
+
|
|
107
|
+
#### Basic Element Creation
|
|
108
|
+
```javascript
|
|
109
|
+
const { Div, Button, Input } = NativeDocument.elements;
|
|
110
|
+
|
|
111
|
+
// Element with no attributes or children
|
|
112
|
+
const simpleDiv = Div();
|
|
113
|
+
|
|
114
|
+
// Element with attributes only
|
|
115
|
+
const styledDiv = Div({ class: 'container', id: 'main' });
|
|
116
|
+
|
|
117
|
+
// Element with children only
|
|
118
|
+
const textDiv = Div('Hello World');
|
|
119
|
+
const arrayDiv = Div(['Hello ', 'World']);
|
|
120
|
+
|
|
121
|
+
// Element with both attributes and children
|
|
122
|
+
const fullDiv = Div({ class: 'card' }, [
|
|
123
|
+
'Content here'
|
|
124
|
+
]);
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
#### Reactive Attributes
|
|
128
|
+
```javascript
|
|
129
|
+
const isVisible = Observable(true);
|
|
130
|
+
const theme = Observable('dark');
|
|
131
|
+
|
|
132
|
+
const element = Div({
|
|
133
|
+
class: {
|
|
134
|
+
'visible': isVisible,
|
|
135
|
+
'dark-theme': theme.check(t => t === 'dark')
|
|
136
|
+
},
|
|
137
|
+
style: {
|
|
138
|
+
opacity: isVisible.check(v => v ? 1 : 0.5)
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
#### Event Handling
|
|
144
|
+
```javascript
|
|
145
|
+
const counter = Observable(0);
|
|
146
|
+
|
|
147
|
+
const button = Button('Click me')
|
|
148
|
+
.nd.on.click(() => {
|
|
149
|
+
counter.set(counter.val() + 1);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// Multiple events
|
|
153
|
+
const input = Input()
|
|
154
|
+
.nd.on.focus(e => console.log('Focused'))
|
|
155
|
+
.nd.on.blur(e => console.log('Blurred'))
|
|
156
|
+
.nd.on.input(e => console.log('Value:', e.target.value));
|
|
157
|
+
|
|
158
|
+
//Or
|
|
159
|
+
const input = Input()
|
|
160
|
+
.nd.on({
|
|
161
|
+
focus: e => console.log('Focused'),
|
|
162
|
+
blur: e => console.log('Blurred'),
|
|
163
|
+
input: e => console.log('Value:', e.target.value)
|
|
164
|
+
})
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### Lifecycle and Memory Management
|
|
168
|
+
|
|
169
|
+
NativeDocument includes automatic memory management to prevent memory leaks.
|
|
170
|
+
|
|
171
|
+
#### Element Lifecycle
|
|
172
|
+
```javascript
|
|
173
|
+
const element = Div('Content')
|
|
174
|
+
.nd.mounted(el => {
|
|
175
|
+
console.log('Element added to DOM');
|
|
176
|
+
})
|
|
177
|
+
.nd.unmounted(el => {
|
|
178
|
+
console.log('Element removed from DOM');
|
|
179
|
+
});
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
#### Manual Cleanup
|
|
183
|
+
For complex scenarios, you can manage cleanup manually:
|
|
184
|
+
|
|
185
|
+
```javascript
|
|
186
|
+
const observable = Observable(0);
|
|
187
|
+
|
|
188
|
+
// Manual subscription
|
|
189
|
+
const unsubscribe = observable.subscribe(value => {
|
|
190
|
+
console.log('Value:', value);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Clean up when needed
|
|
194
|
+
unsubscribe();
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Reactivity Model
|
|
198
|
+
|
|
199
|
+
### Data Flow
|
|
200
|
+
NativeDocument follows a unidirectional data flow:
|
|
201
|
+
|
|
202
|
+
1. **State Change**: An observable value is updated
|
|
203
|
+
2. **Notification**: All subscribers are notified
|
|
204
|
+
3. **DOM Update**: UI elements update automatically
|
|
205
|
+
4. **Event Handling**: User interactions trigger new state changes
|
|
206
|
+
|
|
207
|
+
```javascript
|
|
208
|
+
const items = Observable.array(['Apple', 'Banana']);
|
|
209
|
+
|
|
210
|
+
const list = ForEach(items, (item) =>
|
|
211
|
+
Div([
|
|
212
|
+
item,
|
|
213
|
+
Button('Remove').nd.on.click(() => {
|
|
214
|
+
// User action → State change → UI update
|
|
215
|
+
const index = items.val().indexOf(item);
|
|
216
|
+
items.splice(index, 1);
|
|
217
|
+
})
|
|
218
|
+
])
|
|
219
|
+
);
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Reactive Chains
|
|
223
|
+
Observables can depend on other observables, creating reactive chains:
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
const price = Observable(100);
|
|
227
|
+
const quantity = Observable(2);
|
|
228
|
+
const discount = Observable(0.1);
|
|
229
|
+
|
|
230
|
+
const subtotal = Observable.computed(() => {
|
|
231
|
+
return price.val() * quantity.val();
|
|
232
|
+
}, [price, quantity]);
|
|
233
|
+
|
|
234
|
+
const total = Observable.computed(() => {
|
|
235
|
+
return subtotal.val() * (1 - discount.val());
|
|
236
|
+
}, [subtotal, discount]);
|
|
237
|
+
|
|
238
|
+
// Changing any value updates the chain
|
|
239
|
+
price.set(150); // subtotal and total update automatically
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Component Patterns
|
|
243
|
+
|
|
244
|
+
### Functional Components
|
|
245
|
+
Create reusable components as functions:
|
|
246
|
+
|
|
247
|
+
```javascript
|
|
248
|
+
function UserCard(user) {
|
|
249
|
+
return Div({ class: 'user-card' }, [
|
|
250
|
+
Div({ class: 'name' }, user.name),
|
|
251
|
+
Div({ class: 'email' }, user.email),
|
|
252
|
+
Button('Edit').nd.on.click(() => {
|
|
253
|
+
// Handle edit
|
|
254
|
+
})
|
|
255
|
+
]);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Usage
|
|
259
|
+
const user = { name: 'John Doe', email: 'john@example.com' };
|
|
260
|
+
const card = UserCard(user);
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Stateful Components
|
|
264
|
+
Components with internal state:
|
|
265
|
+
|
|
266
|
+
```javascript
|
|
267
|
+
function Counter(initialValue = 0) {
|
|
268
|
+
const count = Observable(initialValue);
|
|
269
|
+
|
|
270
|
+
return Div({ class: 'counter' }, [
|
|
271
|
+
Div(['Count: ', count]),
|
|
272
|
+
Button('-').nd.on.click(() => count.set(count.val() - 1)),
|
|
273
|
+
Button('+').nd.on.click(() => count.set(count.val() + 1)),
|
|
274
|
+
Button('Reset').nd.on.click(() => count.set(initialValue))
|
|
275
|
+
]);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Usage
|
|
279
|
+
const myCounter = Counter(10);
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### Higher-Order Components
|
|
283
|
+
Components that enhance other components:
|
|
284
|
+
|
|
285
|
+
```javascript
|
|
286
|
+
function withLoading(component, isLoading) {
|
|
287
|
+
return When(isLoading.check(loading => !loading))
|
|
288
|
+
.show(component)
|
|
289
|
+
.otherwise(Div({ class: 'loading' }, 'Loading...'));
|
|
290
|
+
// Or
|
|
291
|
+
|
|
292
|
+
// return Switch(isLoading.check(loading => !loading),
|
|
293
|
+
// component,
|
|
294
|
+
// Div({ class: 'loading' }, 'Loading...')
|
|
295
|
+
// );
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// Usage
|
|
299
|
+
const isLoading = Observable(true);
|
|
300
|
+
const content = Div('Main content');
|
|
301
|
+
const wrappedContent = withLoading(content, isLoading);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## State Management Patterns
|
|
305
|
+
|
|
306
|
+
### Local State
|
|
307
|
+
For component-specific state, use observables directly:
|
|
308
|
+
|
|
309
|
+
```javascript
|
|
310
|
+
function TodoForm() {
|
|
311
|
+
const text = Observable('');
|
|
312
|
+
const isValid = Observable.computed(() => text.val().trim().length > 0, [text]);
|
|
313
|
+
|
|
314
|
+
return Div([
|
|
315
|
+
Input({ placeholder: 'Enter todo...', value: text }),
|
|
316
|
+
Button('Add')
|
|
317
|
+
.nd.on.click(() => {
|
|
318
|
+
if (isValid.val()) {
|
|
319
|
+
// Add todo logic
|
|
320
|
+
text.set('');
|
|
321
|
+
}
|
|
322
|
+
})
|
|
323
|
+
]);
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Shared State
|
|
328
|
+
For state shared between components, create a store:
|
|
329
|
+
|
|
330
|
+
```javascript
|
|
331
|
+
// Create a shared store
|
|
332
|
+
const TodoStore = {
|
|
333
|
+
todos: Observable.array([]),
|
|
334
|
+
|
|
335
|
+
addTodo(text) {
|
|
336
|
+
this.todos.push({
|
|
337
|
+
id: Date.now(),
|
|
338
|
+
text: text,
|
|
339
|
+
done: false
|
|
340
|
+
});
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
removeTodo(id) {
|
|
344
|
+
const index = this.todos.val().findIndex(todo => todo.id === id);
|
|
345
|
+
if (index !== -1) {
|
|
346
|
+
this.todos.splice(index, 1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
// Use in components
|
|
352
|
+
function TodoList() {
|
|
353
|
+
return ForEach(TodoStore.todos, (todo) =>
|
|
354
|
+
Div([
|
|
355
|
+
todo.text,
|
|
356
|
+
Button('Delete').nd.on.click(() => {
|
|
357
|
+
TodoStore.removeTodo(todo.id);
|
|
358
|
+
})
|
|
359
|
+
])
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
```
|
|
363
|
+
|
|
364
|
+
### Global State with Store
|
|
365
|
+
For complex applications, use the built-in Store:
|
|
366
|
+
|
|
367
|
+
```javascript
|
|
368
|
+
const { Store } = NativeDocument;
|
|
369
|
+
|
|
370
|
+
// Create global observables
|
|
371
|
+
const userStore = Store.create('user', { name: '', isLoggedIn: false });
|
|
372
|
+
const themeStore = Store.create('theme', 'light');
|
|
373
|
+
|
|
374
|
+
// Use in components
|
|
375
|
+
function Header() {
|
|
376
|
+
const user = Store.use('user');
|
|
377
|
+
const theme = Store.use('theme');
|
|
378
|
+
|
|
379
|
+
return Div({ class: `theme-${theme}` }, [
|
|
380
|
+
ShowIf(user.check(u => u.isLoggedIn),
|
|
381
|
+
Div(['Welcome, ', user.$value.name])
|
|
382
|
+
)
|
|
383
|
+
]);
|
|
384
|
+
}
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
## Error Handling
|
|
388
|
+
|
|
389
|
+
### Graceful Error Handling
|
|
390
|
+
Wrap potentially failing operations:
|
|
391
|
+
|
|
392
|
+
```javascript
|
|
393
|
+
function SafeComponent() {
|
|
394
|
+
try {
|
|
395
|
+
return riskyOperation();
|
|
396
|
+
} catch (error) {
|
|
397
|
+
console.error('Component error:', error);
|
|
398
|
+
return Div({ class: 'error' }, 'Something went wrong');
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
### Error Boundaries
|
|
404
|
+
Use error boundaries for robust applications:
|
|
405
|
+
|
|
406
|
+
```javascript
|
|
407
|
+
function withErrorBoundary(component) {
|
|
408
|
+
return component.errorBoundary((error) => {
|
|
409
|
+
console.error('Error caught:', error);
|
|
410
|
+
return Div({ class: 'error-boundary' }, [
|
|
411
|
+
'An error occurred. Please try again.'
|
|
412
|
+
]);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
## Performance Considerations
|
|
418
|
+
|
|
419
|
+
### Efficient Updates
|
|
420
|
+
NativeDocument optimizes updates automatically, but you can help:
|
|
421
|
+
|
|
422
|
+
```javascript
|
|
423
|
+
// Good: Batch related updates
|
|
424
|
+
function updateUser(newData) {
|
|
425
|
+
user.set({ ...user.val(), ...newData });
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
// Less efficient: Multiple separate updates
|
|
429
|
+
function updateUserSeparately(name, email) {
|
|
430
|
+
user.set({ ...user.val(), name });
|
|
431
|
+
user.set({ ...user.val(), email });
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### List Rendering
|
|
436
|
+
Use key functions for efficient list updates:
|
|
437
|
+
|
|
438
|
+
```javascript
|
|
439
|
+
ForEach(items, (item) =>
|
|
440
|
+
Div(['Item: ', item.name]),
|
|
441
|
+
// Key function for efficient updates
|
|
442
|
+
(item) => item.id
|
|
443
|
+
);
|
|
444
|
+
// or
|
|
445
|
+
ForEach(items, (item) =>
|
|
446
|
+
Div(['Item: ', item.name]),
|
|
447
|
+
// Key property for efficient updates
|
|
448
|
+
'id'
|
|
449
|
+
);
|
|
450
|
+
```
|
|
451
|
+
|
|
452
|
+
## Best Practices
|
|
453
|
+
|
|
454
|
+
### 1. Keep Components Small and Focused
|
|
455
|
+
```javascript
|
|
456
|
+
// Good: Focused component
|
|
457
|
+
function UserName(user) {
|
|
458
|
+
return Div({ class: 'user-name' }, user.name);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
// Less ideal: Component doing too much
|
|
462
|
+
function UserEverything(user) {
|
|
463
|
+
// Handles name, email, avatar, settings, etc.
|
|
464
|
+
}
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### 2. Use Computed Values for Derived State
|
|
468
|
+
```javascript
|
|
469
|
+
// Good: Computed value
|
|
470
|
+
const filteredItems = Observable.computed(() => {
|
|
471
|
+
return items.val().filter(item => item.visible);
|
|
472
|
+
}, [items]);
|
|
473
|
+
|
|
474
|
+
// Less efficient: Manual filtering on each render
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
### 3. Separate Concerns
|
|
478
|
+
```javascript
|
|
479
|
+
// Good: Separate data logic from UI
|
|
480
|
+
const UserService = {
|
|
481
|
+
async loadUser(id) {
|
|
482
|
+
// Data loading logic
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
|
|
486
|
+
function UserProfile(userId) {
|
|
487
|
+
// UI rendering logic
|
|
488
|
+
}
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
### 4. Use Meaningful Names
|
|
492
|
+
```javascript
|
|
493
|
+
// Good: Clear naming
|
|
494
|
+
const isUserLoggedIn = Observable(false);
|
|
495
|
+
const currentUserName = Observable('');
|
|
496
|
+
|
|
497
|
+
// Less clear
|
|
498
|
+
const flag = Observable(false);
|
|
499
|
+
const data = Observable('');
|
|
500
|
+
```
|
|
501
|
+
|
|
502
|
+
## Next Steps
|
|
503
|
+
|
|
504
|
+
Now that you understand NativeDocument's core concepts, explore these advanced topics:
|
|
505
|
+
|
|
506
|
+
- **[Observables](docs/observables.md)** - Reactive state management
|
|
507
|
+
- **[Elements](docs/elements.md)** - Creating and composing UI
|
|
508
|
+
- **[Conditional Rendering](docs/conditional-rendering.md)** - Dynamic content
|
|
509
|
+
- **[Routing](docs/routing.md)** - Navigation and URL management
|
|
510
|
+
- **[State Management](docs/state-management.md)** - Global state patterns
|
|
511
|
+
- **[Lifecycle Events](docs/lifecycle-events.md)** - Lifecycle events
|
|
512
|
+
- **[Memory Management](docs/memory-management.md)** - Memory management
|
|
513
|
+
- **[Anchor](docs/anchor.md)** - Anchor
|