eleva 1.0.0-rc.13 → 1.0.0-rc.14
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 +20 -75
- package/dist/eleva-plugins.cjs.js +4 -653
- package/dist/eleva-plugins.cjs.js.map +1 -1
- package/dist/eleva-plugins.esm.js +5 -653
- package/dist/eleva-plugins.esm.js.map +1 -1
- package/dist/eleva-plugins.umd.js +4 -653
- package/dist/eleva-plugins.umd.js.map +1 -1
- package/dist/eleva-plugins.umd.min.js +1 -1
- package/dist/eleva-plugins.umd.min.js.map +1 -1
- package/dist/eleva.cjs.js +52 -110
- package/dist/eleva.cjs.js.map +1 -1
- package/dist/eleva.d.ts +47 -109
- package/dist/eleva.esm.js +52 -110
- package/dist/eleva.esm.js.map +1 -1
- package/dist/eleva.umd.js +52 -110
- package/dist/eleva.umd.js.map +1 -1
- package/dist/eleva.umd.min.js +1 -1
- package/dist/eleva.umd.min.js.map +1 -1
- package/dist/plugins/attr.umd.js +2 -2
- package/dist/plugins/attr.umd.js.map +1 -1
- package/dist/plugins/attr.umd.min.js +1 -1
- package/dist/plugins/attr.umd.min.js.map +1 -1
- package/dist/plugins/router.umd.js +1 -1
- package/dist/plugins/router.umd.js.map +1 -1
- package/dist/plugins/router.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/core/Eleva.js +21 -15
- package/src/modules/TemplateEngine.js +36 -104
- package/src/plugins/Attr.js +2 -2
- package/src/plugins/Router.js +1 -1
- package/src/plugins/index.js +1 -1
- package/types/core/Eleva.d.ts +9 -5
- package/types/core/Eleva.d.ts.map +1 -1
- package/types/modules/TemplateEngine.d.ts +38 -104
- package/types/modules/TemplateEngine.d.ts.map +1 -1
- package/types/plugins/Router.d.ts +1 -1
- package/types/plugins/index.d.ts +0 -1
- package/dist/plugins/props.umd.js +0 -660
- package/dist/plugins/props.umd.js.map +0 -1
- package/dist/plugins/props.umd.min.js +0 -2
- package/dist/plugins/props.umd.min.js.map +0 -1
- package/src/plugins/Props.js +0 -602
- package/types/plugins/Props.d.ts +0 -49
- package/types/plugins/Props.d.ts.map +0 -1
package/dist/eleva.esm.js
CHANGED
|
@@ -1,103 +1,47 @@
|
|
|
1
|
-
/*! Eleva v1.0.0-rc.
|
|
1
|
+
/*! Eleva v1.0.0-rc.14 | MIT License | https://elevajs.com */
|
|
2
2
|
// ============================================================================
|
|
3
3
|
// TYPE DEFINITIONS - TypeScript-friendly JSDoc types for IDE support
|
|
4
4
|
// ============================================================================
|
|
5
5
|
/**
|
|
6
|
-
* @typedef {Record<string, unknown>}
|
|
7
|
-
* Data context for
|
|
8
|
-
*/ /**
|
|
9
|
-
* @typedef {string} TemplateString
|
|
10
|
-
* A string containing {{ expression }} interpolation markers
|
|
6
|
+
* @typedef {Record<string, unknown>} ContextData
|
|
7
|
+
* Data context for expression evaluation
|
|
11
8
|
*/ /**
|
|
12
9
|
* @typedef {string} Expression
|
|
13
10
|
* A JavaScript expression to be evaluated in the data context
|
|
14
11
|
*/ /**
|
|
15
12
|
* @typedef {unknown} EvaluationResult
|
|
16
|
-
* The result of evaluating an expression (string, number, boolean, object, etc.)
|
|
13
|
+
* The result of evaluating an expression (string, number, boolean, object, function, etc.)
|
|
17
14
|
*/ /**
|
|
18
15
|
* @class 🔒 TemplateEngine
|
|
19
|
-
* @classdesc A
|
|
20
|
-
*
|
|
21
|
-
*
|
|
16
|
+
* @classdesc A minimal expression evaluator for Eleva's directive attributes.
|
|
17
|
+
* Evaluates JavaScript expressions against a component's context data.
|
|
18
|
+
* Used internally for `@event` handlers and `:prop` bindings.
|
|
22
19
|
*
|
|
23
|
-
*
|
|
24
|
-
* - `{{ expression }}` - Interpolate any JavaScript expression
|
|
25
|
-
* - `{{ variable }}` - Access data properties directly
|
|
26
|
-
* - `{{ object.property }}` - Access nested properties
|
|
27
|
-
* - `{{ condition ? a : b }}` - Ternary expressions
|
|
28
|
-
* - `{{ func(arg) }}` - Call functions from data context
|
|
20
|
+
* All methods are static and can be called directly on the class.
|
|
29
21
|
*
|
|
30
22
|
* @example
|
|
31
|
-
* //
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* const result = TemplateEngine.parse(template, data);
|
|
35
|
-
* // Result: "Hello, World!"
|
|
23
|
+
* // Property access
|
|
24
|
+
* TemplateEngine.evaluate("user.name", { user: { name: "John" } });
|
|
25
|
+
* // Result: "John"
|
|
36
26
|
*
|
|
37
27
|
* @example
|
|
38
|
-
* //
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* const result = TemplateEngine.parse(template, data);
|
|
42
|
-
* // Result: "Welcome, John!"
|
|
28
|
+
* // Function reference (for @event handlers)
|
|
29
|
+
* TemplateEngine.evaluate("handleClick", { handleClick: () => console.log("clicked") });
|
|
30
|
+
* // Result: [Function]
|
|
43
31
|
*
|
|
44
32
|
* @example
|
|
45
|
-
* //
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
* const result = TemplateEngine.parse(template, data);
|
|
49
|
-
* // Result: "Status: Online"
|
|
33
|
+
* // Signal values (for :prop bindings)
|
|
34
|
+
* TemplateEngine.evaluate("count.value", { count: { value: 42 } });
|
|
35
|
+
* // Result: 42
|
|
50
36
|
*
|
|
51
37
|
* @example
|
|
52
|
-
* //
|
|
53
|
-
*
|
|
54
|
-
*
|
|
55
|
-
* const result = TemplateEngine.parse(template, data);
|
|
56
|
-
* // Result: "Count: 42"
|
|
38
|
+
* // Complex expressions
|
|
39
|
+
* TemplateEngine.evaluate("items.filter(i => i.active)", { items: [{active: true}, {active: false}] });
|
|
40
|
+
* // Result: [{active: true}]
|
|
57
41
|
*/ class TemplateEngine {
|
|
58
42
|
/**
|
|
59
|
-
* Parses a template string, replacing expressions with their evaluated values.
|
|
60
|
-
* Expressions are evaluated in the provided data context.
|
|
61
|
-
*
|
|
62
|
-
* @public
|
|
63
|
-
* @static
|
|
64
|
-
* @param {TemplateString|unknown} template - The template string to parse.
|
|
65
|
-
* @param {TemplateData} data - The data context for evaluating expressions.
|
|
66
|
-
* @returns {string} The parsed template with expressions replaced by their values.
|
|
67
|
-
*
|
|
68
|
-
* @example
|
|
69
|
-
* // Simple variables
|
|
70
|
-
* TemplateEngine.parse("Hello, {{name}}!", { name: "World" });
|
|
71
|
-
* // Result: "Hello, World!"
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* // Nested properties
|
|
75
|
-
* TemplateEngine.parse("{{user.name}} is {{user.age}} years old", {
|
|
76
|
-
* user: { name: "John", age: 30 }
|
|
77
|
-
* });
|
|
78
|
-
* // Result: "John is 30 years old"
|
|
79
|
-
*
|
|
80
|
-
* @example
|
|
81
|
-
* // Multiple expressions
|
|
82
|
-
* TemplateEngine.parse("{{greeting}}, {{name}}! You have {{count}} messages.", {
|
|
83
|
-
* greeting: "Hello",
|
|
84
|
-
* name: "User",
|
|
85
|
-
* count: 5
|
|
86
|
-
* });
|
|
87
|
-
* // Result: "Hello, User! You have 5 messages."
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* // With conditionals
|
|
91
|
-
* TemplateEngine.parse("Status: {{online ? 'Active' : 'Inactive'}}", {
|
|
92
|
-
* online: true
|
|
93
|
-
* });
|
|
94
|
-
* // Result: "Status: Active"
|
|
95
|
-
*/ static parse(template, data) {
|
|
96
|
-
if (typeof template !== "string") return template;
|
|
97
|
-
return template.replace(this.expressionPattern, (_, expression)=>this.evaluate(expression, data));
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
43
|
* Evaluates an expression in the context of the provided data object.
|
|
44
|
+
* Used for resolving `@event` handlers and `:prop` bindings.
|
|
101
45
|
*
|
|
102
46
|
* Note: This does not provide a true sandbox and evaluated expressions may access global scope.
|
|
103
47
|
* The use of the `with` statement is necessary for expression evaluation but has security implications.
|
|
@@ -106,7 +50,7 @@
|
|
|
106
50
|
* @public
|
|
107
51
|
* @static
|
|
108
52
|
* @param {Expression|unknown} expression - The expression to evaluate.
|
|
109
|
-
* @param {
|
|
53
|
+
* @param {ContextData} data - The data context for evaluation.
|
|
110
54
|
* @returns {EvaluationResult} The result of the evaluation, or empty string if evaluation fails.
|
|
111
55
|
*
|
|
112
56
|
* @example
|
|
@@ -115,9 +59,19 @@
|
|
|
115
59
|
* // Result: "John"
|
|
116
60
|
*
|
|
117
61
|
* @example
|
|
118
|
-
* //
|
|
119
|
-
* TemplateEngine.evaluate("
|
|
120
|
-
* // Result:
|
|
62
|
+
* // Function reference
|
|
63
|
+
* TemplateEngine.evaluate("increment", { increment: () => count++ });
|
|
64
|
+
* // Result: [Function]
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* // Nested property with Signal
|
|
68
|
+
* TemplateEngine.evaluate("count.value", { count: { value: 42 } });
|
|
69
|
+
* // Result: 42
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* // Object reference (no JSON.stringify needed)
|
|
73
|
+
* TemplateEngine.evaluate("user", { user: { name: "John", age: 30 } });
|
|
74
|
+
* // Result: { name: "John", age: 30 }
|
|
121
75
|
*
|
|
122
76
|
* @example
|
|
123
77
|
* // Expressions
|
|
@@ -125,19 +79,12 @@
|
|
|
125
79
|
* // Result: true
|
|
126
80
|
*
|
|
127
81
|
* @example
|
|
128
|
-
* // Function calls
|
|
129
|
-
* TemplateEngine.evaluate("formatDate(date)", {
|
|
130
|
-
* date: new Date(),
|
|
131
|
-
* formatDate: (d) => d.toISOString()
|
|
132
|
-
* });
|
|
133
|
-
* // Result: "2024-01-01T00:00:00.000Z"
|
|
134
|
-
*
|
|
135
|
-
* @example
|
|
136
82
|
* // Failed evaluation returns empty string
|
|
137
83
|
* TemplateEngine.evaluate("nonexistent.property", {});
|
|
138
84
|
* // Result: ""
|
|
139
85
|
*/ static evaluate(expression, data) {
|
|
140
86
|
if (typeof expression !== "string") return expression;
|
|
87
|
+
if (!expression.trim()) return "";
|
|
141
88
|
let fn = this._functionCache.get(expression);
|
|
142
89
|
if (!fn) {
|
|
143
90
|
try {
|
|
@@ -154,14 +101,6 @@
|
|
|
154
101
|
}
|
|
155
102
|
}
|
|
156
103
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Regular expression for matching template expressions in the format {{ expression }}
|
|
159
|
-
* Matches: {{ anything }} with optional whitespace inside braces
|
|
160
|
-
*
|
|
161
|
-
* @static
|
|
162
|
-
* @private
|
|
163
|
-
* @type {RegExp}
|
|
164
|
-
*/ TemplateEngine.expressionPattern = /\{\{\s*(.*?)\s*\}\}/g;
|
|
165
104
|
/**
|
|
166
105
|
* Cache for compiled expression functions.
|
|
167
106
|
* Stores compiled Function objects keyed by expression string for O(1) lookup.
|
|
@@ -1096,8 +1035,7 @@
|
|
|
1096
1035
|
* 3. Updating the DOM
|
|
1097
1036
|
* 4. Processing events, injecting styles, and mounting child components.
|
|
1098
1037
|
*/ const render = async ()=>{
|
|
1099
|
-
const
|
|
1100
|
-
const html = this.templateEngine.parse(templateResult, mergedContext);
|
|
1038
|
+
const html = typeof template === "function" ? await template(mergedContext) : template;
|
|
1101
1039
|
// Execute before hooks
|
|
1102
1040
|
if (!isMounted) {
|
|
1103
1041
|
await mergedContext.onBeforeMount?.({
|
|
@@ -1113,7 +1051,7 @@
|
|
|
1113
1051
|
this.renderer.patchDOM(container, html);
|
|
1114
1052
|
this._processEvents(container, mergedContext, listeners);
|
|
1115
1053
|
if (style) this._injectStyles(container, compId, style, mergedContext);
|
|
1116
|
-
if (children) await this._mountComponents(container, children, childInstances);
|
|
1054
|
+
if (children) await this._mountComponents(container, children, childInstances, mergedContext);
|
|
1117
1055
|
// Execute after hooks
|
|
1118
1056
|
if (!isMounted) {
|
|
1119
1057
|
await mergedContext.onMount?.({
|
|
@@ -1206,7 +1144,7 @@
|
|
|
1206
1144
|
* @param {ComponentContext} context - The current component context for style interpolation.
|
|
1207
1145
|
* @returns {void}
|
|
1208
1146
|
*/ _injectStyles(container, compId, styleDef, context) {
|
|
1209
|
-
/** @type {string} */ const newStyle = typeof styleDef === "function" ?
|
|
1147
|
+
/** @type {string} */ const newStyle = typeof styleDef === "function" ? styleDef(context) : styleDef;
|
|
1210
1148
|
/** @type {HTMLStyleElement|null} */ let styleEl = container.querySelector(`style[data-e-style="${compId}"]`);
|
|
1211
1149
|
if (styleEl && styleEl.textContent === newStyle) return;
|
|
1212
1150
|
if (!styleEl) {
|
|
@@ -1217,17 +1155,20 @@
|
|
|
1217
1155
|
styleEl.textContent = newStyle;
|
|
1218
1156
|
}
|
|
1219
1157
|
/**
|
|
1220
|
-
* Extracts props from an element's attributes that start with
|
|
1221
|
-
*
|
|
1158
|
+
* Extracts and evaluates props from an element's attributes that start with `:`.
|
|
1159
|
+
* Prop values are evaluated as expressions against the component context,
|
|
1160
|
+
* allowing direct passing of objects, arrays, and other complex types.
|
|
1222
1161
|
*
|
|
1223
1162
|
* @private
|
|
1224
1163
|
* @param {HTMLElement} element - The DOM element to extract props from
|
|
1225
|
-
* @
|
|
1164
|
+
* @param {ComponentContext} context - The component context for evaluating prop expressions
|
|
1165
|
+
* @returns {Record<string, string>} An object containing the evaluated props
|
|
1226
1166
|
* @example
|
|
1227
1167
|
* // For an element with attributes:
|
|
1228
|
-
* // <div :name="
|
|
1229
|
-
* //
|
|
1230
|
-
|
|
1168
|
+
* // <div :name="user.name" :data="items">
|
|
1169
|
+
* // With context: { user: { name: "John" }, items: [1, 2, 3] }
|
|
1170
|
+
* // Returns: { name: "John", data: [1, 2, 3] }
|
|
1171
|
+
*/ _extractProps(element, context) {
|
|
1231
1172
|
if (!element.attributes) return {};
|
|
1232
1173
|
const props = {};
|
|
1233
1174
|
const attrs = element.attributes;
|
|
@@ -1235,7 +1176,7 @@
|
|
|
1235
1176
|
const attr = attrs[i];
|
|
1236
1177
|
if (attr.name.startsWith(":")) {
|
|
1237
1178
|
const propName = attr.name.slice(1);
|
|
1238
|
-
props[propName] = attr.value;
|
|
1179
|
+
props[propName] = this.templateEngine.evaluate(attr.value, context);
|
|
1239
1180
|
element.removeAttribute(attr.name);
|
|
1240
1181
|
}
|
|
1241
1182
|
}
|
|
@@ -1253,6 +1194,7 @@
|
|
|
1253
1194
|
* @param {HTMLElement} container - The container element to mount components in
|
|
1254
1195
|
* @param {Object<string, ComponentDefinition>} children - Map of selectors to component definitions for explicit children
|
|
1255
1196
|
* @param {Array<MountResult>} childInstances - Array to store all mounted component instances
|
|
1197
|
+
* @param {ComponentContext} context - The parent component context for evaluating prop expressions
|
|
1256
1198
|
* @returns {Promise<void>}
|
|
1257
1199
|
*
|
|
1258
1200
|
* @example
|
|
@@ -1261,12 +1203,12 @@
|
|
|
1261
1203
|
* 'UserProfile': UserProfileComponent,
|
|
1262
1204
|
* '#settings-panel': "settings-panel"
|
|
1263
1205
|
* };
|
|
1264
|
-
*/ async _mountComponents(container, children, childInstances) {
|
|
1206
|
+
*/ async _mountComponents(container, children, childInstances, context) {
|
|
1265
1207
|
for (const [selector, component] of Object.entries(children)){
|
|
1266
1208
|
if (!selector) continue;
|
|
1267
1209
|
for (const el of container.querySelectorAll(selector)){
|
|
1268
1210
|
if (!(el instanceof HTMLElement)) continue;
|
|
1269
|
-
/** @type {Record<string, string>} */ const props = this._extractProps(el);
|
|
1211
|
+
/** @type {Record<string, string>} */ const props = this._extractProps(el, context);
|
|
1270
1212
|
/** @type {MountResult} */ const instance = await this.mount(el, component, props);
|
|
1271
1213
|
if (instance && !childInstances.includes(instance)) {
|
|
1272
1214
|
childInstances.push(instance);
|