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.umd.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! Eleva v1.0.0-rc.
|
|
1
|
+
/*! Eleva v1.0.0-rc.14 | MIT License | https://elevajs.com */
|
|
2
2
|
(function (global, factory) {
|
|
3
3
|
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
|
|
4
4
|
typeof define === 'function' && define.amd ? define(factory) :
|
|
@@ -9,101 +9,45 @@
|
|
|
9
9
|
// TYPE DEFINITIONS - TypeScript-friendly JSDoc types for IDE support
|
|
10
10
|
// ============================================================================
|
|
11
11
|
/**
|
|
12
|
-
* @typedef {Record<string, unknown>}
|
|
13
|
-
* Data context for
|
|
14
|
-
*/ /**
|
|
15
|
-
* @typedef {string} TemplateString
|
|
16
|
-
* A string containing {{ expression }} interpolation markers
|
|
12
|
+
* @typedef {Record<string, unknown>} ContextData
|
|
13
|
+
* Data context for expression evaluation
|
|
17
14
|
*/ /**
|
|
18
15
|
* @typedef {string} Expression
|
|
19
16
|
* A JavaScript expression to be evaluated in the data context
|
|
20
17
|
*/ /**
|
|
21
18
|
* @typedef {unknown} EvaluationResult
|
|
22
|
-
* The result of evaluating an expression (string, number, boolean, object, etc.)
|
|
19
|
+
* The result of evaluating an expression (string, number, boolean, object, function, etc.)
|
|
23
20
|
*/ /**
|
|
24
21
|
* @class 🔒 TemplateEngine
|
|
25
|
-
* @classdesc A
|
|
26
|
-
*
|
|
27
|
-
*
|
|
22
|
+
* @classdesc A minimal expression evaluator for Eleva's directive attributes.
|
|
23
|
+
* Evaluates JavaScript expressions against a component's context data.
|
|
24
|
+
* Used internally for `@event` handlers and `:prop` bindings.
|
|
28
25
|
*
|
|
29
|
-
*
|
|
30
|
-
* - `{{ expression }}` - Interpolate any JavaScript expression
|
|
31
|
-
* - `{{ variable }}` - Access data properties directly
|
|
32
|
-
* - `{{ object.property }}` - Access nested properties
|
|
33
|
-
* - `{{ condition ? a : b }}` - Ternary expressions
|
|
34
|
-
* - `{{ func(arg) }}` - Call functions from data context
|
|
26
|
+
* All methods are static and can be called directly on the class.
|
|
35
27
|
*
|
|
36
28
|
* @example
|
|
37
|
-
* //
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* const result = TemplateEngine.parse(template, data);
|
|
41
|
-
* // Result: "Hello, World!"
|
|
29
|
+
* // Property access
|
|
30
|
+
* TemplateEngine.evaluate("user.name", { user: { name: "John" } });
|
|
31
|
+
* // Result: "John"
|
|
42
32
|
*
|
|
43
33
|
* @example
|
|
44
|
-
* //
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
* const result = TemplateEngine.parse(template, data);
|
|
48
|
-
* // Result: "Welcome, John!"
|
|
34
|
+
* // Function reference (for @event handlers)
|
|
35
|
+
* TemplateEngine.evaluate("handleClick", { handleClick: () => console.log("clicked") });
|
|
36
|
+
* // Result: [Function]
|
|
49
37
|
*
|
|
50
38
|
* @example
|
|
51
|
-
* //
|
|
52
|
-
*
|
|
53
|
-
*
|
|
54
|
-
* const result = TemplateEngine.parse(template, data);
|
|
55
|
-
* // Result: "Status: Online"
|
|
39
|
+
* // Signal values (for :prop bindings)
|
|
40
|
+
* TemplateEngine.evaluate("count.value", { count: { value: 42 } });
|
|
41
|
+
* // Result: 42
|
|
56
42
|
*
|
|
57
43
|
* @example
|
|
58
|
-
* //
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* const result = TemplateEngine.parse(template, data);
|
|
62
|
-
* // Result: "Count: 42"
|
|
44
|
+
* // Complex expressions
|
|
45
|
+
* TemplateEngine.evaluate("items.filter(i => i.active)", { items: [{active: true}, {active: false}] });
|
|
46
|
+
* // Result: [{active: true}]
|
|
63
47
|
*/ class TemplateEngine {
|
|
64
48
|
/**
|
|
65
|
-
* Parses a template string, replacing expressions with their evaluated values.
|
|
66
|
-
* Expressions are evaluated in the provided data context.
|
|
67
|
-
*
|
|
68
|
-
* @public
|
|
69
|
-
* @static
|
|
70
|
-
* @param {TemplateString|unknown} template - The template string to parse.
|
|
71
|
-
* @param {TemplateData} data - The data context for evaluating expressions.
|
|
72
|
-
* @returns {string} The parsed template with expressions replaced by their values.
|
|
73
|
-
*
|
|
74
|
-
* @example
|
|
75
|
-
* // Simple variables
|
|
76
|
-
* TemplateEngine.parse("Hello, {{name}}!", { name: "World" });
|
|
77
|
-
* // Result: "Hello, World!"
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* // Nested properties
|
|
81
|
-
* TemplateEngine.parse("{{user.name}} is {{user.age}} years old", {
|
|
82
|
-
* user: { name: "John", age: 30 }
|
|
83
|
-
* });
|
|
84
|
-
* // Result: "John is 30 years old"
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* // Multiple expressions
|
|
88
|
-
* TemplateEngine.parse("{{greeting}}, {{name}}! You have {{count}} messages.", {
|
|
89
|
-
* greeting: "Hello",
|
|
90
|
-
* name: "User",
|
|
91
|
-
* count: 5
|
|
92
|
-
* });
|
|
93
|
-
* // Result: "Hello, User! You have 5 messages."
|
|
94
|
-
*
|
|
95
|
-
* @example
|
|
96
|
-
* // With conditionals
|
|
97
|
-
* TemplateEngine.parse("Status: {{online ? 'Active' : 'Inactive'}}", {
|
|
98
|
-
* online: true
|
|
99
|
-
* });
|
|
100
|
-
* // Result: "Status: Active"
|
|
101
|
-
*/ static parse(template, data) {
|
|
102
|
-
if (typeof template !== "string") return template;
|
|
103
|
-
return template.replace(this.expressionPattern, (_, expression)=>this.evaluate(expression, data));
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
49
|
* Evaluates an expression in the context of the provided data object.
|
|
50
|
+
* Used for resolving `@event` handlers and `:prop` bindings.
|
|
107
51
|
*
|
|
108
52
|
* Note: This does not provide a true sandbox and evaluated expressions may access global scope.
|
|
109
53
|
* The use of the `with` statement is necessary for expression evaluation but has security implications.
|
|
@@ -112,7 +56,7 @@
|
|
|
112
56
|
* @public
|
|
113
57
|
* @static
|
|
114
58
|
* @param {Expression|unknown} expression - The expression to evaluate.
|
|
115
|
-
* @param {
|
|
59
|
+
* @param {ContextData} data - The data context for evaluation.
|
|
116
60
|
* @returns {EvaluationResult} The result of the evaluation, or empty string if evaluation fails.
|
|
117
61
|
*
|
|
118
62
|
* @example
|
|
@@ -121,9 +65,19 @@
|
|
|
121
65
|
* // Result: "John"
|
|
122
66
|
*
|
|
123
67
|
* @example
|
|
124
|
-
* //
|
|
125
|
-
* TemplateEngine.evaluate("
|
|
126
|
-
* // Result:
|
|
68
|
+
* // Function reference
|
|
69
|
+
* TemplateEngine.evaluate("increment", { increment: () => count++ });
|
|
70
|
+
* // Result: [Function]
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* // Nested property with Signal
|
|
74
|
+
* TemplateEngine.evaluate("count.value", { count: { value: 42 } });
|
|
75
|
+
* // Result: 42
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* // Object reference (no JSON.stringify needed)
|
|
79
|
+
* TemplateEngine.evaluate("user", { user: { name: "John", age: 30 } });
|
|
80
|
+
* // Result: { name: "John", age: 30 }
|
|
127
81
|
*
|
|
128
82
|
* @example
|
|
129
83
|
* // Expressions
|
|
@@ -131,19 +85,12 @@
|
|
|
131
85
|
* // Result: true
|
|
132
86
|
*
|
|
133
87
|
* @example
|
|
134
|
-
* // Function calls
|
|
135
|
-
* TemplateEngine.evaluate("formatDate(date)", {
|
|
136
|
-
* date: new Date(),
|
|
137
|
-
* formatDate: (d) => d.toISOString()
|
|
138
|
-
* });
|
|
139
|
-
* // Result: "2024-01-01T00:00:00.000Z"
|
|
140
|
-
*
|
|
141
|
-
* @example
|
|
142
88
|
* // Failed evaluation returns empty string
|
|
143
89
|
* TemplateEngine.evaluate("nonexistent.property", {});
|
|
144
90
|
* // Result: ""
|
|
145
91
|
*/ static evaluate(expression, data) {
|
|
146
92
|
if (typeof expression !== "string") return expression;
|
|
93
|
+
if (!expression.trim()) return "";
|
|
147
94
|
let fn = this._functionCache.get(expression);
|
|
148
95
|
if (!fn) {
|
|
149
96
|
try {
|
|
@@ -160,14 +107,6 @@
|
|
|
160
107
|
}
|
|
161
108
|
}
|
|
162
109
|
}
|
|
163
|
-
/**
|
|
164
|
-
* Regular expression for matching template expressions in the format {{ expression }}
|
|
165
|
-
* Matches: {{ anything }} with optional whitespace inside braces
|
|
166
|
-
*
|
|
167
|
-
* @static
|
|
168
|
-
* @private
|
|
169
|
-
* @type {RegExp}
|
|
170
|
-
*/ TemplateEngine.expressionPattern = /\{\{\s*(.*?)\s*\}\}/g;
|
|
171
110
|
/**
|
|
172
111
|
* Cache for compiled expression functions.
|
|
173
112
|
* Stores compiled Function objects keyed by expression string for O(1) lookup.
|
|
@@ -1102,8 +1041,7 @@
|
|
|
1102
1041
|
* 3. Updating the DOM
|
|
1103
1042
|
* 4. Processing events, injecting styles, and mounting child components.
|
|
1104
1043
|
*/ const render = async ()=>{
|
|
1105
|
-
const
|
|
1106
|
-
const html = this.templateEngine.parse(templateResult, mergedContext);
|
|
1044
|
+
const html = typeof template === "function" ? await template(mergedContext) : template;
|
|
1107
1045
|
// Execute before hooks
|
|
1108
1046
|
if (!isMounted) {
|
|
1109
1047
|
await mergedContext.onBeforeMount?.({
|
|
@@ -1119,7 +1057,7 @@
|
|
|
1119
1057
|
this.renderer.patchDOM(container, html);
|
|
1120
1058
|
this._processEvents(container, mergedContext, listeners);
|
|
1121
1059
|
if (style) this._injectStyles(container, compId, style, mergedContext);
|
|
1122
|
-
if (children) await this._mountComponents(container, children, childInstances);
|
|
1060
|
+
if (children) await this._mountComponents(container, children, childInstances, mergedContext);
|
|
1123
1061
|
// Execute after hooks
|
|
1124
1062
|
if (!isMounted) {
|
|
1125
1063
|
await mergedContext.onMount?.({
|
|
@@ -1212,7 +1150,7 @@
|
|
|
1212
1150
|
* @param {ComponentContext} context - The current component context for style interpolation.
|
|
1213
1151
|
* @returns {void}
|
|
1214
1152
|
*/ _injectStyles(container, compId, styleDef, context) {
|
|
1215
|
-
/** @type {string} */ const newStyle = typeof styleDef === "function" ?
|
|
1153
|
+
/** @type {string} */ const newStyle = typeof styleDef === "function" ? styleDef(context) : styleDef;
|
|
1216
1154
|
/** @type {HTMLStyleElement|null} */ let styleEl = container.querySelector(`style[data-e-style="${compId}"]`);
|
|
1217
1155
|
if (styleEl && styleEl.textContent === newStyle) return;
|
|
1218
1156
|
if (!styleEl) {
|
|
@@ -1223,17 +1161,20 @@
|
|
|
1223
1161
|
styleEl.textContent = newStyle;
|
|
1224
1162
|
}
|
|
1225
1163
|
/**
|
|
1226
|
-
* Extracts props from an element's attributes that start with
|
|
1227
|
-
*
|
|
1164
|
+
* Extracts and evaluates props from an element's attributes that start with `:`.
|
|
1165
|
+
* Prop values are evaluated as expressions against the component context,
|
|
1166
|
+
* allowing direct passing of objects, arrays, and other complex types.
|
|
1228
1167
|
*
|
|
1229
1168
|
* @private
|
|
1230
1169
|
* @param {HTMLElement} element - The DOM element to extract props from
|
|
1231
|
-
* @
|
|
1170
|
+
* @param {ComponentContext} context - The component context for evaluating prop expressions
|
|
1171
|
+
* @returns {Record<string, string>} An object containing the evaluated props
|
|
1232
1172
|
* @example
|
|
1233
1173
|
* // For an element with attributes:
|
|
1234
|
-
* // <div :name="
|
|
1235
|
-
* //
|
|
1236
|
-
|
|
1174
|
+
* // <div :name="user.name" :data="items">
|
|
1175
|
+
* // With context: { user: { name: "John" }, items: [1, 2, 3] }
|
|
1176
|
+
* // Returns: { name: "John", data: [1, 2, 3] }
|
|
1177
|
+
*/ _extractProps(element, context) {
|
|
1237
1178
|
if (!element.attributes) return {};
|
|
1238
1179
|
const props = {};
|
|
1239
1180
|
const attrs = element.attributes;
|
|
@@ -1241,7 +1182,7 @@
|
|
|
1241
1182
|
const attr = attrs[i];
|
|
1242
1183
|
if (attr.name.startsWith(":")) {
|
|
1243
1184
|
const propName = attr.name.slice(1);
|
|
1244
|
-
props[propName] = attr.value;
|
|
1185
|
+
props[propName] = this.templateEngine.evaluate(attr.value, context);
|
|
1245
1186
|
element.removeAttribute(attr.name);
|
|
1246
1187
|
}
|
|
1247
1188
|
}
|
|
@@ -1259,6 +1200,7 @@
|
|
|
1259
1200
|
* @param {HTMLElement} container - The container element to mount components in
|
|
1260
1201
|
* @param {Object<string, ComponentDefinition>} children - Map of selectors to component definitions for explicit children
|
|
1261
1202
|
* @param {Array<MountResult>} childInstances - Array to store all mounted component instances
|
|
1203
|
+
* @param {ComponentContext} context - The parent component context for evaluating prop expressions
|
|
1262
1204
|
* @returns {Promise<void>}
|
|
1263
1205
|
*
|
|
1264
1206
|
* @example
|
|
@@ -1267,12 +1209,12 @@
|
|
|
1267
1209
|
* 'UserProfile': UserProfileComponent,
|
|
1268
1210
|
* '#settings-panel': "settings-panel"
|
|
1269
1211
|
* };
|
|
1270
|
-
*/ async _mountComponents(container, children, childInstances) {
|
|
1212
|
+
*/ async _mountComponents(container, children, childInstances, context) {
|
|
1271
1213
|
for (const [selector, component] of Object.entries(children)){
|
|
1272
1214
|
if (!selector) continue;
|
|
1273
1215
|
for (const el of container.querySelectorAll(selector)){
|
|
1274
1216
|
if (!(el instanceof HTMLElement)) continue;
|
|
1275
|
-
/** @type {Record<string, string>} */ const props = this._extractProps(el);
|
|
1217
|
+
/** @type {Record<string, string>} */ const props = this._extractProps(el, context);
|
|
1276
1218
|
/** @type {MountResult} */ const instance = await this.mount(el, component, props);
|
|
1277
1219
|
if (instance && !childInstances.includes(instance)) {
|
|
1278
1220
|
childInstances.push(instance);
|