@servlyadmin/runtime-core 0.1.4 → 0.1.6

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/index.cjs CHANGED
@@ -1471,15 +1471,62 @@ function applyAttributes(domElement, element, context) {
1471
1471
  }
1472
1472
  }
1473
1473
  }
1474
- function attachEventHandlers(domElement, elementId, eventHandlers, elementState) {
1475
- if (!eventHandlers || !eventHandlers[elementId]) {
1476
- return;
1474
+ function resolveFunctionBinding(binding, context) {
1475
+ if (binding.source === "props" || binding.source === "parent") {
1476
+ const path = binding.path;
1477
+ if (!path) return void 0;
1478
+ const parts = path.split(".");
1479
+ let value = context.props;
1480
+ for (const part of parts) {
1481
+ if (value === null || value === void 0) return void 0;
1482
+ value = value[part];
1483
+ }
1484
+ if (typeof value === "function") {
1485
+ return value;
1486
+ }
1487
+ return void 0;
1488
+ }
1489
+ if (binding.source === "static" && typeof binding.value === "function") {
1490
+ return binding.value;
1491
+ }
1492
+ return void 0;
1493
+ }
1494
+ function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false) {
1495
+ const elementId = element.i;
1496
+ if (eventHandlers && eventHandlers[elementId]) {
1497
+ const handlers = eventHandlers[elementId];
1498
+ for (const [eventName, handler] of Object.entries(handlers)) {
1499
+ const domEventName = eventName.replace(/^on/, "").toLowerCase();
1500
+ elementState.eventListeners.set(domEventName, handler);
1501
+ domElement.addEventListener(domEventName, handler);
1502
+ }
1503
+ }
1504
+ const bindings = element.configuration?.bindings?.inputs;
1505
+ if (bindings) {
1506
+ for (const [propName, binding] of Object.entries(bindings)) {
1507
+ if (propName.startsWith("on") && propName.length > 2) {
1508
+ const handler = resolveFunctionBinding(binding, context);
1509
+ if (handler) {
1510
+ const domEventName = propName.slice(2).toLowerCase();
1511
+ if (!elementState.eventListeners.has(domEventName)) {
1512
+ elementState.eventListeners.set(domEventName, handler);
1513
+ domElement.addEventListener(domEventName, handler);
1514
+ }
1515
+ }
1516
+ }
1517
+ }
1477
1518
  }
1478
- const handlers = eventHandlers[elementId];
1479
- for (const [eventName, handler] of Object.entries(handlers)) {
1480
- const domEventName = eventName.replace(/^on/, "").toLowerCase();
1481
- elementState.eventListeners.set(domEventName, handler);
1482
- domElement.addEventListener(domEventName, handler);
1519
+ if (isRootElement && context.props) {
1520
+ for (const [propName, value] of Object.entries(context.props)) {
1521
+ if (propName.startsWith("on") && propName.length > 2 && typeof value === "function") {
1522
+ const domEventName = propName.slice(2).toLowerCase();
1523
+ if (!elementState.eventListeners.has(domEventName)) {
1524
+ const handler = value;
1525
+ elementState.eventListeners.set(domEventName, handler);
1526
+ domElement.addEventListener(domEventName, handler);
1527
+ }
1528
+ }
1529
+ }
1483
1530
  }
1484
1531
  }
1485
1532
  function detachEventHandlers(elementState) {
@@ -1488,7 +1535,7 @@ function detachEventHandlers(elementState) {
1488
1535
  }
1489
1536
  elementState.eventListeners.clear();
1490
1537
  }
1491
- function createElement(element, context, eventHandlers) {
1538
+ function createElement(element, context, eventHandlers, isRootElement = false) {
1492
1539
  const tag = getElementTag(element);
1493
1540
  const domElement = document.createElement(tag);
1494
1541
  domElement.setAttribute("data-servly-id", element.i);
@@ -1514,7 +1561,7 @@ function createElement(element, context, eventHandlers) {
1514
1561
  textContent,
1515
1562
  eventListeners: /* @__PURE__ */ new Map()
1516
1563
  };
1517
- attachEventHandlers(domElement, element.i, eventHandlers, elementState);
1564
+ attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement);
1518
1565
  return elementState;
1519
1566
  }
1520
1567
  var globalRenderingStack = /* @__PURE__ */ new Set();
@@ -1575,8 +1622,8 @@ function renderComponentRef(element, container, context, state) {
1575
1622
  globalRenderingStack.delete(refId);
1576
1623
  }
1577
1624
  }
1578
- function renderElement(element, tree, context, eventHandlers, elementStates, state) {
1579
- const elementState = createElement(element, context, eventHandlers);
1625
+ function renderElement(element, tree, context, eventHandlers, elementStates, state, isRootElement = false) {
1626
+ const elementState = createElement(element, context, eventHandlers, isRootElement);
1580
1627
  elementStates.set(element.i, elementState);
1581
1628
  const config = element.configuration;
1582
1629
  if (config?.componentViewRef) {
@@ -1588,7 +1635,7 @@ function renderElement(element, tree, context, eventHandlers, elementStates, sta
1588
1635
  }
1589
1636
  const children = tree.get(element.i) || [];
1590
1637
  for (const child of children) {
1591
- const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state);
1638
+ const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state, false);
1592
1639
  elementState.domElement.appendChild(childElement);
1593
1640
  }
1594
1641
  return elementState.domElement;
@@ -1637,14 +1684,16 @@ function render(options) {
1637
1684
  context,
1638
1685
  eventHandlers,
1639
1686
  state.elementStates,
1640
- state
1687
+ state,
1688
+ true
1689
+ // isRootElement
1641
1690
  );
1642
1691
  container.appendChild(state.rootElement);
1643
1692
  } else {
1644
1693
  const wrapper = document.createElement("div");
1645
1694
  wrapper.setAttribute("data-servly-wrapper", "true");
1646
1695
  for (const root of rootElements) {
1647
- const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state);
1696
+ const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state, true);
1648
1697
  wrapper.appendChild(rootElement);
1649
1698
  }
