@constela/runtime 0.13.0 → 0.14.0
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.d.ts +1 -0
- package/dist/index.js +393 -31
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -428,6 +428,18 @@ function evaluate(expr, ctx) {
|
|
|
428
428
|
return val == null ? "" : String(val);
|
|
429
429
|
}).join("");
|
|
430
430
|
}
|
|
431
|
+
case "validity": {
|
|
432
|
+
const element2 = ctx.refs?.[expr.ref];
|
|
433
|
+
if (!element2) return null;
|
|
434
|
+
const formElement = element2;
|
|
435
|
+
if (!formElement.validity) return null;
|
|
436
|
+
const validity = formElement.validity;
|
|
437
|
+
const property = expr.property || "valid";
|
|
438
|
+
if (property === "message") {
|
|
439
|
+
return formElement.validationMessage || "";
|
|
440
|
+
}
|
|
441
|
+
return validity[property] ?? null;
|
|
442
|
+
}
|
|
431
443
|
default: {
|
|
432
444
|
const _exhaustiveCheck = expr;
|
|
433
445
|
throw new Error(`Unknown expression type: ${JSON.stringify(_exhaustiveCheck)}`);
|
|
@@ -593,15 +605,24 @@ async function executeAction(action, ctx) {
|
|
|
593
605
|
const extAction = action;
|
|
594
606
|
const isLocal = extAction._isLocalAction && extAction._localStore;
|
|
595
607
|
const localStore = extAction._localStore;
|
|
608
|
+
const delayPromises = [];
|
|
596
609
|
for (const step of action.steps) {
|
|
597
610
|
if (step.do === "set" || step.do === "update" || step.do === "setPath") {
|
|
598
611
|
executeStepSync(step, ctx, isLocal ? localStore : void 0);
|
|
599
612
|
} else if (step.do === "if") {
|
|
600
613
|
await executeIfStep(step, ctx, isLocal ? localStore : void 0);
|
|
614
|
+
} else if (step.do === "delay") {
|
|
615
|
+
const delayPromise = executeDelayStep(step, ctx);
|
|
616
|
+
delayPromises.push(delayPromise);
|
|
617
|
+
} else if (step.do === "interval") {
|
|
618
|
+
await executeIntervalStep(step, ctx);
|
|
601
619
|
} else {
|
|
602
620
|
await executeStep(step, ctx);
|
|
603
621
|
}
|
|
604
622
|
}
|
|
623
|
+
if (delayPromises.length > 0) {
|
|
624
|
+
await Promise.all(delayPromises);
|
|
625
|
+
}
|
|
605
626
|
}
|
|
606
627
|
function executeStepSync(step, ctx, localStore) {
|
|
607
628
|
switch (step.do) {
|
|
@@ -892,6 +913,18 @@ async function executeStep(step, ctx) {
|
|
|
892
913
|
case "close":
|
|
893
914
|
await executeCloseStep(step, ctx);
|
|
894
915
|
break;
|
|
916
|
+
case "delay":
|
|
917
|
+
await executeDelayStep(step, ctx);
|
|
918
|
+
break;
|
|
919
|
+
case "interval":
|
|
920
|
+
await executeIntervalStep(step, ctx);
|
|
921
|
+
break;
|
|
922
|
+
case "clearTimer":
|
|
923
|
+
await executeClearTimerStep(step, ctx);
|
|
924
|
+
break;
|
|
925
|
+
case "focus":
|
|
926
|
+
await executeFocusStep(step, ctx);
|
|
927
|
+
break;
|
|
895
928
|
}
|
|
896
929
|
}
|
|
897
930
|
async function executeSetStep(target, value, ctx) {
|
|
@@ -1258,6 +1291,137 @@ async function executeCloseStep(step, ctx) {
|
|
|
1258
1291
|
if (!ctx.connections) return;
|
|
1259
1292
|
ctx.connections.close(step.connection);
|
|
1260
1293
|
}
|
|
1294
|
+
async function executeDelayStep(step, ctx) {
|
|
1295
|
+
const evalCtx = createEvalContext(ctx);
|
|
1296
|
+
const msValue = evaluate(step.ms, evalCtx);
|
|
1297
|
+
const ms = typeof msValue === "number" ? Math.max(0, msValue) : 0;
|
|
1298
|
+
return new Promise((resolve) => {
|
|
1299
|
+
let resolved = false;
|
|
1300
|
+
const timeoutId = setTimeout(async () => {
|
|
1301
|
+
if (resolved) return;
|
|
1302
|
+
resolved = true;
|
|
1303
|
+
for (const thenStep of step.then) {
|
|
1304
|
+
if (thenStep.do === "set" || thenStep.do === "update" || thenStep.do === "setPath") {
|
|
1305
|
+
executeStepSync(thenStep, ctx);
|
|
1306
|
+
} else if (thenStep.do === "if") {
|
|
1307
|
+
await executeIfStep(thenStep, ctx);
|
|
1308
|
+
} else {
|
|
1309
|
+
await executeStep(thenStep, ctx);
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
resolve();
|
|
1313
|
+
}, ms);
|
|
1314
|
+
const numericId = typeof timeoutId === "number" ? timeoutId : Number(timeoutId);
|
|
1315
|
+
if (step.result) {
|
|
1316
|
+
ctx.locals[step.result] = numericId;
|
|
1317
|
+
}
|
|
1318
|
+
if (!ctx.locals["_timerResolvers"]) {
|
|
1319
|
+
ctx.locals["_timerResolvers"] = /* @__PURE__ */ new Map();
|
|
1320
|
+
}
|
|
1321
|
+
ctx.locals["_timerResolvers"].set(numericId, () => {
|
|
1322
|
+
if (!resolved) {
|
|
1323
|
+
resolved = true;
|
|
1324
|
+
clearTimeout(timeoutId);
|
|
1325
|
+
resolve();
|
|
1326
|
+
}
|
|
1327
|
+
});
|
|
1328
|
+
if (ctx.cleanups) {
|
|
1329
|
+
ctx.cleanups.push(() => {
|
|
1330
|
+
if (!resolved) {
|
|
1331
|
+
resolved = true;
|
|
1332
|
+
clearTimeout(timeoutId);
|
|
1333
|
+
resolve();
|
|
1334
|
+
}
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
async function executeIntervalStep(step, ctx) {
|
|
1340
|
+
const evalCtx = createEvalContext(ctx);
|
|
1341
|
+
const msValue = evaluate(step.ms, evalCtx);
|
|
1342
|
+
const ms = typeof msValue === "number" ? Math.max(0, msValue) : 0;
|
|
1343
|
+
const intervalId = setInterval(async () => {
|
|
1344
|
+
const action = ctx.actions[step.action];
|
|
1345
|
+
if (action) {
|
|
1346
|
+
await executeAction(action, ctx);
|
|
1347
|
+
}
|
|
1348
|
+
}, ms);
|
|
1349
|
+
const numericId = typeof intervalId === "number" ? intervalId : Number(intervalId);
|
|
1350
|
+
if (step.result) {
|
|
1351
|
+
ctx.locals[step.result] = numericId;
|
|
1352
|
+
}
|
|
1353
|
+
if (ctx.cleanups) {
|
|
1354
|
+
ctx.cleanups.push(() => clearInterval(intervalId));
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
async function executeClearTimerStep(step, ctx) {
|
|
1358
|
+
const evalCtx = createEvalContext(ctx);
|
|
1359
|
+
const timerId = evaluate(step.target, evalCtx);
|
|
1360
|
+
if (timerId == null) {
|
|
1361
|
+
return;
|
|
1362
|
+
}
|
|
1363
|
+
const numericId = typeof timerId === "number" ? timerId : Number(timerId);
|
|
1364
|
+
const timerResolvers = ctx.locals["_timerResolvers"];
|
|
1365
|
+
if (timerResolvers?.has(numericId)) {
|
|
1366
|
+
const resolver = timerResolvers.get(numericId);
|
|
1367
|
+
if (resolver) {
|
|
1368
|
+
resolver();
|
|
1369
|
+
}
|
|
1370
|
+
timerResolvers.delete(numericId);
|
|
1371
|
+
}
|
|
1372
|
+
clearTimeout(timerId);
|
|
1373
|
+
clearInterval(timerId);
|
|
1374
|
+
}
|
|
1375
|
+
async function executeFocusStep(step, ctx) {
|
|
1376
|
+
const evalCtx = createEvalContext(ctx);
|
|
1377
|
+
const targetValue = evaluate(step.target, evalCtx);
|
|
1378
|
+
let element2;
|
|
1379
|
+
if (targetValue instanceof Element) {
|
|
1380
|
+
element2 = targetValue;
|
|
1381
|
+
} else if (typeof targetValue === "string") {
|
|
1382
|
+
element2 = ctx.refs?.[targetValue];
|
|
1383
|
+
}
|
|
1384
|
+
try {
|
|
1385
|
+
if (!element2) {
|
|
1386
|
+
const refName = typeof targetValue === "string" ? targetValue : "unknown";
|
|
1387
|
+
throw new Error(`Ref "${refName}" not found`);
|
|
1388
|
+
}
|
|
1389
|
+
switch (step.operation) {
|
|
1390
|
+
case "focus":
|
|
1391
|
+
if (typeof element2.focus === "function") {
|
|
1392
|
+
element2.focus();
|
|
1393
|
+
}
|
|
1394
|
+
break;
|
|
1395
|
+
case "blur":
|
|
1396
|
+
if (typeof element2.blur === "function") {
|
|
1397
|
+
element2.blur();
|
|
1398
|
+
}
|
|
1399
|
+
break;
|
|
1400
|
+
case "select":
|
|
1401
|
+
if (typeof element2.select === "function") {
|
|
1402
|
+
element2.select();
|
|
1403
|
+
} else {
|
|
1404
|
+
throw new Error(`Element does not support select operation`);
|
|
1405
|
+
}
|
|
1406
|
+
break;
|
|
1407
|
+
}
|
|
1408
|
+
if (step.onSuccess) {
|
|
1409
|
+
for (const successStep of step.onSuccess) {
|
|
1410
|
+
await executeStep(successStep, ctx);
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
} catch (err) {
|
|
1414
|
+
ctx.locals["error"] = {
|
|
1415
|
+
message: err instanceof Error ? err.message : String(err),
|
|
1416
|
+
name: err instanceof Error ? err.name : "Error"
|
|
1417
|
+
};
|
|
1418
|
+
if (step.onError) {
|
|
1419
|
+
for (const errorStep of step.onError) {
|
|
1420
|
+
await executeStep(errorStep, ctx);
|
|
1421
|
+
}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1261
1425
|
|
|
1262
1426
|
// ../../node_modules/.pnpm/marked@17.0.1/node_modules/marked/lib/marked.esm.js
|
|
1263
1427
|
function L() {
|
|
@@ -2691,14 +2855,14 @@ function createDOMPurify() {
|
|
|
2691
2855
|
DocumentFragment,
|
|
2692
2856
|
HTMLTemplateElement,
|
|
2693
2857
|
Node: Node2,
|
|
2694
|
-
Element,
|
|
2858
|
+
Element: Element2,
|
|
2695
2859
|
NodeFilter,
|
|
2696
2860
|
NamedNodeMap = window2.NamedNodeMap || window2.MozNamedAttrMap,
|
|
2697
2861
|
HTMLFormElement,
|
|
2698
2862
|
DOMParser,
|
|
2699
2863
|
trustedTypes
|
|
2700
2864
|
} = window2;
|
|
2701
|
-
const ElementPrototype =
|
|
2865
|
+
const ElementPrototype = Element2.prototype;
|
|
2702
2866
|
const cloneNode = lookupGetter(ElementPrototype, "cloneNode");
|
|
2703
2867
|
const remove = lookupGetter(ElementPrototype, "remove");
|
|
2704
2868
|
const getNextSibling = lookupGetter(ElementPrototype, "nextSibling");
|
|
@@ -3152,7 +3316,7 @@ function createDOMPurify() {
|
|
|
3152
3316
|
_forceRemove(currentNode);
|
|
3153
3317
|
return true;
|
|
3154
3318
|
}
|
|
3155
|
-
if (currentNode instanceof
|
|
3319
|
+
if (currentNode instanceof Element2 && !_checkValidNamespace(currentNode)) {
|
|
3156
3320
|
_forceRemove(currentNode);
|
|
3157
3321
|
return true;
|
|
3158
3322
|
}
|
|
@@ -13248,6 +13412,188 @@ function isSvgTag(tag) {
|
|
|
13248
13412
|
function isEventHandler(value) {
|
|
13249
13413
|
return typeof value === "object" && value !== null && "event" in value && "action" in value;
|
|
13250
13414
|
}
|
|
13415
|
+
function debounce(fn, wait, ctx) {
|
|
13416
|
+
let timeoutId = null;
|
|
13417
|
+
const debouncedFn = (event) => {
|
|
13418
|
+
if (timeoutId !== null) {
|
|
13419
|
+
clearTimeout(timeoutId);
|
|
13420
|
+
}
|
|
13421
|
+
timeoutId = setTimeout(() => {
|
|
13422
|
+
timeoutId = null;
|
|
13423
|
+
fn(event);
|
|
13424
|
+
}, wait);
|
|
13425
|
+
};
|
|
13426
|
+
ctx.cleanups?.push(() => {
|
|
13427
|
+
if (timeoutId !== null) {
|
|
13428
|
+
clearTimeout(timeoutId);
|
|
13429
|
+
timeoutId = null;
|
|
13430
|
+
}
|
|
13431
|
+
});
|
|
13432
|
+
return debouncedFn;
|
|
13433
|
+
}
|
|
13434
|
+
function throttle(fn, wait, ctx) {
|
|
13435
|
+
let lastTime = 0;
|
|
13436
|
+
let timeoutId = null;
|
|
13437
|
+
let lastEvent = null;
|
|
13438
|
+
const throttledFn = (event) => {
|
|
13439
|
+
const now = Date.now();
|
|
13440
|
+
const remaining = wait - (now - lastTime);
|
|
13441
|
+
if (remaining <= 0) {
|
|
13442
|
+
if (timeoutId !== null) {
|
|
13443
|
+
clearTimeout(timeoutId);
|
|
13444
|
+
timeoutId = null;
|
|
13445
|
+
}
|
|
13446
|
+
lastTime = now;
|
|
13447
|
+
fn(event);
|
|
13448
|
+
} else {
|
|
13449
|
+
lastEvent = event;
|
|
13450
|
+
if (timeoutId === null) {
|
|
13451
|
+
timeoutId = setTimeout(() => {
|
|
13452
|
+
timeoutId = null;
|
|
13453
|
+
lastTime = Date.now();
|
|
13454
|
+
if (lastEvent) {
|
|
13455
|
+
fn(lastEvent);
|
|
13456
|
+
lastEvent = null;
|
|
13457
|
+
}
|
|
13458
|
+
}, remaining);
|
|
13459
|
+
}
|
|
13460
|
+
}
|
|
13461
|
+
};
|
|
13462
|
+
ctx.cleanups?.push(() => {
|
|
13463
|
+
if (timeoutId !== null) {
|
|
13464
|
+
clearTimeout(timeoutId);
|
|
13465
|
+
timeoutId = null;
|
|
13466
|
+
}
|
|
13467
|
+
});
|
|
13468
|
+
return throttledFn;
|
|
13469
|
+
}
|
|
13470
|
+
function createEventCallback(handler, ctx) {
|
|
13471
|
+
return async (event) => {
|
|
13472
|
+
const action = ctx.actions[handler.action];
|
|
13473
|
+
if (!action) return;
|
|
13474
|
+
const eventLocals = {};
|
|
13475
|
+
const target = event.target;
|
|
13476
|
+
if (target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement) {
|
|
13477
|
+
eventLocals["value"] = target.value;
|
|
13478
|
+
if (target instanceof HTMLInputElement && target.type === "checkbox") {
|
|
13479
|
+
eventLocals["checked"] = target.checked;
|
|
13480
|
+
}
|
|
13481
|
+
if (target instanceof HTMLInputElement && target.type === "file") {
|
|
13482
|
+
eventLocals["files"] = Array.from(target.files || []).map((f) => ({
|
|
13483
|
+
name: f.name,
|
|
13484
|
+
size: f.size,
|
|
13485
|
+
type: f.type,
|
|
13486
|
+
_file: f
|
|
13487
|
+
}));
|
|
13488
|
+
}
|
|
13489
|
+
}
|
|
13490
|
+
if (event instanceof KeyboardEvent) {
|
|
13491
|
+
eventLocals["key"] = event.key;
|
|
13492
|
+
eventLocals["code"] = event.code;
|
|
13493
|
+
eventLocals["ctrlKey"] = event.ctrlKey;
|
|
13494
|
+
eventLocals["shiftKey"] = event.shiftKey;
|
|
13495
|
+
eventLocals["altKey"] = event.altKey;
|
|
13496
|
+
eventLocals["metaKey"] = event.metaKey;
|
|
13497
|
+
}
|
|
13498
|
+
if (event instanceof MouseEvent) {
|
|
13499
|
+
eventLocals["clientX"] = event.clientX;
|
|
13500
|
+
eventLocals["clientY"] = event.clientY;
|
|
13501
|
+
eventLocals["pageX"] = event.pageX;
|
|
13502
|
+
eventLocals["pageY"] = event.pageY;
|
|
13503
|
+
eventLocals["button"] = event.button;
|
|
13504
|
+
}
|
|
13505
|
+
const touchEvent = event;
|
|
13506
|
+
if (touchEvent.touches && touchEvent.changedTouches) {
|
|
13507
|
+
eventLocals["touches"] = Array.from(touchEvent.touches).map((t) => ({
|
|
13508
|
+
clientX: t.clientX,
|
|
13509
|
+
clientY: t.clientY,
|
|
13510
|
+
pageX: t.pageX,
|
|
13511
|
+
pageY: t.pageY
|
|
13512
|
+
}));
|
|
13513
|
+
eventLocals["changedTouches"] = Array.from(touchEvent.changedTouches).map((t) => ({
|
|
13514
|
+
clientX: t.clientX,
|
|
13515
|
+
clientY: t.clientY,
|
|
13516
|
+
pageX: t.pageX,
|
|
13517
|
+
pageY: t.pageY
|
|
13518
|
+
}));
|
|
13519
|
+
}
|
|
13520
|
+
if (handler.event === "scroll" && event.target instanceof Element) {
|
|
13521
|
+
eventLocals["scrollTop"] = event.target.scrollTop;
|
|
13522
|
+
eventLocals["scrollLeft"] = event.target.scrollLeft;
|
|
13523
|
+
}
|
|
13524
|
+
let payload = void 0;
|
|
13525
|
+
if (handler.payload) {
|
|
13526
|
+
payload = evaluatePayload(handler.payload, {
|
|
13527
|
+
state: ctx.state,
|
|
13528
|
+
locals: { ...ctx.locals, ...eventLocals },
|
|
13529
|
+
...ctx.imports && { imports: ctx.imports }
|
|
13530
|
+
});
|
|
13531
|
+
}
|
|
13532
|
+
const actionCtx = {
|
|
13533
|
+
state: ctx.state,
|
|
13534
|
+
actions: ctx.actions,
|
|
13535
|
+
locals: { ...ctx.locals, ...eventLocals, payload },
|
|
13536
|
+
eventPayload: payload
|
|
13537
|
+
};
|
|
13538
|
+
await executeAction(action, actionCtx);
|
|
13539
|
+
};
|
|
13540
|
+
}
|
|
13541
|
+
function wrapWithDebounceThrottle(callback, handler, ctx) {
|
|
13542
|
+
if (handler.debounce !== void 0 && handler.debounce >= 0) {
|
|
13543
|
+
return debounce(callback, handler.debounce, ctx);
|
|
13544
|
+
}
|
|
13545
|
+
if (handler.throttle !== void 0 && handler.throttle >= 0) {
|
|
13546
|
+
return throttle(callback, handler.throttle, ctx);
|
|
13547
|
+
}
|
|
13548
|
+
return callback;
|
|
13549
|
+
}
|
|
13550
|
+
function setupIntersectionObserver(el, handler, ctx) {
|
|
13551
|
+
const options = {};
|
|
13552
|
+
if (handler.options?.threshold !== void 0) {
|
|
13553
|
+
options.threshold = handler.options.threshold;
|
|
13554
|
+
}
|
|
13555
|
+
if (handler.options?.rootMargin !== void 0) {
|
|
13556
|
+
options.rootMargin = handler.options.rootMargin;
|
|
13557
|
+
}
|
|
13558
|
+
let hasTriggered = false;
|
|
13559
|
+
const observer = new IntersectionObserver((entries2) => {
|
|
13560
|
+
for (const entry of entries2) {
|
|
13561
|
+
if (entry.target !== el) continue;
|
|
13562
|
+
if (handler.options?.once && hasTriggered) {
|
|
13563
|
+
continue;
|
|
13564
|
+
}
|
|
13565
|
+
const action = ctx.actions[handler.action];
|
|
13566
|
+
if (!action) continue;
|
|
13567
|
+
const intersectLocals = {
|
|
13568
|
+
isIntersecting: entry.isIntersecting,
|
|
13569
|
+
intersectionRatio: entry.intersectionRatio
|
|
13570
|
+
};
|
|
13571
|
+
let payload = void 0;
|
|
13572
|
+
if (handler.payload) {
|
|
13573
|
+
payload = evaluatePayload(handler.payload, {
|
|
13574
|
+
state: ctx.state,
|
|
13575
|
+
locals: { ...ctx.locals, ...intersectLocals },
|
|
13576
|
+
...ctx.imports && { imports: ctx.imports }
|
|
13577
|
+
});
|
|
13578
|
+
}
|
|
13579
|
+
const actionCtx = {
|
|
13580
|
+
state: ctx.state,
|
|
13581
|
+
actions: ctx.actions,
|
|
13582
|
+
locals: { ...ctx.locals, ...intersectLocals, payload },
|
|
13583
|
+
eventPayload: payload
|
|
13584
|
+
};
|
|
13585
|
+
executeAction(action, actionCtx);
|
|
13586
|
+
if (handler.options?.once) {
|
|
13587
|
+
hasTriggered = true;
|
|
13588
|
+
observer.unobserve(el);
|
|
13589
|
+
}
|
|
13590
|
+
}
|
|
13591
|
+
}, options);
|
|
13592
|
+
observer.observe(el);
|
|
13593
|
+
ctx.cleanups?.push(() => {
|
|
13594
|
+
observer.disconnect();
|
|
13595
|
+
});
|
|
13596
|
+
}
|
|
13251
13597
|
function render(node, ctx) {
|
|
13252
13598
|
switch (node.kind) {
|
|
13253
13599
|
case "element":
|
|
@@ -13262,6 +13608,8 @@ function render(node, ctx) {
|
|
|
13262
13608
|
return renderMarkdown(node, ctx);
|
|
13263
13609
|
case "code":
|
|
13264
13610
|
return renderCode(node, ctx);
|
|
13611
|
+
case "portal":
|
|
13612
|
+
return renderPortal(node, ctx);
|
|
13265
13613
|
case "localState":
|
|
13266
13614
|
return renderLocalState(node, ctx);
|
|
13267
13615
|
default:
|
|
@@ -13284,34 +13632,13 @@ function renderElement(node, ctx) {
|
|
|
13284
13632
|
if (isEventHandler(propValue)) {
|
|
13285
13633
|
const handler = propValue;
|
|
13286
13634
|
const eventName = handler.event;
|
|
13287
|
-
|
|
13288
|
-
|
|
13289
|
-
|
|
13290
|
-
|
|
13291
|
-
|
|
13292
|
-
|
|
13293
|
-
|
|
13294
|
-
if (target instanceof HTMLInputElement && target.type === "checkbox") {
|
|
13295
|
-
eventLocals["checked"] = target.checked;
|
|
13296
|
-
}
|
|
13297
|
-
}
|
|
13298
|
-
let payload = void 0;
|
|
13299
|
-
if (handler.payload) {
|
|
13300
|
-
payload = evaluatePayload(handler.payload, {
|
|
13301
|
-
state: ctx.state,
|
|
13302
|
-
locals: { ...ctx.locals, ...eventLocals },
|
|
13303
|
-
...ctx.imports && { imports: ctx.imports }
|
|
13304
|
-
});
|
|
13305
|
-
}
|
|
13306
|
-
const actionCtx = {
|
|
13307
|
-
state: ctx.state,
|
|
13308
|
-
actions: ctx.actions,
|
|
13309
|
-
locals: { ...ctx.locals, ...eventLocals, payload },
|
|
13310
|
-
eventPayload: payload
|
|
13311
|
-
};
|
|
13312
|
-
await executeAction(action, actionCtx);
|
|
13313
|
-
}
|
|
13314
|
-
});
|
|
13635
|
+
if (eventName === "intersect") {
|
|
13636
|
+
setupIntersectionObserver(el, handler, ctx);
|
|
13637
|
+
} else {
|
|
13638
|
+
const eventCallback = createEventCallback(handler, ctx);
|
|
13639
|
+
const wrappedCallback = wrapWithDebounceThrottle(eventCallback, handler, ctx);
|
|
13640
|
+
el.addEventListener(eventName, wrappedCallback);
|
|
13641
|
+
}
|
|
13315
13642
|
} else {
|
|
13316
13643
|
const cleanup = createEffect(() => {
|
|
13317
13644
|
const value = evaluate(propValue, { state: ctx.state, locals: ctx.locals, ...ctx.imports && { imports: ctx.imports } });
|
|
@@ -13651,6 +13978,41 @@ function renderCode(node, ctx) {
|
|
|
13651
13978
|
ctx.cleanups?.push(cleanup);
|
|
13652
13979
|
return container;
|
|
13653
13980
|
}
|
|
13981
|
+
function renderPortal(node, ctx) {
|
|
13982
|
+
let targetElement = null;
|
|
13983
|
+
if (node.target === "body") {
|
|
13984
|
+
targetElement = document.body;
|
|
13985
|
+
} else if (node.target === "head") {
|
|
13986
|
+
targetElement = document.head;
|
|
13987
|
+
} else {
|
|
13988
|
+
targetElement = document.querySelector(node.target);
|
|
13989
|
+
}
|
|
13990
|
+
if (!targetElement) {
|
|
13991
|
+
return document.createComment("portal:target-not-found");
|
|
13992
|
+
}
|
|
13993
|
+
const portalContainer = document.createElement("div");
|
|
13994
|
+
portalContainer.setAttribute("data-portal", "true");
|
|
13995
|
+
portalContainer.style.display = "contents";
|
|
13996
|
+
const portalCleanups = [];
|
|
13997
|
+
const portalCtx = {
|
|
13998
|
+
...ctx,
|
|
13999
|
+
cleanups: portalCleanups
|
|
14000
|
+
};
|
|
14001
|
+
for (const child of node.children) {
|
|
14002
|
+
const childNode = render(child, portalCtx);
|
|
14003
|
+
portalContainer.appendChild(childNode);
|
|
14004
|
+
}
|
|
14005
|
+
targetElement.appendChild(portalContainer);
|
|
14006
|
+
ctx.cleanups?.push(() => {
|
|
14007
|
+
for (const cleanup of portalCleanups) {
|
|
14008
|
+
cleanup();
|
|
14009
|
+
}
|
|
14010
|
+
if (portalContainer.parentNode) {
|
|
14011
|
+
portalContainer.parentNode.removeChild(portalContainer);
|
|
14012
|
+
}
|
|
14013
|
+
});
|
|
14014
|
+
return document.createComment("portal");
|
|
14015
|
+
}
|
|
13654
14016
|
function createLocalStateStore(stateDefs) {
|
|
13655
14017
|
const signals = {};
|
|
13656
14018
|
for (const [name, def] of Object.entries(stateDefs)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constela/runtime",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"description": "Runtime DOM renderer for Constela UI framework",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"dompurify": "^3.3.1",
|
|
19
19
|
"marked": "^17.0.1",
|
|
20
20
|
"shiki": "^3.20.0",
|
|
21
|
-
"@constela/compiler": "0.
|
|
22
|
-
"@constela/core": "0.
|
|
21
|
+
"@constela/compiler": "0.11.0",
|
|
22
|
+
"@constela/core": "0.11.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/dompurify": "^3.2.0",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"tsup": "^8.0.0",
|
|
30
30
|
"typescript": "^5.3.0",
|
|
31
31
|
"vitest": "^2.0.0",
|
|
32
|
-
"@constela/server": "
|
|
32
|
+
"@constela/server": "7.0.0"
|
|
33
33
|
},
|
|
34
34
|
"engines": {
|
|
35
35
|
"node": ">=20.0.0"
|