eleva 1.1.0-alpha → 1.2.1-alpha
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/README.md +53 -29
- package/dist/eleva.d.ts +42 -81
- package/dist/eleva.esm.js +52 -13
- package/dist/eleva.esm.js.map +1 -1
- package/dist/eleva.min.js +1 -1
- package/dist/eleva.min.js.map +1 -1
- package/dist/eleva.umd.js +52 -13
- package/dist/eleva.umd.js.map +1 -1
- package/package.json +3 -2
- package/src/core/Eleva.js +47 -12
- package/src/modules/Emitter.js +1 -1
- package/src/modules/Signal.js +2 -0
- package/types/core/Eleva.d.ts +42 -19
- package/types/core/Eleva.d.ts.map +1 -1
- package/types/modules/Emitter.d.ts +1 -1
- package/types/modules/Emitter.d.ts.map +1 -1
- package/types/modules/Signal.d.ts +4 -2
- package/types/modules/Signal.d.ts.map +1 -1
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
# Eleva
|
|
1
|
+
# Eleva 🚀
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
_Built with love for native JavaScript—because sometimes, less really is more!_ 😊
|
|
3
|
+
Pure JavaScript, Pure Performance, Simply Elegant.
|
|
5
4
|
|
|
6
5
|
[](https://opensource.org/licenses/MIT)
|
|
7
6
|
[](https://www.npmjs.com/package/eleva)
|
|
@@ -10,12 +9,25 @@ _Built with love for native JavaScript—because sometimes, less really is more!
|
|
|
10
9
|
[](https://bundlephobia.com/package/eleva@latest)
|
|
11
10
|
[](https://bundlephobia.com/package/eleva@latest)
|
|
12
11
|
|
|
12
|
+
<br>
|
|
13
|
+
<br>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<img src="./docs/imgs/Eleva Logo.png" alt="Eleva Logo" width="50%">
|
|
17
|
+
</p>
|
|
18
|
+
|
|
19
|
+
<br>
|
|
20
|
+
<br>
|
|
21
|
+
|
|
22
|
+
**A minimalist, lightweight, pure vanilla JavaScript frontend runtime framework.**
|
|
23
|
+
_Built with love for native JavaScript—because sometimes, less really is more!_ 😊
|
|
24
|
+
|
|
13
25
|
<!-- [](https://www.jsdelivr.com/package/npm/eleva) -->
|
|
14
26
|
|
|
15
|
-
> **Stability Notice**: This is `v1.
|
|
27
|
+
> **Stability Notice**: This is `v1.2.0-alpha` - APIs may change significantly until the stable release.
|
|
16
28
|
> Not recommended for production use yet. Follow the [versioning guide](#version-guide) for updates.
|
|
17
29
|
|
|
18
|
-
**Version:** `1.
|
|
30
|
+
**Version:** `1.2.0-alpha`
|
|
19
31
|
|
|
20
32
|
Welcome to Eleva! This is my humble, experimental playground for a fresh approach to frontend development. Eleva was born out of my genuine passion for pure vanilla JavaScript—no frameworks, no bloat, just the power of native code. I hope you'll have fun exploring, testing, and contributing to make Eleva even better. 🚀
|
|
21
33
|
|
|
@@ -23,7 +35,7 @@ Welcome to Eleva! This is my humble, experimental playground for a fresh approac
|
|
|
23
35
|
|
|
24
36
|
## Table of Contents
|
|
25
37
|
|
|
26
|
-
- [Eleva](#eleva)
|
|
38
|
+
- [Eleva 🚀](#eleva-)
|
|
27
39
|
- [Table of Contents](#table-of-contents)
|
|
28
40
|
- [Introduction](#introduction)
|
|
29
41
|
- [Design Philosophy](#design-philosophy)
|
|
@@ -127,9 +139,9 @@ Eleva is ideal for developers seeking a lightweight, flexible, and high-performa
|
|
|
127
139
|
|
|
128
140
|
I believe in clear versioning that reflects the maturity of the project:
|
|
129
141
|
|
|
130
|
-
- **Pre-release Versions (Alpha/Beta):** Early versions like `1.
|
|
142
|
+
- **Pre-release Versions (Alpha/Beta):** Early versions like `1.2.0-alpha` indicate the API is still evolving. Expect frequent updates and share your feedback!
|
|
131
143
|
- **Semantic Versioning:** Once stable, I’ll follow semantic versioning strictly to clearly communicate any breaking changes.
|
|
132
|
-
- **Fresh Start:** This release (`1.
|
|
144
|
+
- **Fresh Start:** This release (`1.2.0-alpha`) marks a significant update with enhanced inline documentation, improved JSDoc annotations, and a refined mounting context that now includes an `emitter` property.
|
|
133
145
|
|
|
134
146
|
---
|
|
135
147
|
|
|
@@ -138,9 +150,9 @@ I believe in clear versioning that reflects the maturity of the project:
|
|
|
138
150
|
I follow [Semantic Versioning (SemVer)](https://semver.org/):
|
|
139
151
|
|
|
140
152
|
- **🔢 Major Version:** Breaking changes or major overhauls (e.g., from `1.0.0` to `2.0.0`).
|
|
141
|
-
- **🔢 Minor Version:** New features in a backward-compatible manner (e.g., from `1.
|
|
153
|
+
- **🔢 Minor Version:** New features in a backward-compatible manner (e.g., from `1.1.0` to `1.2.0`).
|
|
142
154
|
- **🔢 Patch Version:** Backward-compatible bug fixes and minor improvements (e.g., `1.0.1`).
|
|
143
|
-
- **📌 Pre-release Identifiers:** Suffixes like `-alpha`, `-beta`, or `-rc` denote unstable releases (e.g., `1.
|
|
155
|
+
- **📌 Pre-release Identifiers:** Suffixes like `-alpha`, `-beta`, or `-rc` denote unstable releases (e.g., `1.2.0-alpha`).
|
|
144
156
|
|
|
145
157
|
---
|
|
146
158
|
|
|
@@ -148,7 +160,7 @@ I follow [Semantic Versioning (SemVer)](https://semver.org/):
|
|
|
148
160
|
|
|
149
161
|
Eleva is crafted for performance:
|
|
150
162
|
|
|
151
|
-
- **Lightweight:** Approximately ~4 KB minified and ~1.
|
|
163
|
+
- **Lightweight:** Approximately ~4 KB minified and ~1.8 KB gzipped.
|
|
152
164
|
- **Efficient Reactivity:** Signal-based updates ensure only necessary DOM parts are updated.
|
|
153
165
|
- **Optimized Diffing:** Renderer efficiently patches changes without the overhead of a virtual DOM.
|
|
154
166
|
- **No Bloat:** Pure vanilla JavaScript with zero dependencies keeps your project nimble.
|
|
@@ -159,14 +171,16 @@ Eleva is crafted for performance:
|
|
|
159
171
|
|
|
160
172
|
Preliminary benchmarks illustrate Eleva’s efficiency compared to popular frameworks:
|
|
161
173
|
|
|
162
|
-
| Framework
|
|
163
|
-
|
|
|
164
|
-
| **Eleva** |
|
|
165
|
-
| React
|
|
166
|
-
| Vue
|
|
167
|
-
| Angular
|
|
174
|
+
| **Framework** | **Bundle Size** (KB) | **Initial Load Time** (ms) | **DOM Update Speed** (s) | **Peak Memory Usage** (KB) | **Overall Performance Score** (lower is better) |
|
|
175
|
+
| ----------------------------- | -------------------- | -------------------------- | ------------------------ | -------------------------- | ----------------------------------------------- |
|
|
176
|
+
| **Eleva** (Direct DOM) | **1.8** | **10** | **0.018** | **0.25** | **3.02 (Best)** |
|
|
177
|
+
| **React** (Virtual DOM) | 42 | 40 | 0.020 | 0.25 | 20.57 |
|
|
178
|
+
| **Vue** (Reactive State) | 33 | 35 | 0.021 | 3.10 | 17.78 |
|
|
179
|
+
| **Angular** (Two-way Binding) | 80 | 100 | 0.021 | 0.25 | 45.07 (Slowest) |
|
|
168
180
|
|
|
169
|
-
|
|
181
|
+
Detailed [Benchmark Metrics Report](BENCHMARK.md)
|
|
182
|
+
|
|
183
|
+
> ⚠️ **Disclaimer:** Benchmarks are based on internal tests and may vary by project and environment.
|
|
170
184
|
|
|
171
185
|
---
|
|
172
186
|
|
|
@@ -226,8 +240,8 @@ app.component("HelloWorld", {
|
|
|
226
240
|
template: ({ count }) => `
|
|
227
241
|
<div>
|
|
228
242
|
<h1>Hello, Eleva! 👋</h1>
|
|
229
|
-
<p>Count: ${count}</p>
|
|
230
|
-
<button @click="() => count++">Increment</button>
|
|
243
|
+
<p>Count: ${count.value}</p>
|
|
244
|
+
<button @click="() => count.value++">Increment</button>
|
|
231
245
|
</div>
|
|
232
246
|
`,
|
|
233
247
|
});
|
|
@@ -236,6 +250,8 @@ app.component("HelloWorld", {
|
|
|
236
250
|
app.mount(document.getElementById("app"), "HelloWorld");
|
|
237
251
|
```
|
|
238
252
|
|
|
253
|
+
Interactive Demo: [CodePen](https://codepen.io/tarekraafat/pen/GgRrxdY?editors=1010)
|
|
254
|
+
|
|
239
255
|
### UMD Example
|
|
240
256
|
|
|
241
257
|
Include Eleva via a script tag and use the global variable:
|
|
@@ -249,7 +265,7 @@ Include Eleva via a script tag and use the global variable:
|
|
|
249
265
|
</head>
|
|
250
266
|
<body>
|
|
251
267
|
<div id="app"></div>
|
|
252
|
-
<script src="https://
|
|
268
|
+
<script src="https://cdn.jsdelivr.net/npm/eleva/dist/eleva.min.js"></script>
|
|
253
269
|
<script>
|
|
254
270
|
const app = new Eleva("MyApp");
|
|
255
271
|
app.component("HelloWorld", {
|
|
@@ -260,8 +276,8 @@ Include Eleva via a script tag and use the global variable:
|
|
|
260
276
|
template: ({ count }) => `
|
|
261
277
|
<div>
|
|
262
278
|
<h1>Hello, Eleva! 👋</h1>
|
|
263
|
-
<p>Count: ${count}</p>
|
|
264
|
-
<button @click="() => count++">Increment</button>
|
|
279
|
+
<p>Count: ${count.value}</p>
|
|
280
|
+
<button @click="() => count.value++">Increment</button>
|
|
265
281
|
</div>
|
|
266
282
|
`,
|
|
267
283
|
});
|
|
@@ -271,6 +287,8 @@ Include Eleva via a script tag and use the global variable:
|
|
|
271
287
|
</html>
|
|
272
288
|
```
|
|
273
289
|
|
|
290
|
+
Interactive Demo: [CodePen](https://codepen.io/tarekraafat/pen/jEOyzYN?editors=1010)
|
|
291
|
+
|
|
274
292
|
---
|
|
275
293
|
|
|
276
294
|
## API Reference
|
|
@@ -303,11 +321,11 @@ Include Eleva via a script tag and use the global variable:
|
|
|
303
321
|
### Renderer
|
|
304
322
|
|
|
305
323
|
- **`patchDOM(container, newHtml)`**
|
|
306
|
-
Efficiently
|
|
324
|
+
Efficiently updates the DOM.
|
|
307
325
|
- **`diff(oldParent, newParent)`**
|
|
308
|
-
|
|
326
|
+
Compares and updates DOM trees.
|
|
309
327
|
- **`updateAttributes(oldEl, newEl)`**
|
|
310
|
-
|
|
328
|
+
Synchronizes element attributes.
|
|
311
329
|
|
|
312
330
|
### Eleva (Core)
|
|
313
331
|
|
|
@@ -319,7 +337,7 @@ Include Eleva via a script tag and use the global variable:
|
|
|
319
337
|
Register a component.
|
|
320
338
|
- **`.mount(container, compName, props)`**
|
|
321
339
|
Mount a component to the DOM.
|
|
322
|
-
_Note:_
|
|
340
|
+
_Note:_ The mounting context now includes an `emitter` property (the full event emitter instance) for simplified event handling. Use `context.emitter.on(...)` and `context.emitter.emit(...)` for event management.
|
|
323
341
|
|
|
324
342
|
For detailed API documentation, please check the [docs](docs/index.md) folder.
|
|
325
343
|
|
|
@@ -348,7 +366,7 @@ I welcome developers to dive in and experiment with Eleva! Here’s how to get s
|
|
|
348
366
|
npm run dev
|
|
349
367
|
```
|
|
350
368
|
|
|
351
|
-
4. **Build for Production:**
|
|
369
|
+
4. **Build for Production without TypeScript Declarations:**
|
|
352
370
|
|
|
353
371
|
```bash
|
|
354
372
|
npm run build
|
|
@@ -361,6 +379,12 @@ I welcome developers to dive in and experiment with Eleva! Here’s how to get s
|
|
|
361
379
|
npm run build:types:bundle
|
|
362
380
|
```
|
|
363
381
|
|
|
382
|
+
6. **Build for Production with TypeScript Declarations:**
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm run build:all
|
|
386
|
+
```
|
|
387
|
+
|
|
364
388
|
---
|
|
365
389
|
|
|
366
390
|
## Testing
|
|
@@ -405,5 +429,5 @@ Eleva is open-source and available under the [MIT License](LICENSE).
|
|
|
405
429
|
|
|
406
430
|
[Documentation](/docs/index.md) |
|
|
407
431
|
[Examples](/examples) |
|
|
408
|
-
[Changelog](/
|
|
432
|
+
[Changelog](/CHANGELOG.md) |
|
|
409
433
|
[GitHub Discussions](https://github.com/TarekRaafat/eleva/discussions)
|
package/dist/eleva.d.ts
CHANGED
|
@@ -1,77 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
* @classdesc Robust inter-component communication with event bubbling.
|
|
4
|
-
* Implements a basic publish-subscribe pattern for event handling, allowing components
|
|
5
|
-
* to communicate through custom events.
|
|
6
|
-
*/
|
|
7
|
-
declare class Emitter {
|
|
8
|
-
/** @type {Object.<string, Function[]>} */
|
|
9
|
-
events: {
|
|
10
|
-
[x: string]: Function[];
|
|
11
|
-
};
|
|
12
|
-
/**
|
|
13
|
-
* Registers an event handler for the specified event.
|
|
14
|
-
*
|
|
15
|
-
* @param {string} event - The name of the event.
|
|
16
|
-
* @param {function(...any): void} handler - The function to call when the event is emitted.
|
|
17
|
-
*/
|
|
18
|
-
on(event: string, handler: (...args: any[]) => void): void;
|
|
19
|
-
/**
|
|
20
|
-
* Removes a previously registered event handler.
|
|
21
|
-
*
|
|
22
|
-
* @param {string} event - The name of the event.
|
|
23
|
-
* @param {function(...any): void} handler - The handler function to remove.
|
|
24
|
-
*/
|
|
25
|
-
off(event: string, handler: (...args: any[]) => void): void;
|
|
26
|
-
/**
|
|
27
|
-
* Emits an event, invoking all handlers registered for that event.
|
|
28
|
-
*
|
|
29
|
-
* @param {string} event - The event name.
|
|
30
|
-
* @param {...any} args - Additional arguments to pass to the event handlers.
|
|
31
|
-
*/
|
|
32
|
-
emit(event: string, ...args: any[]): void;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* @class 🎨 Renderer
|
|
37
|
-
* @classdesc Handles DOM patching, diffing, and attribute updates.
|
|
38
|
-
* Provides methods for efficient DOM updates by diffing the new and old DOM structures
|
|
39
|
-
* and applying only the necessary changes.
|
|
40
|
-
*/
|
|
41
|
-
declare class Renderer {
|
|
42
|
-
/**
|
|
43
|
-
* Patches the DOM of a container element with new HTML content.
|
|
44
|
-
*
|
|
45
|
-
* @param {HTMLElement} container - The container element to patch.
|
|
46
|
-
* @param {string} newHtml - The new HTML content to apply.
|
|
47
|
-
*/
|
|
48
|
-
patchDOM(container: HTMLElement, newHtml: string): void;
|
|
49
|
-
/**
|
|
50
|
-
* Diffs two DOM trees (old and new) and applies updates to the old DOM.
|
|
51
|
-
*
|
|
52
|
-
* @param {HTMLElement} oldParent - The original DOM element.
|
|
53
|
-
* @param {HTMLElement} newParent - The new DOM element.
|
|
54
|
-
*/
|
|
55
|
-
diff(oldParent: HTMLElement, newParent: HTMLElement): void;
|
|
56
|
-
/**
|
|
57
|
-
* Updates the attributes of an element to match those of a new element.
|
|
58
|
-
*
|
|
59
|
-
* @param {HTMLElement} oldEl - The element to update.
|
|
60
|
-
* @param {HTMLElement} newEl - The element providing the updated attributes.
|
|
61
|
-
*/
|
|
62
|
-
updateAttributes(oldEl: HTMLElement, newEl: HTMLElement): void;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
/**
|
|
2
|
+
* Defines the structure and behavior of a component.
|
|
66
3
|
* @typedef {Object} ComponentDefinition
|
|
67
4
|
* @property {function(Object<string, any>): (Object<string, any>|Promise<Object<string, any>>)} [setup]
|
|
68
|
-
*
|
|
5
|
+
* Optional setup function that initializes the component's reactive state and lifecycle.
|
|
6
|
+
* Receives props and context as an argument and should return an object containing the component's state.
|
|
7
|
+
* Can return either a synchronous object or a Promise that resolves to an object for async initialization.
|
|
8
|
+
*
|
|
69
9
|
* @property {function(Object<string, any>): string} template
|
|
70
|
-
*
|
|
10
|
+
* Required function that defines the component's HTML structure.
|
|
11
|
+
* Receives the merged context (props + setup data) and must return an HTML template string.
|
|
12
|
+
* Supports dynamic expressions using {{ }} syntax for reactive data binding.
|
|
13
|
+
*
|
|
71
14
|
* @property {function(Object<string, any>): string} [style]
|
|
72
|
-
*
|
|
15
|
+
* Optional function that defines component-scoped CSS styles.
|
|
16
|
+
* Receives the merged context and returns a CSS string that will be automatically scoped to the component.
|
|
17
|
+
* Styles are injected into the component's container and only affect elements within it.
|
|
18
|
+
*
|
|
73
19
|
* @property {Object<string, ComponentDefinition>} [children]
|
|
74
|
-
*
|
|
20
|
+
* Optional object that defines nested child components.
|
|
21
|
+
* Keys are CSS selectors that match elements in the template where child components should be mounted.
|
|
22
|
+
* Values are ComponentDefinition objects that define the structure and behavior of each child component.
|
|
75
23
|
*/
|
|
76
24
|
/**
|
|
77
25
|
* @class 🧩 Eleva
|
|
@@ -88,24 +36,26 @@ declare class Eleva {
|
|
|
88
36
|
constructor(name: string, config?: {
|
|
89
37
|
[x: string]: any;
|
|
90
38
|
});
|
|
91
|
-
/** @type {string} */
|
|
39
|
+
/** @type {string} The unique identifier name for this Eleva instance */
|
|
92
40
|
name: string;
|
|
93
|
-
/** @type {Object<string, any>} */
|
|
41
|
+
/** @type {Object<string, any>} Optional configuration object for the Eleva instance */
|
|
94
42
|
config: {
|
|
95
43
|
[x: string]: any;
|
|
96
44
|
};
|
|
97
|
-
/** @type {Object<string, ComponentDefinition>} */
|
|
45
|
+
/** @type {Object<string, ComponentDefinition>} Object storing registered component definitions by name */
|
|
98
46
|
_components: {
|
|
99
47
|
[x: string]: ComponentDefinition;
|
|
100
48
|
};
|
|
101
|
-
/** @
|
|
102
|
-
_plugins
|
|
103
|
-
/** @private */
|
|
49
|
+
/** @private {Array<Object>} Collection of installed plugin instances */
|
|
50
|
+
private _plugins;
|
|
51
|
+
/** @private {string[]} Array of lifecycle hook names supported by the component */
|
|
104
52
|
private _lifecycleHooks;
|
|
105
|
-
/** @private {boolean} */
|
|
53
|
+
/** @private {boolean} Flag indicating if component is currently mounted */
|
|
106
54
|
private _isMounted;
|
|
107
|
-
emitter
|
|
108
|
-
|
|
55
|
+
/** @private {Emitter} Instance of the event emitter for handling component events */
|
|
56
|
+
private emitter;
|
|
57
|
+
/** @private {Renderer} Instance of the renderer for handling DOM updates and patching */
|
|
58
|
+
private renderer;
|
|
109
59
|
/**
|
|
110
60
|
* Integrates a plugin with the Eleva framework.
|
|
111
61
|
*
|
|
@@ -171,9 +121,14 @@ declare class Eleva {
|
|
|
171
121
|
*/
|
|
172
122
|
private _mountChildren;
|
|
173
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Defines the structure and behavior of a component.
|
|
126
|
+
*/
|
|
174
127
|
type ComponentDefinition = {
|
|
175
128
|
/**
|
|
176
|
-
*
|
|
129
|
+
* Optional setup function that initializes the component's reactive state and lifecycle.
|
|
130
|
+
* Receives props and context as an argument and should return an object containing the component's state.
|
|
131
|
+
* Can return either a synchronous object or a Promise that resolves to an object for async initialization.
|
|
177
132
|
*/
|
|
178
133
|
setup?: ((arg0: {
|
|
179
134
|
[x: string]: any;
|
|
@@ -183,19 +138,25 @@ type ComponentDefinition = {
|
|
|
183
138
|
[x: string]: any;
|
|
184
139
|
}>)) | undefined;
|
|
185
140
|
/**
|
|
186
|
-
*
|
|
141
|
+
* Required function that defines the component's HTML structure.
|
|
142
|
+
* Receives the merged context (props + setup data) and must return an HTML template string.
|
|
143
|
+
* Supports dynamic expressions using {{ }} syntax for reactive data binding.
|
|
187
144
|
*/
|
|
188
145
|
template: (arg0: {
|
|
189
146
|
[x: string]: any;
|
|
190
147
|
}) => string;
|
|
191
148
|
/**
|
|
192
|
-
*
|
|
149
|
+
* Optional function that defines component-scoped CSS styles.
|
|
150
|
+
* Receives the merged context and returns a CSS string that will be automatically scoped to the component.
|
|
151
|
+
* Styles are injected into the component's container and only affect elements within it.
|
|
193
152
|
*/
|
|
194
153
|
style?: ((arg0: {
|
|
195
154
|
[x: string]: any;
|
|
196
155
|
}) => string) | undefined;
|
|
197
156
|
/**
|
|
198
|
-
*
|
|
157
|
+
* Optional object that defines nested child components.
|
|
158
|
+
* Keys are CSS selectors that match elements in the template where child components should be mounted.
|
|
159
|
+
* Values are ComponentDefinition objects that define the structure and behavior of each child component.
|
|
199
160
|
*/
|
|
200
161
|
children?: {
|
|
201
162
|
[x: string]: ComponentDefinition;
|
package/dist/eleva.esm.js
CHANGED
|
@@ -56,7 +56,9 @@ class Signal {
|
|
|
56
56
|
* @param {*} value - The initial value of the signal.
|
|
57
57
|
*/
|
|
58
58
|
constructor(value) {
|
|
59
|
+
/** @private {*} Internal storage for the signal's current value */
|
|
59
60
|
this._value = value;
|
|
61
|
+
/** @private {Set<function>} Collection of callback functions to be notified when value changes */
|
|
60
62
|
this._watchers = new Set();
|
|
61
63
|
}
|
|
62
64
|
|
|
@@ -104,7 +106,7 @@ class Emitter {
|
|
|
104
106
|
* Creates a new Emitter instance.
|
|
105
107
|
*/
|
|
106
108
|
constructor() {
|
|
107
|
-
/** @type {Object.<string, Function[]>} */
|
|
109
|
+
/** @type {Object.<string, Function[]>} Storage for event handlers mapped by event name */
|
|
108
110
|
this.events = {};
|
|
109
111
|
}
|
|
110
112
|
|
|
@@ -254,15 +256,27 @@ class Renderer {
|
|
|
254
256
|
}
|
|
255
257
|
|
|
256
258
|
/**
|
|
259
|
+
* Defines the structure and behavior of a component.
|
|
257
260
|
* @typedef {Object} ComponentDefinition
|
|
258
261
|
* @property {function(Object<string, any>): (Object<string, any>|Promise<Object<string, any>>)} [setup]
|
|
259
|
-
*
|
|
262
|
+
* Optional setup function that initializes the component's reactive state and lifecycle.
|
|
263
|
+
* Receives props and context as an argument and should return an object containing the component's state.
|
|
264
|
+
* Can return either a synchronous object or a Promise that resolves to an object for async initialization.
|
|
265
|
+
*
|
|
260
266
|
* @property {function(Object<string, any>): string} template
|
|
261
|
-
*
|
|
267
|
+
* Required function that defines the component's HTML structure.
|
|
268
|
+
* Receives the merged context (props + setup data) and must return an HTML template string.
|
|
269
|
+
* Supports dynamic expressions using {{ }} syntax for reactive data binding.
|
|
270
|
+
*
|
|
262
271
|
* @property {function(Object<string, any>): string} [style]
|
|
263
|
-
*
|
|
272
|
+
* Optional function that defines component-scoped CSS styles.
|
|
273
|
+
* Receives the merged context and returns a CSS string that will be automatically scoped to the component.
|
|
274
|
+
* Styles are injected into the component's container and only affect elements within it.
|
|
275
|
+
*
|
|
264
276
|
* @property {Object<string, ComponentDefinition>} [children]
|
|
265
|
-
*
|
|
277
|
+
* Optional object that defines nested child components.
|
|
278
|
+
* Keys are CSS selectors that match elements in the template where child components should be mounted.
|
|
279
|
+
* Values are ComponentDefinition objects that define the structure and behavior of each child component.
|
|
266
280
|
*/
|
|
267
281
|
|
|
268
282
|
/**
|
|
@@ -278,19 +292,21 @@ class Eleva {
|
|
|
278
292
|
* @param {Object<string, any>} [config={}] - Optional configuration for the instance.
|
|
279
293
|
*/
|
|
280
294
|
constructor(name, config = {}) {
|
|
281
|
-
/** @type {string} */
|
|
295
|
+
/** @type {string} The unique identifier name for this Eleva instance */
|
|
282
296
|
this.name = name;
|
|
283
|
-
/** @type {Object<string, any>} */
|
|
297
|
+
/** @type {Object<string, any>} Optional configuration object for the Eleva instance */
|
|
284
298
|
this.config = config;
|
|
285
|
-
/** @type {Object<string, ComponentDefinition>} */
|
|
299
|
+
/** @type {Object<string, ComponentDefinition>} Object storing registered component definitions by name */
|
|
286
300
|
this._components = {};
|
|
287
|
-
/** @
|
|
301
|
+
/** @private {Array<Object>} Collection of installed plugin instances */
|
|
288
302
|
this._plugins = [];
|
|
289
|
-
/** @private */
|
|
303
|
+
/** @private {string[]} Array of lifecycle hook names supported by the component */
|
|
290
304
|
this._lifecycleHooks = ["onBeforeMount", "onMount", "onBeforeUpdate", "onUpdate", "onUnmount"];
|
|
291
|
-
/** @private {boolean} */
|
|
305
|
+
/** @private {boolean} Flag indicating if component is currently mounted */
|
|
292
306
|
this._isMounted = false;
|
|
307
|
+
/** @private {Emitter} Instance of the event emitter for handling component events */
|
|
293
308
|
this.emitter = new Emitter();
|
|
309
|
+
/** @private {Renderer} Instance of the renderer for handling DOM updates and patching */
|
|
294
310
|
this.renderer = new Renderer();
|
|
295
311
|
}
|
|
296
312
|
|
|
@@ -341,16 +357,33 @@ class Eleva {
|
|
|
341
357
|
} else {
|
|
342
358
|
throw new Error("Invalid component parameter.");
|
|
343
359
|
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Destructure the component definition to access core functionality.
|
|
363
|
+
* - setup: Optional function for component initialization and state management
|
|
364
|
+
* - template: Required function that returns the component's HTML structure
|
|
365
|
+
* - style: Optional function for component-scoped CSS styles
|
|
366
|
+
* - children: Optional object defining nested child components
|
|
367
|
+
*/
|
|
344
368
|
const {
|
|
345
369
|
setup,
|
|
346
370
|
template,
|
|
347
371
|
style,
|
|
348
372
|
children
|
|
349
373
|
} = definition;
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Creates the initial context object for the component instance.
|
|
377
|
+
* This context provides core functionality and will be merged with setup data.
|
|
378
|
+
* @type {Object<string, any>}
|
|
379
|
+
* @property {Object<string, any>} props - Component properties passed during mounting
|
|
380
|
+
* @property {Emitter} emitter - Event emitter instance for component event handling
|
|
381
|
+
* @property {function(any): Signal} signal - Factory function to create reactive Signal instances
|
|
382
|
+
* @property {Object<string, function(): void>} ...lifecycleHooks - Prepared lifecycle hook functions
|
|
383
|
+
*/
|
|
350
384
|
const context = {
|
|
351
385
|
props,
|
|
352
|
-
|
|
353
|
-
on: this.emitter.on.bind(this.emitter),
|
|
386
|
+
emitter: this.emitter,
|
|
354
387
|
signal: v => new Signal(v),
|
|
355
388
|
...this._prepareLifecycleHooks()
|
|
356
389
|
};
|
|
@@ -391,6 +424,12 @@ class Eleva {
|
|
|
391
424
|
mergedContext.onUpdate && mergedContext.onUpdate();
|
|
392
425
|
}
|
|
393
426
|
};
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Sets up reactive watchers for all Signal instances in the component's data.
|
|
430
|
+
* When a Signal's value changes, the component will re-render to reflect the updates.
|
|
431
|
+
* Stores unsubscribe functions to clean up watchers when component unmounts.
|
|
432
|
+
*/
|
|
394
433
|
Object.values(data).forEach(val => {
|
|
395
434
|
if (val instanceof Signal) watcherUnsubscribers.push(val.watch(render));
|
|
396
435
|
});
|