1650
1699
  state.rootElement = wrapper;
package/dist/index.d.cts CHANGED
@@ -52,6 +52,15 @@ interface ElementConfig {
52
52
  readOnly?: boolean;
53
53
  /** Inline styles */
54
54
  style?: Record<string, any>;
55
+ /** Input bindings for props */
56
+ bindings?: {
57
+ inputs?: Record<string, {
58
+ source: 'static' | 'props' | 'state' | 'parent' | 'function';
59
+ value?: any;
60
+ path?: string;
61
+ binding?: any;
62
+ }>;
63
+ };
55
64
  /** Reference to another component (for componentView elements) */
56
65
  componentViewRef?: string;
57
66
  /** Version specifier for the referenced component */
package/dist/index.d.ts CHANGED
@@ -52,6 +52,15 @@ interface ElementConfig {
52
52
  readOnly?: boolean;
53
53
  /** Inline styles */
54
54
  style?: Record<string, any>;
55
+ /** Input bindings for props */
56
+ bindings?: {
57
+ inputs?: Record<string, {
58
+ source: 'static' | 'props' | 'state' | 'parent' | 'function';
59
+ value?: any;
60
+ path?: string;
61
+ binding?: any;
62
+ }>;
63
+ };
55
64
  /** Reference to another component (for componentView elements) */
56
65
  componentViewRef?: string;
57
66
  /** Version specifier for the referenced component */
package/dist/index.js CHANGED
@@ -1198,15 +1198,62 @@ function applyAttributes(domElement, element, context) {
1198
1198
  }
1199
1199
  }
1200
1200
  }
1201
- function attachEventHandlers(domElement, elementId, eventHandlers, elementState) {
1202
- if (!eventHandlers || !eventHandlers[elementId]) {
1203
- return;
1201
+ function resolveFunctionBinding(binding, context) {
1202
+ if (binding.source === "props" || binding.source === "parent") {
1203
+ const path = binding.path;
1204
+ if (!path) return void 0;
1205
+ const parts = path.split(".");
1206
+ let value = context.props;
1207
+ for (const part of parts) {
1208
+ if (value === null || value === void 0) return void 0;
1209
+ value = value[part];
1210
+ }
1211
+ if (typeof value === "function") {
1212
+ return value;
1213
+ }
1214
+ return void 0;
1215
+ }
1216
+ if (binding.source === "static" && typeof binding.value === "function") {
1217
+ return binding.value;
1218
+ }
1219
+ return void 0;
1220
+ }
1221
+ function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false) {
1222
+ const elementId = element.i;
1223
+ if (eventHandlers && eventHandlers[elementId]) {
1224
+ const handlers = eventHandlers[elementId];
1225
+ for (const [eventName, handler] of Object.entries(handlers)) {
1226
+ const domEventName = eventName.replace(/^on/, "").toLowerCase();
1227
+ elementState.eventListeners.set(domEventName, handler);
1228
+ domElement.addEventListener(domEventName, handler);
1229
+ }
1230
+ }
1231
+ const bindings = element.configuration?.bindings?.inputs;
1232
+ if (bindings) {
1233
+ for (const [propName, binding] of Object.entries(bindings)) {
1234
+ if (propName.startsWith("on") && propName.length > 2) {
1235
+ const handler = resolveFunctionBinding(binding, context);
1236
+ if (handler) {
1237
+ const domEventName = propName.slice(2).toLowerCase();
1238
+ if (!elementState.eventListeners.has(domEventName)) {
1239
+ elementState.eventListeners.set(domEventName, handler);
1240
+ domElement.addEventListener(domEventName, handler);
1241
+ }
1242
+ }
1243
+ }
1244
+ }
1204
1245
  }
1205
- const handlers = eventHandlers[elementId];
1206
- for (const [eventName, handler] of Object.entries(handlers)) {
1207
- const domEventName = eventName.replace(/^on/, "").toLowerCase();
1208
- elementState.eventListeners.set(domEventName, handler);
1209
- domElement.addEventListener(domEventName, handler);
1246
+ if (isRootElement && context.props) {
1247
+ for (const [propName, value] of Object.entries(context.props)) {
1248
+ if (propName.startsWith("on") && propName.length > 2 && typeof value === "function") {
1249
+ const domEventName = propName.slice(2).toLowerCase();
1250
+ if (!elementState.eventListeners.has(domEventName)) {
1251
+ const handler = value;
1252
+ elementState.eventListeners.set(domEventName, handler);
1253
+ domElement.addEventListener(domEventName, handler);
1254
+ }
1255
+ }
1256
+ }
1210
1257
  }
1211
1258
  }
1212
1259
  function detachEventHandlers(elementState) {
@@ -1215,7 +1262,7 @@ function detachEventHandlers(elementState) {
1215
1262
  }
1216
1263
  elementState.eventListeners.clear();
1217
1264
  }
1218
- function createElement(element, context, eventHandlers) {
1265
+ function createElement(element, context, eventHandlers, isRootElement = false) {
1219
1266
  const tag = getElementTag(element);
1220
1267
  const domElement = document.createElement(tag);
1221
1268
  domElement.setAttribute("data-servly-id", element.i);
@@ -1241,7 +1288,7 @@ function createElement(element, context, eventHandlers) {
1241
1288
  textContent,
1242
1289
  eventListeners: /* @__PURE__ */ new Map()
1243
1290
  };
1244
- attachEventHandlers(domElement, element.i, eventHandlers, elementState);
1291
+ attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement);
1245
1292
  return elementState;
1246
1293
  }
1247
1294
  var globalRenderingStack = /* @__PURE__ */ new Set();
@@ -1302,8 +1349,8 @@ function renderComponentRef(element, container, context, state) {
1302
1349
  globalRenderingStack.delete(refId);
1303
1350
  }
1304
1351
  }
1305
- function renderElement(element, tree, context, eventHandlers, elementStates, state) {
1306
- const elementState = createElement(element, context, eventHandlers);
1352
+ function renderElement(element, tree, context, eventHandlers, elementStates, state, isRootElement = false) {
1353
+ const elementState = createElement(element, context, eventHandlers, isRootElement);
1307
1354
  elementStates.set(element.i, elementState);
1308
1355
  const config = element.configuration;
1309
1356
  if (config?.componentViewRef) {
@@ -1315,7 +1362,7 @@ function renderElement(element, tree, context, eventHandlers, elementStates, sta
1315
1362
  }
1316
1363
  const children = tree.get(element.i) || [];
1317
1364
  for (const child of children) {
1318
- const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state);
1365
+ const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state, false);
1319
1366
  elementState.domElement.appendChild(childElement);
1320
1367
  }
1321
1368
  return elementState.domElement;
@@ -1364,14 +1411,16 @@ function render(options) {
1364
1411
  context,
1365
1412
  eventHandlers,
1366
1413
  state.elementStates,
1367
- state
1414
+ state,
1415
+ true
1416
+ // isRootElement
1368
1417
  );
1369
1418
  container.appendChild(state.rootElement);
1370
1419
  } else {
1371
1420
  const wrapper = document.createElement("div");
1372
1421
  wrapper.setAttribute("data-servly-wrapper", "true");
1373
1422
  for (const root of rootElements) {
1374
- const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state);
1423
+ const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state, true);
1375
1424
  wrapper.appendChild(rootElement);
1376
1425
  }
1377
1426
  state.rootElement = wrapper;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servlyadmin/runtime-core",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Framework-agnostic core renderer for Servly components",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",