@servlyadmin/runtime-core 0.1.6 → 0.1.8
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/chunk-IWFVKY5N.js +154 -0
- package/dist/index.cjs +2136 -160
- package/dist/index.d.cts +631 -2
- package/dist/index.d.ts +631 -2
- package/dist/index.js +1955 -178
- package/dist/tailwind-CGAHPC3O.js +24 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_SERVLY_TAILWIND_CONFIG,
|
|
3
|
+
addCustomStyles,
|
|
4
|
+
getTailwind,
|
|
5
|
+
initServlyTailwind,
|
|
6
|
+
injectTailwind,
|
|
7
|
+
isTailwindLoaded,
|
|
8
|
+
removeCustomStyles,
|
|
9
|
+
removeTailwind,
|
|
10
|
+
updateTailwindConfig
|
|
11
|
+
} from "./chunk-IWFVKY5N.js";
|
|
1
12
|
import {
|
|
2
13
|
buildRegistryFromBundle,
|
|
3
14
|
collectAllDependencies,
|
|
@@ -526,16 +537,95 @@ var BINDING_SOURCES = [
|
|
|
526
537
|
"input",
|
|
527
538
|
"currentItem",
|
|
528
539
|
"localStore",
|
|
540
|
+
"localStorage",
|
|
541
|
+
"sessionStorage",
|
|
529
542
|
"config",
|
|
530
543
|
"element",
|
|
531
544
|
"self",
|
|
532
545
|
"params",
|
|
533
|
-
"query"
|
|
546
|
+
"query",
|
|
547
|
+
"window",
|
|
548
|
+
"bindings",
|
|
549
|
+
"binding",
|
|
550
|
+
"boundInputs",
|
|
551
|
+
"parent"
|
|
534
552
|
];
|
|
535
553
|
var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
|
|
536
554
|
function hasTemplateSyntax(value) {
|
|
537
555
|
return typeof value === "string" && value.includes("{{") && value.includes("}}");
|
|
538
556
|
}
|
|
557
|
+
function getLocalStorageValue(key) {
|
|
558
|
+
if (typeof localStorage === "undefined") return void 0;
|
|
559
|
+
try {
|
|
560
|
+
const stored = localStorage.getItem(key);
|
|
561
|
+
if (stored === null) return void 0;
|
|
562
|
+
try {
|
|
563
|
+
return JSON.parse(stored);
|
|
564
|
+
} catch {
|
|
565
|
+
return stored;
|
|
566
|
+
}
|
|
567
|
+
} catch {
|
|
568
|
+
return void 0;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
function getSessionStorageValue(key) {
|
|
572
|
+
if (typeof sessionStorage === "undefined") return void 0;
|
|
573
|
+
try {
|
|
574
|
+
const stored = sessionStorage.getItem(key);
|
|
575
|
+
if (stored === null) return void 0;
|
|
576
|
+
try {
|
|
577
|
+
return JSON.parse(stored);
|
|
578
|
+
} catch {
|
|
579
|
+
return stored;
|
|
580
|
+
}
|
|
581
|
+
} catch {
|
|
582
|
+
return void 0;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
function getWindowInfo() {
|
|
586
|
+
if (typeof window === "undefined") return {};
|
|
587
|
+
const searchParams = {};
|
|
588
|
+
try {
|
|
589
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
590
|
+
urlSearchParams.forEach((value, key) => {
|
|
591
|
+
searchParams[key] = value;
|
|
592
|
+
});
|
|
593
|
+
} catch {
|
|
594
|
+
}
|
|
595
|
+
return {
|
|
596
|
+
href: window.location.href,
|
|
597
|
+
pathname: window.location.pathname,
|
|
598
|
+
search: window.location.search,
|
|
599
|
+
hash: window.location.hash,
|
|
600
|
+
origin: window.location.origin,
|
|
601
|
+
protocol: window.location.protocol,
|
|
602
|
+
host: window.location.host,
|
|
603
|
+
hostname: window.location.hostname,
|
|
604
|
+
port: window.location.port,
|
|
605
|
+
searchParams,
|
|
606
|
+
params: searchParams,
|
|
607
|
+
innerWidth: window.innerWidth,
|
|
608
|
+
innerHeight: window.innerHeight,
|
|
609
|
+
screenWidth: window.screen?.width,
|
|
610
|
+
screenHeight: window.screen?.height
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
function navigatePath(obj, parts) {
|
|
614
|
+
let current = obj;
|
|
615
|
+
for (const part of parts) {
|
|
616
|
+
if (current === null || current === void 0) return void 0;
|
|
617
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
618
|
+
if (arrayMatch) {
|
|
619
|
+
const [, propName, indexStr] = arrayMatch;
|
|
620
|
+
current = current[propName];
|
|
621
|
+
if (!Array.isArray(current)) return void 0;
|
|
622
|
+
current = current[parseInt(indexStr, 10)];
|
|
623
|
+
} else {
|
|
624
|
+
current = current[part];
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
return current;
|
|
628
|
+
}
|
|
539
629
|
function resolveBindingPath(path, context) {
|
|
540
630
|
const trimmed = path.trim();
|
|
541
631
|
const parts = trimmed.split(".");
|
|
@@ -543,17 +633,70 @@ function resolveBindingPath(path, context) {
|
|
|
543
633
|
return void 0;
|
|
544
634
|
}
|
|
545
635
|
const prefix = parts[0].toLowerCase();
|
|
636
|
+
if (prefix === "localstore" || prefix === "localstorage") {
|
|
637
|
+
if (parts.length === 1) {
|
|
638
|
+
const all = {};
|
|
639
|
+
if (typeof localStorage !== "undefined") {
|
|
640
|
+
for (let i = 0; i < localStorage.length; i++) {
|
|
641
|
+
const key2 = localStorage.key(i);
|
|
642
|
+
if (key2) {
|
|
643
|
+
all[key2] = getLocalStorageValue(key2);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return all;
|
|
648
|
+
}
|
|
649
|
+
const key = parts[1];
|
|
650
|
+
const value = getLocalStorageValue(key);
|
|
651
|
+
if (parts.length === 2) return value;
|
|
652
|
+
return navigatePath(value, parts.slice(2));
|
|
653
|
+
}
|
|
654
|
+
if (prefix === "sessionstorage") {
|
|
655
|
+
if (parts.length === 1) {
|
|
656
|
+
const all = {};
|
|
657
|
+
if (typeof sessionStorage !== "undefined") {
|
|
658
|
+
for (let i = 0; i < sessionStorage.length; i++) {
|
|
659
|
+
const key2 = sessionStorage.key(i);
|
|
660
|
+
if (key2) {
|
|
661
|
+
all[key2] = getSessionStorageValue(key2);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return all;
|
|
666
|
+
}
|
|
667
|
+
const key = parts[1];
|
|
668
|
+
const value = getSessionStorageValue(key);
|
|
669
|
+
if (parts.length === 2) return value;
|
|
670
|
+
return navigatePath(value, parts.slice(2));
|
|
671
|
+
}
|
|
672
|
+
if (prefix === "window" || prefix === "url") {
|
|
673
|
+
const windowInfo = getWindowInfo();
|
|
674
|
+
if (parts.length === 1) return windowInfo;
|
|
675
|
+
return navigatePath(windowInfo, parts.slice(1));
|
|
676
|
+
}
|
|
677
|
+
if (prefix === "params" || prefix === "query") {
|
|
678
|
+
const windowInfo = getWindowInfo();
|
|
679
|
+
const params = windowInfo.searchParams || {};
|
|
680
|
+
if (parts.length === 1) return params;
|
|
681
|
+
return navigatePath(params, parts.slice(1));
|
|
682
|
+
}
|
|
546
683
|
let source;
|
|
547
684
|
let startIndex = 0;
|
|
548
|
-
if (prefix === "props" || prefix === "input") {
|
|
685
|
+
if (prefix === "props" || prefix === "input" || prefix === "bindings" || prefix === "binding" || prefix === "boundinputs" || prefix === "parent") {
|
|
549
686
|
source = context.props;
|
|
550
687
|
startIndex = 1;
|
|
551
688
|
} else if (prefix === "state" || prefix === "appstate") {
|
|
552
689
|
source = context.state;
|
|
553
690
|
startIndex = 1;
|
|
554
|
-
} else if (prefix === "context") {
|
|
691
|
+
} else if (prefix === "context" || prefix === "config") {
|
|
555
692
|
source = context.context;
|
|
556
693
|
startIndex = 1;
|
|
694
|
+
} else if (prefix === "currentitem") {
|
|
695
|
+
source = context.props;
|
|
696
|
+
startIndex = 0;
|
|
697
|
+
} else if (prefix === "self" || prefix === "element") {
|
|
698
|
+
source = context.state;
|
|
699
|
+
startIndex = 1;
|
|
557
700
|
} else if (BINDING_SOURCES.includes(prefix)) {
|
|
558
701
|
source = context.props;
|
|
559
702
|
startIndex = 1;
|
|
@@ -564,41 +707,49 @@ function resolveBindingPath(path, context) {
|
|
|
564
707
|
if (!source) {
|
|
565
708
|
return void 0;
|
|
566
709
|
}
|
|
567
|
-
|
|
568
|
-
for (let i = startIndex; i < parts.length; i++) {
|
|
569
|
-
if (value === null || value === void 0) {
|
|
570
|
-
return void 0;
|
|
571
|
-
}
|
|
572
|
-
value = value[parts[i]];
|
|
573
|
-
}
|
|
574
|
-
return value;
|
|
710
|
+
return navigatePath(source, parts.slice(startIndex));
|
|
575
711
|
}
|
|
576
712
|
function resolveExpression(expression, context) {
|
|
577
713
|
const trimmed = expression.trim();
|
|
578
|
-
const
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
714
|
+
const comparisonOperators = ["===", "!==", "==", "!=", ">=", "<=", ">", "<"];
|
|
715
|
+
for (const op of comparisonOperators) {
|
|
716
|
+
if (trimmed.includes(op)) {
|
|
717
|
+
const [left, right] = trimmed.split(op, 2);
|
|
718
|
+
const leftVal = resolveExpressionValue(left.trim(), context);
|
|
719
|
+
const rightVal = resolveExpressionValue(right.trim(), context);
|
|
720
|
+
switch (op) {
|
|
721
|
+
case "===":
|
|
722
|
+
return leftVal === rightVal;
|
|
723
|
+
case "!==":
|
|
724
|
+
return leftVal !== rightVal;
|
|
725
|
+
case "==":
|
|
726
|
+
return leftVal == rightVal;
|
|
727
|
+
case "!=":
|
|
728
|
+
return leftVal != rightVal;
|
|
729
|
+
case ">":
|
|
730
|
+
return leftVal > rightVal;
|
|
731
|
+
case "<":
|
|
732
|
+
return leftVal < rightVal;
|
|
733
|
+
case ">=":
|
|
734
|
+
return leftVal >= rightVal;
|
|
735
|
+
case "<=":
|
|
736
|
+
return leftVal <= rightVal;
|
|
737
|
+
}
|
|
590
738
|
}
|
|
591
|
-
if (defaultVal === "true") return true;
|
|
592
|
-
if (defaultVal === "false") return false;
|
|
593
|
-
return resolveExpression(defaultVal, context);
|
|
594
739
|
}
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
740
|
+
if (trimmed.startsWith("!") && !trimmed.startsWith("!=")) {
|
|
741
|
+
const innerValue = resolveExpression(trimmed.slice(1).trim(), context);
|
|
742
|
+
return !innerValue;
|
|
743
|
+
}
|
|
744
|
+
if (trimmed.includes("||")) {
|
|
745
|
+
const parts = trimmed.split("||");
|
|
746
|
+
for (let i = 0; i < parts.length; i++) {
|
|
747
|
+
const part = parts[i].trim();
|
|
748
|
+
const value = resolveExpressionValue(part, context);
|
|
749
|
+
if (value || i === parts.length - 1) {
|
|
750
|
+
return value;
|
|
751
|
+
}
|
|
600
752
|
}
|
|
601
|
-
return resolveTernaryValue(ternaryMatch[3].trim(), context);
|
|
602
753
|
}
|
|
603
754
|
if (trimmed.includes("&&")) {
|
|
604
755
|
const parts = trimmed.split("&&");
|
|
@@ -608,6 +759,28 @@ function resolveExpression(expression, context) {
|
|
|
608
759
|
}
|
|
609
760
|
return resolveExpression(parts[parts.length - 1].trim(), context);
|
|
610
761
|
}
|
|
762
|
+
const ternaryMatch = trimmed.match(/^(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/);
|
|
763
|
+
if (ternaryMatch) {
|
|
764
|
+
const condition = resolveExpression(ternaryMatch[1].trim(), context);
|
|
765
|
+
if (condition) {
|
|
766
|
+
return resolveTernaryValue(ternaryMatch[2].trim(), context);
|
|
767
|
+
}
|
|
768
|
+
return resolveTernaryValue(ternaryMatch[3].trim(), context);
|
|
769
|
+
}
|
|
770
|
+
return resolveExpressionValue(trimmed, context);
|
|
771
|
+
}
|
|
772
|
+
function resolveExpressionValue(value, context) {
|
|
773
|
+
const trimmed = value.trim();
|
|
774
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
775
|
+
return trimmed.slice(1, -1);
|
|
776
|
+
}
|
|
777
|
+
if (!isNaN(Number(trimmed)) && trimmed !== "") {
|
|
778
|
+
return Number(trimmed);
|
|
779
|
+
}
|
|
780
|
+
if (trimmed === "true") return true;
|
|
781
|
+
if (trimmed === "false") return false;
|
|
782
|
+
if (trimmed === "null") return null;
|
|
783
|
+
if (trimmed === "undefined") return void 0;
|
|
611
784
|
return resolveBindingPath(trimmed, context);
|
|
612
785
|
}
|
|
613
786
|
function resolveTernaryValue(value, context) {
|
|
@@ -639,7 +812,7 @@ function resolveTemplate(template, context, componentId) {
|
|
|
639
812
|
}
|
|
640
813
|
return String(value);
|
|
641
814
|
}
|
|
642
|
-
return template.replace(TEMPLATE_REGEX, (
|
|
815
|
+
return template.replace(TEMPLATE_REGEX, (_match, expression) => {
|
|
643
816
|
const value = resolveExpression(expression, context);
|
|
644
817
|
if (value === void 0 || value === null) {
|
|
645
818
|
return "";
|
|
@@ -1069,157 +1242,1206 @@ function resetLongTaskObserver() {
|
|
|
1069
1242
|
longTaskObserverInstance = null;
|
|
1070
1243
|
}
|
|
1071
1244
|
|
|
1072
|
-
// src/
|
|
1073
|
-
var
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
list: "ul",
|
|
1086
|
-
listItem: "li",
|
|
1087
|
-
heading: "h1",
|
|
1088
|
-
paragraph: "p",
|
|
1089
|
-
section: "section",
|
|
1090
|
-
article: "article",
|
|
1091
|
-
header: "header",
|
|
1092
|
-
footer: "footer",
|
|
1093
|
-
nav: "nav",
|
|
1094
|
-
aside: "aside",
|
|
1095
|
-
main: "main",
|
|
1096
|
-
span: "span",
|
|
1097
|
-
div: "div"
|
|
1098
|
-
};
|
|
1099
|
-
var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
|
|
1100
|
-
"input",
|
|
1101
|
-
"img",
|
|
1102
|
-
"br",
|
|
1103
|
-
"hr",
|
|
1104
|
-
"area",
|
|
1105
|
-
"base",
|
|
1106
|
-
"col",
|
|
1107
|
-
"embed",
|
|
1108
|
-
"link",
|
|
1109
|
-
"meta",
|
|
1110
|
-
"param",
|
|
1111
|
-
"source",
|
|
1112
|
-
"track",
|
|
1113
|
-
"wbr"
|
|
1114
|
-
]);
|
|
1115
|
-
function getElementTag(element) {
|
|
1116
|
-
const config = element.configuration;
|
|
1117
|
-
if (config?.tag) {
|
|
1118
|
-
return config.tag;
|
|
1245
|
+
// src/stateManager.ts
|
|
1246
|
+
var StateManager = class {
|
|
1247
|
+
constructor(config = {}) {
|
|
1248
|
+
this.state = {};
|
|
1249
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
1250
|
+
this.config = config;
|
|
1251
|
+
this.state = config.initialState || {};
|
|
1252
|
+
if (config.persistToLocalStorage && typeof localStorage !== "undefined") {
|
|
1253
|
+
this.loadFromLocalStorage();
|
|
1254
|
+
}
|
|
1255
|
+
if (config.onStateChange) {
|
|
1256
|
+
this.listeners.add(config.onStateChange);
|
|
1257
|
+
}
|
|
1119
1258
|
}
|
|
1120
|
-
|
|
1121
|
-
|
|
1259
|
+
/**
|
|
1260
|
+
* Get value by path from state
|
|
1261
|
+
*/
|
|
1262
|
+
get(path) {
|
|
1263
|
+
return getValueByPath(this.state, path);
|
|
1122
1264
|
}
|
|
1123
|
-
|
|
1124
|
-
|
|
1265
|
+
/**
|
|
1266
|
+
* Get the entire state object
|
|
1267
|
+
*/
|
|
1268
|
+
getState() {
|
|
1269
|
+
return { ...this.state };
|
|
1125
1270
|
}
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1271
|
+
/**
|
|
1272
|
+
* Set a value in state
|
|
1273
|
+
*/
|
|
1274
|
+
set(key, value, elementId) {
|
|
1275
|
+
const previousValue = this.get(key);
|
|
1276
|
+
setValueByPath(this.state, key, value);
|
|
1277
|
+
this.notifyChange({
|
|
1278
|
+
key,
|
|
1279
|
+
value,
|
|
1280
|
+
previousValue,
|
|
1281
|
+
operation: "set",
|
|
1282
|
+
elementId,
|
|
1283
|
+
timestamp: Date.now()
|
|
1284
|
+
});
|
|
1139
1285
|
}
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1286
|
+
/**
|
|
1287
|
+
* Merge an object into state at the given path
|
|
1288
|
+
*/
|
|
1289
|
+
merge(key, value, deep = false, elementId) {
|
|
1290
|
+
const previousValue = this.get(key);
|
|
1291
|
+
const currentValue = previousValue || {};
|
|
1292
|
+
const newValue = deep ? deepMerge(currentValue, value) : { ...currentValue, ...value };
|
|
1293
|
+
setValueByPath(this.state, key, newValue);
|
|
1294
|
+
this.notifyChange({
|
|
1295
|
+
key,
|
|
1296
|
+
value: newValue,
|
|
1297
|
+
previousValue,
|
|
1298
|
+
operation: "merge",
|
|
1299
|
+
elementId,
|
|
1300
|
+
timestamp: Date.now()
|
|
1301
|
+
});
|
|
1146
1302
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1303
|
+
/**
|
|
1304
|
+
* Delete a key from state
|
|
1305
|
+
*/
|
|
1306
|
+
delete(key, elementId) {
|
|
1307
|
+
const previousValue = this.get(key);
|
|
1308
|
+
deleteValueByPath(this.state, key);
|
|
1309
|
+
this.notifyChange({
|
|
1310
|
+
key,
|
|
1311
|
+
value: void 0,
|
|
1312
|
+
previousValue,
|
|
1313
|
+
operation: "delete",
|
|
1314
|
+
elementId,
|
|
1315
|
+
timestamp: Date.now()
|
|
1316
|
+
});
|
|
1152
1317
|
}
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
{
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1318
|
+
/**
|
|
1319
|
+
* Append to an array in state
|
|
1320
|
+
*/
|
|
1321
|
+
append(key, value, elementId) {
|
|
1322
|
+
const previousValue = this.get(key);
|
|
1323
|
+
const currentArray = Array.isArray(previousValue) ? [...previousValue] : [];
|
|
1324
|
+
currentArray.push(value);
|
|
1325
|
+
setValueByPath(this.state, key, currentArray);
|
|
1326
|
+
this.notifyChange({
|
|
1327
|
+
key,
|
|
1328
|
+
value: currentArray,
|
|
1329
|
+
previousValue,
|
|
1330
|
+
operation: "append",
|
|
1331
|
+
elementId,
|
|
1332
|
+
timestamp: Date.now()
|
|
1333
|
+
});
|
|
1334
|
+
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Prepend to an array in state
|
|
1337
|
+
*/
|
|
1338
|
+
prepend(key, value, elementId) {
|
|
1339
|
+
const previousValue = this.get(key);
|
|
1340
|
+
const currentArray = Array.isArray(previousValue) ? [...previousValue] : [];
|
|
1341
|
+
currentArray.unshift(value);
|
|
1342
|
+
setValueByPath(this.state, key, currentArray);
|
|
1343
|
+
this.notifyChange({
|
|
1344
|
+
key,
|
|
1345
|
+
value: currentArray,
|
|
1346
|
+
previousValue,
|
|
1347
|
+
operation: "prepend",
|
|
1348
|
+
elementId,
|
|
1349
|
+
timestamp: Date.now()
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
/**
|
|
1353
|
+
* Toggle a boolean value in state
|
|
1354
|
+
*/
|
|
1355
|
+
toggle(key, elementId) {
|
|
1356
|
+
const previousValue = this.get(key);
|
|
1357
|
+
const newValue = !previousValue;
|
|
1358
|
+
setValueByPath(this.state, key, newValue);
|
|
1359
|
+
this.notifyChange({
|
|
1360
|
+
key,
|
|
1361
|
+
value: newValue,
|
|
1362
|
+
previousValue,
|
|
1363
|
+
operation: "toggle",
|
|
1364
|
+
elementId,
|
|
1365
|
+
timestamp: Date.now()
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Subscribe to state changes
|
|
1370
|
+
*/
|
|
1371
|
+
subscribe(listener) {
|
|
1372
|
+
this.listeners.add(listener);
|
|
1373
|
+
return () => this.listeners.delete(listener);
|
|
1374
|
+
}
|
|
1375
|
+
/**
|
|
1376
|
+
* Notify all listeners of a state change
|
|
1377
|
+
*/
|
|
1378
|
+
notifyChange(event) {
|
|
1379
|
+
if (this.config.persistToLocalStorage) {
|
|
1380
|
+
this.saveToLocalStorage();
|
|
1381
|
+
}
|
|
1382
|
+
for (const listener of this.listeners) {
|
|
1383
|
+
try {
|
|
1384
|
+
listener(event);
|
|
1385
|
+
} catch (error) {
|
|
1386
|
+
console.error("State change listener error:", error);
|
|
1174
1387
|
}
|
|
1175
|
-
continue;
|
|
1176
1388
|
}
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1389
|
+
}
|
|
1390
|
+
/**
|
|
1391
|
+
* Load state from localStorage
|
|
1392
|
+
*/
|
|
1393
|
+
loadFromLocalStorage() {
|
|
1394
|
+
try {
|
|
1395
|
+
const prefix = this.config.localStoragePrefix || "servly_state_";
|
|
1396
|
+
const stored = localStorage.getItem(`${prefix}state`);
|
|
1397
|
+
if (stored) {
|
|
1398
|
+
const parsed = JSON.parse(stored);
|
|
1399
|
+
this.state = { ...this.state, ...parsed };
|
|
1182
1400
|
}
|
|
1401
|
+
} catch (error) {
|
|
1402
|
+
console.warn("Failed to load state from localStorage:", error);
|
|
1183
1403
|
}
|
|
1184
1404
|
}
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1405
|
+
/**
|
|
1406
|
+
* Save state to localStorage
|
|
1407
|
+
*/
|
|
1408
|
+
saveToLocalStorage() {
|
|
1409
|
+
try {
|
|
1410
|
+
const prefix = this.config.localStoragePrefix || "servly_state_";
|
|
1411
|
+
localStorage.setItem(`${prefix}state`, JSON.stringify(this.state));
|
|
1412
|
+
} catch (error) {
|
|
1413
|
+
console.warn("Failed to save state to localStorage:", error);
|
|
1192
1414
|
}
|
|
1193
1415
|
}
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1416
|
+
/**
|
|
1417
|
+
* Clear all state
|
|
1418
|
+
*/
|
|
1419
|
+
clear() {
|
|
1420
|
+
const previousState = { ...this.state };
|
|
1421
|
+
this.state = {};
|
|
1422
|
+
if (this.config.persistToLocalStorage) {
|
|
1423
|
+
try {
|
|
1424
|
+
const prefix = this.config.localStoragePrefix || "servly_state_";
|
|
1425
|
+
localStorage.removeItem(`${prefix}state`);
|
|
1426
|
+
} catch (error) {
|
|
1427
|
+
console.warn("Failed to clear localStorage:", error);
|
|
1428
|
+
}
|
|
1198
1429
|
}
|
|
1430
|
+
this.notifyChange({
|
|
1431
|
+
key: "",
|
|
1432
|
+
value: {},
|
|
1433
|
+
previousValue: previousState,
|
|
1434
|
+
operation: "delete",
|
|
1435
|
+
timestamp: Date.now()
|
|
1436
|
+
});
|
|
1199
1437
|
}
|
|
1200
|
-
}
|
|
1201
|
-
function
|
|
1202
|
-
if (
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1438
|
+
};
|
|
1439
|
+
function getValueByPath(obj, path) {
|
|
1440
|
+
if (!obj || !path) return void 0;
|
|
1441
|
+
const parts = path.split(".");
|
|
1442
|
+
let current = obj;
|
|
1443
|
+
for (const part of parts) {
|
|
1444
|
+
if (current === null || current === void 0) return void 0;
|
|
1445
|
+
const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
|
|
1446
|
+
if (arrayMatch) {
|
|
1447
|
+
const [, propName, indexStr] = arrayMatch;
|
|
1448
|
+
current = current[propName];
|
|
1449
|
+
if (!Array.isArray(current)) return void 0;
|
|
1450
|
+
current = current[parseInt(indexStr, 10)];
|
|
1451
|
+
} else {
|
|
1452
|
+
current = current[part];
|
|
1210
1453
|
}
|
|
1211
|
-
|
|
1212
|
-
|
|
1454
|
+
}
|
|
1455
|
+
return current;
|
|
1456
|
+
}
|
|
1457
|
+
function setValueByPath(obj, path, value) {
|
|
1458
|
+
if (!obj || !path) return;
|
|
1459
|
+
const parts = path.split(".");
|
|
1460
|
+
let current = obj;
|
|
1461
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1462
|
+
const part = parts[i];
|
|
1463
|
+
const arrayMatch2 = part.match(/^(\w+)\[(\d+)\]$/);
|
|
1464
|
+
if (arrayMatch2) {
|
|
1465
|
+
const [, propName, indexStr] = arrayMatch2;
|
|
1466
|
+
if (!current[propName]) current[propName] = [];
|
|
1467
|
+
const index = parseInt(indexStr, 10);
|
|
1468
|
+
if (!current[propName][index]) current[propName][index] = {};
|
|
1469
|
+
current = current[propName][index];
|
|
1470
|
+
} else {
|
|
1471
|
+
if (!current[part]) current[part] = {};
|
|
1472
|
+
current = current[part];
|
|
1213
1473
|
}
|
|
1214
|
-
return void 0;
|
|
1215
1474
|
}
|
|
1216
|
-
|
|
1217
|
-
|
|
1475
|
+
const lastPart = parts[parts.length - 1];
|
|
1476
|
+
const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
|
|
1477
|
+
if (arrayMatch) {
|
|
1478
|
+
const [, propName, indexStr] = arrayMatch;
|
|
1479
|
+
if (!current[propName]) current[propName] = [];
|
|
1480
|
+
current[propName][parseInt(indexStr, 10)] = value;
|
|
1481
|
+
} else {
|
|
1482
|
+
current[lastPart] = value;
|
|
1218
1483
|
}
|
|
1219
|
-
return void 0;
|
|
1220
1484
|
}
|
|
1221
|
-
function
|
|
1222
|
-
|
|
1485
|
+
function deleteValueByPath(obj, path) {
|
|
1486
|
+
if (!obj || !path) return;
|
|
1487
|
+
const parts = path.split(".");
|
|
1488
|
+
let current = obj;
|
|
1489
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
1490
|
+
const part = parts[i];
|
|
1491
|
+
if (current[part] === void 0) return;
|
|
1492
|
+
current = current[part];
|
|
1493
|
+
}
|
|
1494
|
+
const lastPart = parts[parts.length - 1];
|
|
1495
|
+
delete current[lastPart];
|
|
1496
|
+
}
|
|
1497
|
+
function deepMerge(target, source) {
|
|
1498
|
+
if (!source) return target;
|
|
1499
|
+
if (!target) return source;
|
|
1500
|
+
const result = { ...target };
|
|
1501
|
+
for (const key of Object.keys(source)) {
|
|
1502
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key]) && target[key] && typeof target[key] === "object" && !Array.isArray(target[key])) {
|
|
1503
|
+
result[key] = deepMerge(target[key], source[key]);
|
|
1504
|
+
} else {
|
|
1505
|
+
result[key] = source[key];
|
|
1506
|
+
}
|
|
1507
|
+
}
|
|
1508
|
+
return result;
|
|
1509
|
+
}
|
|
1510
|
+
function addClass(currentClasses, classToAdd) {
|
|
1511
|
+
const classes = currentClasses.split(/\s+/).filter(Boolean);
|
|
1512
|
+
if (!classes.includes(classToAdd)) {
|
|
1513
|
+
classes.push(classToAdd);
|
|
1514
|
+
}
|
|
1515
|
+
return classes.join(" ");
|
|
1516
|
+
}
|
|
1517
|
+
function removeClass(currentClasses, classToRemove) {
|
|
1518
|
+
return currentClasses.split(/\s+/).filter((cls) => cls && cls !== classToRemove).join(" ");
|
|
1519
|
+
}
|
|
1520
|
+
function toggleClass(currentClasses, classToToggle) {
|
|
1521
|
+
const classes = currentClasses.split(/\s+/).filter(Boolean);
|
|
1522
|
+
const index = classes.indexOf(classToToggle);
|
|
1523
|
+
if (index > -1) {
|
|
1524
|
+
classes.splice(index, 1);
|
|
1525
|
+
} else {
|
|
1526
|
+
classes.push(classToToggle);
|
|
1527
|
+
}
|
|
1528
|
+
return classes.join(" ");
|
|
1529
|
+
}
|
|
1530
|
+
function hasClass(currentClasses, classToCheck) {
|
|
1531
|
+
return currentClasses.split(/\s+/).includes(classToCheck);
|
|
1532
|
+
}
|
|
1533
|
+
function getLocalStorage(key, defaultValue) {
|
|
1534
|
+
if (typeof localStorage === "undefined") return defaultValue;
|
|
1535
|
+
try {
|
|
1536
|
+
const stored = localStorage.getItem(key);
|
|
1537
|
+
if (stored === null) return defaultValue;
|
|
1538
|
+
return JSON.parse(stored);
|
|
1539
|
+
} catch {
|
|
1540
|
+
return localStorage.getItem(key) ?? defaultValue;
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
function setLocalStorage(key, value) {
|
|
1544
|
+
if (typeof localStorage === "undefined") return;
|
|
1545
|
+
try {
|
|
1546
|
+
localStorage.setItem(key, JSON.stringify(value));
|
|
1547
|
+
} catch (error) {
|
|
1548
|
+
console.warn("Failed to set localStorage:", error);
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
function removeLocalStorage(key) {
|
|
1552
|
+
if (typeof localStorage === "undefined") return;
|
|
1553
|
+
localStorage.removeItem(key);
|
|
1554
|
+
}
|
|
1555
|
+
function getSessionStorage(key, defaultValue) {
|
|
1556
|
+
if (typeof sessionStorage === "undefined") return defaultValue;
|
|
1557
|
+
try {
|
|
1558
|
+
const stored = sessionStorage.getItem(key);
|
|
1559
|
+
if (stored === null) return defaultValue;
|
|
1560
|
+
return JSON.parse(stored);
|
|
1561
|
+
} catch {
|
|
1562
|
+
return sessionStorage.getItem(key) ?? defaultValue;
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
function setSessionStorage(key, value) {
|
|
1566
|
+
if (typeof sessionStorage === "undefined") return;
|
|
1567
|
+
try {
|
|
1568
|
+
sessionStorage.setItem(key, JSON.stringify(value));
|
|
1569
|
+
} catch (error) {
|
|
1570
|
+
console.warn("Failed to set sessionStorage:", error);
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
function removeSessionStorage(key) {
|
|
1574
|
+
if (typeof sessionStorage === "undefined") return;
|
|
1575
|
+
sessionStorage.removeItem(key);
|
|
1576
|
+
}
|
|
1577
|
+
function navigateTo(url, options = {}) {
|
|
1578
|
+
if (typeof window === "undefined") return;
|
|
1579
|
+
const { replace = false, state, newTab = false } = options;
|
|
1580
|
+
if (newTab) {
|
|
1581
|
+
window.open(url, "_blank");
|
|
1582
|
+
return;
|
|
1583
|
+
}
|
|
1584
|
+
if (url.startsWith("http://") || url.startsWith("https://")) {
|
|
1585
|
+
if (replace) {
|
|
1586
|
+
window.location.replace(url);
|
|
1587
|
+
} else {
|
|
1588
|
+
window.location.href = url;
|
|
1589
|
+
}
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
if (url.startsWith("#")) {
|
|
1593
|
+
window.location.hash = url;
|
|
1594
|
+
return;
|
|
1595
|
+
}
|
|
1596
|
+
if (replace) {
|
|
1597
|
+
window.history.replaceState(state, "", url);
|
|
1598
|
+
} else {
|
|
1599
|
+
window.history.pushState(state, "", url);
|
|
1600
|
+
}
|
|
1601
|
+
window.dispatchEvent(new PopStateEvent("popstate", { state }));
|
|
1602
|
+
}
|
|
1603
|
+
function goBack() {
|
|
1604
|
+
if (typeof window === "undefined") return;
|
|
1605
|
+
window.history.back();
|
|
1606
|
+
}
|
|
1607
|
+
function goForward() {
|
|
1608
|
+
if (typeof window === "undefined") return;
|
|
1609
|
+
window.history.forward();
|
|
1610
|
+
}
|
|
1611
|
+
function getUrlInfo() {
|
|
1612
|
+
if (typeof window === "undefined") {
|
|
1613
|
+
return {
|
|
1614
|
+
href: "",
|
|
1615
|
+
pathname: "",
|
|
1616
|
+
search: "",
|
|
1617
|
+
hash: "",
|
|
1618
|
+
searchParams: {}
|
|
1619
|
+
};
|
|
1620
|
+
}
|
|
1621
|
+
const searchParams = {};
|
|
1622
|
+
const urlSearchParams = new URLSearchParams(window.location.search);
|
|
1623
|
+
urlSearchParams.forEach((value, key) => {
|
|
1624
|
+
searchParams[key] = value;
|
|
1625
|
+
});
|
|
1626
|
+
return {
|
|
1627
|
+
href: window.location.href,
|
|
1628
|
+
pathname: window.location.pathname,
|
|
1629
|
+
search: window.location.search,
|
|
1630
|
+
hash: window.location.hash,
|
|
1631
|
+
searchParams
|
|
1632
|
+
};
|
|
1633
|
+
}
|
|
1634
|
+
|
|
1635
|
+
// src/eventSystem.ts
|
|
1636
|
+
var builtInPlugins = {
|
|
1637
|
+
/**
|
|
1638
|
+
* Set state value
|
|
1639
|
+
* Mirrors: state-setState from actions.ts
|
|
1640
|
+
*/
|
|
1641
|
+
"state-setState": (action, ctx) => {
|
|
1642
|
+
const { stateConfig } = action.config || {};
|
|
1643
|
+
if (!stateConfig || !ctx.stateManager) return;
|
|
1644
|
+
const config = typeof stateConfig === "string" ? JSON.parse(stateConfig) : stateConfig;
|
|
1645
|
+
const { key, value, operation = "set" } = config;
|
|
1646
|
+
if (!key) return;
|
|
1647
|
+
switch (operation) {
|
|
1648
|
+
case "set":
|
|
1649
|
+
ctx.stateManager.set(key, value, ctx.elementId);
|
|
1650
|
+
break;
|
|
1651
|
+
case "merge":
|
|
1652
|
+
ctx.stateManager.merge(key, value, false, ctx.elementId);
|
|
1653
|
+
break;
|
|
1654
|
+
case "deepMerge":
|
|
1655
|
+
ctx.stateManager.merge(key, value, true, ctx.elementId);
|
|
1656
|
+
break;
|
|
1657
|
+
case "toggle":
|
|
1658
|
+
ctx.stateManager.toggle(key, ctx.elementId);
|
|
1659
|
+
break;
|
|
1660
|
+
case "append":
|
|
1661
|
+
ctx.stateManager.append(key, value, ctx.elementId);
|
|
1662
|
+
break;
|
|
1663
|
+
case "prepend":
|
|
1664
|
+
ctx.stateManager.prepend(key, value, ctx.elementId);
|
|
1665
|
+
break;
|
|
1666
|
+
case "delete":
|
|
1667
|
+
ctx.stateManager.delete(key, ctx.elementId);
|
|
1668
|
+
break;
|
|
1669
|
+
case "increment":
|
|
1670
|
+
const currentVal = ctx.stateManager.get(key) || 0;
|
|
1671
|
+
ctx.stateManager.set(key, currentVal + (value || 1), ctx.elementId);
|
|
1672
|
+
break;
|
|
1673
|
+
case "decrement":
|
|
1674
|
+
const currVal = ctx.stateManager.get(key) || 0;
|
|
1675
|
+
ctx.stateManager.set(key, currVal - (value || 1), ctx.elementId);
|
|
1676
|
+
break;
|
|
1677
|
+
}
|
|
1678
|
+
return { success: true, key, operation };
|
|
1679
|
+
},
|
|
1680
|
+
/**
|
|
1681
|
+
* Navigate to URL
|
|
1682
|
+
* Mirrors: navigateTo from actions.ts
|
|
1683
|
+
*/
|
|
1684
|
+
"navigateTo": (action, ctx) => {
|
|
1685
|
+
const { url, replace, newTab, state } = action.config || {};
|
|
1686
|
+
if (!url) return;
|
|
1687
|
+
navigateTo(url, { replace, newTab, state });
|
|
1688
|
+
return { success: true, url };
|
|
1689
|
+
},
|
|
1690
|
+
/**
|
|
1691
|
+
* Set localStorage value
|
|
1692
|
+
*/
|
|
1693
|
+
"localStorage-set": (action, ctx) => {
|
|
1694
|
+
const { key, value } = action.config || {};
|
|
1695
|
+
if (!key) return;
|
|
1696
|
+
setLocalStorage(key, value);
|
|
1697
|
+
return { success: true, key };
|
|
1698
|
+
},
|
|
1699
|
+
/**
|
|
1700
|
+
* Get localStorage value
|
|
1701
|
+
*/
|
|
1702
|
+
"localStorage-get": (action, ctx) => {
|
|
1703
|
+
const { key, defaultValue } = action.config || {};
|
|
1704
|
+
if (!key) return defaultValue;
|
|
1705
|
+
return getLocalStorage(key, defaultValue);
|
|
1706
|
+
},
|
|
1707
|
+
/**
|
|
1708
|
+
* Remove localStorage value
|
|
1709
|
+
*/
|
|
1710
|
+
"localStorage-remove": (action, ctx) => {
|
|
1711
|
+
const { key } = action.config || {};
|
|
1712
|
+
if (!key) return;
|
|
1713
|
+
if (typeof localStorage !== "undefined") {
|
|
1714
|
+
localStorage.removeItem(key);
|
|
1715
|
+
}
|
|
1716
|
+
return { success: true, key };
|
|
1717
|
+
},
|
|
1718
|
+
/**
|
|
1719
|
+
* Set sessionStorage value
|
|
1720
|
+
*/
|
|
1721
|
+
"sessionStorage-set": (action, ctx) => {
|
|
1722
|
+
const { key, value } = action.config || {};
|
|
1723
|
+
if (!key) return;
|
|
1724
|
+
setSessionStorage(key, value);
|
|
1725
|
+
return { success: true, key };
|
|
1726
|
+
},
|
|
1727
|
+
/**
|
|
1728
|
+
* Get sessionStorage value
|
|
1729
|
+
*/
|
|
1730
|
+
"sessionStorage-get": (action, ctx) => {
|
|
1731
|
+
const { key, defaultValue } = action.config || {};
|
|
1732
|
+
if (!key) return defaultValue;
|
|
1733
|
+
return getSessionStorage(key, defaultValue);
|
|
1734
|
+
},
|
|
1735
|
+
/**
|
|
1736
|
+
* Console log (for debugging)
|
|
1737
|
+
*/
|
|
1738
|
+
"console-log": (action, ctx) => {
|
|
1739
|
+
const { message, data } = action.config || {};
|
|
1740
|
+
console.log("[Servly]", message, data);
|
|
1741
|
+
return { success: true };
|
|
1742
|
+
},
|
|
1743
|
+
/**
|
|
1744
|
+
* Show alert
|
|
1745
|
+
*/
|
|
1746
|
+
"alert": (action, ctx) => {
|
|
1747
|
+
const { message } = action.config || {};
|
|
1748
|
+
if (typeof alert !== "undefined") {
|
|
1749
|
+
alert(message);
|
|
1750
|
+
}
|
|
1751
|
+
return { success: true };
|
|
1752
|
+
},
|
|
1753
|
+
/**
|
|
1754
|
+
* Copy to clipboard
|
|
1755
|
+
*/
|
|
1756
|
+
"clipboard-copy": async (action, ctx) => {
|
|
1757
|
+
const { text } = action.config || {};
|
|
1758
|
+
if (!text || typeof navigator === "undefined") return { success: false };
|
|
1759
|
+
try {
|
|
1760
|
+
await navigator.clipboard.writeText(text);
|
|
1761
|
+
return { success: true };
|
|
1762
|
+
} catch (error) {
|
|
1763
|
+
return { success: false, error };
|
|
1764
|
+
}
|
|
1765
|
+
},
|
|
1766
|
+
/**
|
|
1767
|
+
* Scroll to element
|
|
1768
|
+
*/
|
|
1769
|
+
"scrollTo": (action, ctx) => {
|
|
1770
|
+
const { selector, behavior = "smooth", block = "start" } = action.config || {};
|
|
1771
|
+
if (!selector || typeof document === "undefined") return;
|
|
1772
|
+
const element = document.querySelector(selector);
|
|
1773
|
+
if (element) {
|
|
1774
|
+
element.scrollIntoView({ behavior, block });
|
|
1775
|
+
return { success: true };
|
|
1776
|
+
}
|
|
1777
|
+
return { success: false, error: "Element not found" };
|
|
1778
|
+
},
|
|
1779
|
+
/**
|
|
1780
|
+
* Focus element
|
|
1781
|
+
*/
|
|
1782
|
+
"focus": (action, ctx) => {
|
|
1783
|
+
const { selector } = action.config || {};
|
|
1784
|
+
if (!selector || typeof document === "undefined") return;
|
|
1785
|
+
const element = document.querySelector(selector);
|
|
1786
|
+
if (element && typeof element.focus === "function") {
|
|
1787
|
+
element.focus();
|
|
1788
|
+
return { success: true };
|
|
1789
|
+
}
|
|
1790
|
+
return { success: false, error: "Element not found" };
|
|
1791
|
+
},
|
|
1792
|
+
/**
|
|
1793
|
+
* Blur element
|
|
1794
|
+
*/
|
|
1795
|
+
"blur": (action, ctx) => {
|
|
1796
|
+
const { selector } = action.config || {};
|
|
1797
|
+
if (!selector || typeof document === "undefined") return;
|
|
1798
|
+
const element = document.querySelector(selector);
|
|
1799
|
+
if (element && typeof element.blur === "function") {
|
|
1800
|
+
element.blur();
|
|
1801
|
+
return { success: true };
|
|
1802
|
+
}
|
|
1803
|
+
return { success: false, error: "Element not found" };
|
|
1804
|
+
},
|
|
1805
|
+
/**
|
|
1806
|
+
* Add class to element
|
|
1807
|
+
*/
|
|
1808
|
+
"addClass": (action, ctx) => {
|
|
1809
|
+
const { selector, className } = action.config || {};
|
|
1810
|
+
if (!selector || !className || typeof document === "undefined") return;
|
|
1811
|
+
const element = document.querySelector(selector);
|
|
1812
|
+
if (element) {
|
|
1813
|
+
element.classList.add(className);
|
|
1814
|
+
return { success: true };
|
|
1815
|
+
}
|
|
1816
|
+
return { success: false, error: "Element not found" };
|
|
1817
|
+
},
|
|
1818
|
+
/**
|
|
1819
|
+
* Remove class from element
|
|
1820
|
+
*/
|
|
1821
|
+
"removeClass": (action, ctx) => {
|
|
1822
|
+
const { selector, className } = action.config || {};
|
|
1823
|
+
if (!selector || !className || typeof document === "undefined") return;
|
|
1824
|
+
const element = document.querySelector(selector);
|
|
1825
|
+
if (element) {
|
|
1826
|
+
element.classList.remove(className);
|
|
1827
|
+
return { success: true };
|
|
1828
|
+
}
|
|
1829
|
+
return { success: false, error: "Element not found" };
|
|
1830
|
+
},
|
|
1831
|
+
/**
|
|
1832
|
+
* Toggle class on element
|
|
1833
|
+
*/
|
|
1834
|
+
"toggleClass": (action, ctx) => {
|
|
1835
|
+
const { selector, className } = action.config || {};
|
|
1836
|
+
if (!selector || !className || typeof document === "undefined") return;
|
|
1837
|
+
const element = document.querySelector(selector);
|
|
1838
|
+
if (element) {
|
|
1839
|
+
element.classList.toggle(className);
|
|
1840
|
+
return { success: true };
|
|
1841
|
+
}
|
|
1842
|
+
return { success: false, error: "Element not found" };
|
|
1843
|
+
},
|
|
1844
|
+
/**
|
|
1845
|
+
* Set element attribute
|
|
1846
|
+
*/
|
|
1847
|
+
"setAttribute": (action, ctx) => {
|
|
1848
|
+
const { selector, attribute, value } = action.config || {};
|
|
1849
|
+
if (!selector || !attribute || typeof document === "undefined") return;
|
|
1850
|
+
const element = document.querySelector(selector);
|
|
1851
|
+
if (element) {
|
|
1852
|
+
element.setAttribute(attribute, value);
|
|
1853
|
+
return { success: true };
|
|
1854
|
+
}
|
|
1855
|
+
return { success: false, error: "Element not found" };
|
|
1856
|
+
},
|
|
1857
|
+
/**
|
|
1858
|
+
* Remove element attribute
|
|
1859
|
+
*/
|
|
1860
|
+
"removeAttribute": (action, ctx) => {
|
|
1861
|
+
const { selector, attribute } = action.config || {};
|
|
1862
|
+
if (!selector || !attribute || typeof document === "undefined") return;
|
|
1863
|
+
const element = document.querySelector(selector);
|
|
1864
|
+
if (element) {
|
|
1865
|
+
element.removeAttribute(attribute);
|
|
1866
|
+
return { success: true };
|
|
1867
|
+
}
|
|
1868
|
+
return { success: false, error: "Element not found" };
|
|
1869
|
+
},
|
|
1870
|
+
/**
|
|
1871
|
+
* Dispatch custom event
|
|
1872
|
+
*/
|
|
1873
|
+
"dispatchEvent": (action, ctx) => {
|
|
1874
|
+
const { selector, eventName, detail } = action.config || {};
|
|
1875
|
+
if (!eventName || typeof document === "undefined") return;
|
|
1876
|
+
const target = selector ? document.querySelector(selector) : document;
|
|
1877
|
+
if (target) {
|
|
1878
|
+
const event = new CustomEvent(eventName, { detail, bubbles: true });
|
|
1879
|
+
target.dispatchEvent(event);
|
|
1880
|
+
return { success: true };
|
|
1881
|
+
}
|
|
1882
|
+
return { success: false, error: "Target not found" };
|
|
1883
|
+
},
|
|
1884
|
+
/**
|
|
1885
|
+
* Delay execution
|
|
1886
|
+
*/
|
|
1887
|
+
"delay": async (action, ctx) => {
|
|
1888
|
+
const { ms = 0 } = action.config || {};
|
|
1889
|
+
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
1890
|
+
return { success: true };
|
|
1891
|
+
},
|
|
1892
|
+
/**
|
|
1893
|
+
* Conditional execution
|
|
1894
|
+
*/
|
|
1895
|
+
"condition": (action, ctx) => {
|
|
1896
|
+
const { condition, thenActions, elseActions } = action.config || {};
|
|
1897
|
+
return { condition, thenActions, elseActions };
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
var EventSystem = class {
|
|
1901
|
+
constructor(config = {}) {
|
|
1902
|
+
this.debounceTimers = /* @__PURE__ */ new Map();
|
|
1903
|
+
this.throttleTimers = /* @__PURE__ */ new Map();
|
|
1904
|
+
this.config = config;
|
|
1905
|
+
this.pluginExecutors = {
|
|
1906
|
+
...builtInPlugins,
|
|
1907
|
+
...config.pluginExecutors
|
|
1908
|
+
};
|
|
1909
|
+
}
|
|
1910
|
+
/**
|
|
1911
|
+
* Register a custom plugin executor
|
|
1912
|
+
*/
|
|
1913
|
+
registerPlugin(key, executor) {
|
|
1914
|
+
this.pluginExecutors[key] = executor;
|
|
1915
|
+
}
|
|
1916
|
+
/**
|
|
1917
|
+
* Create an event handler from Servly plugin format
|
|
1918
|
+
*/
|
|
1919
|
+
createHandler(elementId, handlerConfig, context, options = {}) {
|
|
1920
|
+
return (event) => {
|
|
1921
|
+
if (handlerConfig.preventDefault || options.preventDefault) {
|
|
1922
|
+
event.preventDefault();
|
|
1923
|
+
}
|
|
1924
|
+
if (handlerConfig.stopPropagation || options.stopPropagation) {
|
|
1925
|
+
event.stopPropagation();
|
|
1926
|
+
}
|
|
1927
|
+
if (this.config.onEvent) {
|
|
1928
|
+
this.config.onEvent(event.type, elementId, event);
|
|
1929
|
+
}
|
|
1930
|
+
if (handlerConfig.plugins && handlerConfig.plugins.length > 0) {
|
|
1931
|
+
this.executePlugins(handlerConfig.plugins, {
|
|
1932
|
+
event,
|
|
1933
|
+
elementId,
|
|
1934
|
+
context,
|
|
1935
|
+
stateManager: this.config.stateManager
|
|
1936
|
+
});
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
}
|
|
1940
|
+
/**
|
|
1941
|
+
* Execute a sequence of plugin actions
|
|
1942
|
+
*/
|
|
1943
|
+
async executePlugins(plugins, eventContext) {
|
|
1944
|
+
const results = [];
|
|
1945
|
+
for (const action of plugins) {
|
|
1946
|
+
try {
|
|
1947
|
+
const executor = this.pluginExecutors[action.key];
|
|
1948
|
+
if (executor) {
|
|
1949
|
+
const result = await executor(action, eventContext);
|
|
1950
|
+
results.push(result);
|
|
1951
|
+
if (this.config.onPluginExecute) {
|
|
1952
|
+
this.config.onPluginExecute(action, result);
|
|
1953
|
+
}
|
|
1954
|
+
} else {
|
|
1955
|
+
console.warn(`[EventSystem] Unknown plugin: ${action.key}`);
|
|
1956
|
+
results.push({ error: `Unknown plugin: ${action.key}` });
|
|
1957
|
+
}
|
|
1958
|
+
} catch (error) {
|
|
1959
|
+
console.error(`[EventSystem] Plugin error (${action.key}):`, error);
|
|
1960
|
+
results.push({ error });
|
|
1961
|
+
}
|
|
1962
|
+
}
|
|
1963
|
+
return results;
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Create a debounced event handler
|
|
1967
|
+
*/
|
|
1968
|
+
createDebouncedHandler(elementId, handler, delay) {
|
|
1969
|
+
const key = `${elementId}-debounce`;
|
|
1970
|
+
return (event) => {
|
|
1971
|
+
const existingTimer = this.debounceTimers.get(key);
|
|
1972
|
+
if (existingTimer) {
|
|
1973
|
+
clearTimeout(existingTimer);
|
|
1974
|
+
}
|
|
1975
|
+
const timer = setTimeout(() => {
|
|
1976
|
+
handler(event);
|
|
1977
|
+
this.debounceTimers.delete(key);
|
|
1978
|
+
}, delay);
|
|
1979
|
+
this.debounceTimers.set(key, timer);
|
|
1980
|
+
};
|
|
1981
|
+
}
|
|
1982
|
+
/**
|
|
1983
|
+
* Create a throttled event handler
|
|
1984
|
+
*/
|
|
1985
|
+
createThrottledHandler(elementId, handler, delay) {
|
|
1986
|
+
const key = `${elementId}-throttle`;
|
|
1987
|
+
return (event) => {
|
|
1988
|
+
if (this.throttleTimers.get(key)) {
|
|
1989
|
+
return;
|
|
1990
|
+
}
|
|
1991
|
+
handler(event);
|
|
1992
|
+
this.throttleTimers.set(key, true);
|
|
1993
|
+
setTimeout(() => {
|
|
1994
|
+
this.throttleTimers.delete(key);
|
|
1995
|
+
}, delay);
|
|
1996
|
+
};
|
|
1997
|
+
}
|
|
1998
|
+
/**
|
|
1999
|
+
* Clean up all timers
|
|
2000
|
+
*/
|
|
2001
|
+
destroy() {
|
|
2002
|
+
for (const timer of this.debounceTimers.values()) {
|
|
2003
|
+
clearTimeout(timer);
|
|
2004
|
+
}
|
|
2005
|
+
this.debounceTimers.clear();
|
|
2006
|
+
this.throttleTimers.clear();
|
|
2007
|
+
}
|
|
2008
|
+
};
|
|
2009
|
+
var EVENT_HANDLERS = {
|
|
2010
|
+
onClick: "click",
|
|
2011
|
+
onDoubleClick: "dblclick",
|
|
2012
|
+
onMouseDown: "mousedown",
|
|
2013
|
+
onMouseUp: "mouseup",
|
|
2014
|
+
onMouseEnter: "mouseenter",
|
|
2015
|
+
onMouseLeave: "mouseleave",
|
|
2016
|
+
onMouseMove: "mousemove",
|
|
2017
|
+
onMouseOver: "mouseover",
|
|
2018
|
+
onMouseOut: "mouseout",
|
|
2019
|
+
onKeyDown: "keydown",
|
|
2020
|
+
onKeyUp: "keyup",
|
|
2021
|
+
onKeyPress: "keypress",
|
|
2022
|
+
onFocus: "focus",
|
|
2023
|
+
onBlur: "blur",
|
|
2024
|
+
onChange: "change",
|
|
2025
|
+
onInput: "input",
|
|
2026
|
+
onSubmit: "submit",
|
|
2027
|
+
onReset: "reset",
|
|
2028
|
+
onScroll: "scroll",
|
|
2029
|
+
onWheel: "wheel",
|
|
2030
|
+
onDragStart: "dragstart",
|
|
2031
|
+
onDrag: "drag",
|
|
2032
|
+
onDragEnd: "dragend",
|
|
2033
|
+
onDragEnter: "dragenter",
|
|
2034
|
+
onDragLeave: "dragleave",
|
|
2035
|
+
onDragOver: "dragover",
|
|
2036
|
+
onDrop: "drop",
|
|
2037
|
+
onTouchStart: "touchstart",
|
|
2038
|
+
onTouchMove: "touchmove",
|
|
2039
|
+
onTouchEnd: "touchend",
|
|
2040
|
+
onTouchCancel: "touchcancel",
|
|
2041
|
+
onContextMenu: "contextmenu",
|
|
2042
|
+
onCopy: "copy",
|
|
2043
|
+
onCut: "cut",
|
|
2044
|
+
onPaste: "paste",
|
|
2045
|
+
onLoad: "load",
|
|
2046
|
+
onError: "error",
|
|
2047
|
+
onAnimationStart: "animationstart",
|
|
2048
|
+
onAnimationEnd: "animationend",
|
|
2049
|
+
onAnimationIteration: "animationiteration",
|
|
2050
|
+
onTransitionEnd: "transitionend"
|
|
2051
|
+
};
|
|
2052
|
+
function toDomEventName(reactEventName) {
|
|
2053
|
+
return EVENT_HANDLERS[reactEventName] || reactEventName.replace(/^on/, "").toLowerCase();
|
|
2054
|
+
}
|
|
2055
|
+
function toReactEventName(domEventName) {
|
|
2056
|
+
const entry = Object.entries(EVENT_HANDLERS).find(([, dom]) => dom === domEventName);
|
|
2057
|
+
return entry ? entry[0] : `on${domEventName.charAt(0).toUpperCase()}${domEventName.slice(1)}`;
|
|
2058
|
+
}
|
|
2059
|
+
var defaultEventSystem = null;
|
|
2060
|
+
function getEventSystem(config) {
|
|
2061
|
+
if (!defaultEventSystem || config) {
|
|
2062
|
+
defaultEventSystem = new EventSystem(config);
|
|
2063
|
+
}
|
|
2064
|
+
return defaultEventSystem;
|
|
2065
|
+
}
|
|
2066
|
+
function resetEventSystem() {
|
|
2067
|
+
if (defaultEventSystem) {
|
|
2068
|
+
defaultEventSystem.destroy();
|
|
2069
|
+
defaultEventSystem = null;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// src/overrides.ts
|
|
2074
|
+
var OverrideSystem = class {
|
|
2075
|
+
constructor(config = {}) {
|
|
2076
|
+
this.elementStates = /* @__PURE__ */ new Map();
|
|
2077
|
+
this.watchIntervals = /* @__PURE__ */ new Map();
|
|
2078
|
+
this.config = config;
|
|
2079
|
+
}
|
|
2080
|
+
/**
|
|
2081
|
+
* Get overrides from an element
|
|
2082
|
+
*/
|
|
2083
|
+
getOverrides(element) {
|
|
2084
|
+
const rawOverrides = element.configuration?._overrides_;
|
|
2085
|
+
if (!rawOverrides) return [];
|
|
2086
|
+
if (Array.isArray(rawOverrides)) {
|
|
2087
|
+
return rawOverrides.filter((o) => o && typeof o === "object");
|
|
2088
|
+
}
|
|
2089
|
+
if (typeof rawOverrides === "object") {
|
|
2090
|
+
console.warn("[OverrideSystem] Legacy object override format detected, ignoring");
|
|
2091
|
+
return [];
|
|
2092
|
+
}
|
|
2093
|
+
return [];
|
|
2094
|
+
}
|
|
2095
|
+
/**
|
|
2096
|
+
* Initialize overrides for an element (called on mount)
|
|
2097
|
+
*/
|
|
2098
|
+
async initializeElement(element, context) {
|
|
2099
|
+
const elementId = element.i;
|
|
2100
|
+
const overrides = this.getOverrides(element);
|
|
2101
|
+
if (overrides.length === 0) return;
|
|
2102
|
+
const state = {
|
|
2103
|
+
previousValues: /* @__PURE__ */ new Map(),
|
|
2104
|
+
initialized: false,
|
|
2105
|
+
abortController: new AbortController()
|
|
2106
|
+
};
|
|
2107
|
+
this.elementStates.set(elementId, state);
|
|
2108
|
+
const mountOverrides = overrides.filter((o) => !o.isCleanUp);
|
|
2109
|
+
overrides.forEach((override, index) => {
|
|
2110
|
+
if (override.isCleanUp) return;
|
|
2111
|
+
if (!override.dependencies || override.dependencies.length === 0) return;
|
|
2112
|
+
const initialValues = override.dependencies.map(
|
|
2113
|
+
(dep) => resolveTemplate(dep, context)
|
|
2114
|
+
);
|
|
2115
|
+
state.previousValues.set(index, initialValues);
|
|
2116
|
+
});
|
|
2117
|
+
await this.processOverrides(elementId, mountOverrides, context, "onMount");
|
|
2118
|
+
state.initialized = true;
|
|
2119
|
+
}
|
|
2120
|
+
/**
|
|
2121
|
+
* Check and process dependency changes for an element
|
|
2122
|
+
*/
|
|
2123
|
+
async checkDependencies(element, context) {
|
|
2124
|
+
const elementId = element.i;
|
|
2125
|
+
const overrides = this.getOverrides(element);
|
|
2126
|
+
const state = this.elementStates.get(elementId);
|
|
2127
|
+
if (!state || !state.initialized) return;
|
|
2128
|
+
const overridesToTrigger = [];
|
|
2129
|
+
overrides.forEach((override, index) => {
|
|
2130
|
+
if (override.isCleanUp) return;
|
|
2131
|
+
if (!override.dependencies || override.dependencies.length === 0) return;
|
|
2132
|
+
const currentValues = override.dependencies.map(
|
|
2133
|
+
(dep) => resolveTemplate(dep, context)
|
|
2134
|
+
);
|
|
2135
|
+
const previousValues = state.previousValues.get(index) || [];
|
|
2136
|
+
let hasChanged = false;
|
|
2137
|
+
if (previousValues.length !== currentValues.length) {
|
|
2138
|
+
hasChanged = true;
|
|
2139
|
+
} else {
|
|
2140
|
+
for (let i = 0; i < currentValues.length; i++) {
|
|
2141
|
+
if (JSON.stringify(previousValues[i]) !== JSON.stringify(currentValues[i])) {
|
|
2142
|
+
hasChanged = true;
|
|
2143
|
+
break;
|
|
2144
|
+
}
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
if (hasChanged) {
|
|
2148
|
+
overridesToTrigger.push(override);
|
|
2149
|
+
state.previousValues.set(index, currentValues);
|
|
2150
|
+
if (this.config.onDependencyChange) {
|
|
2151
|
+
this.config.onDependencyChange(elementId, override.dependencies, currentValues);
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
if (overridesToTrigger.length > 0) {
|
|
2156
|
+
await this.processOverrides(elementId, overridesToTrigger, context, "onDependencyChange");
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
/**
|
|
2160
|
+
* Cleanup overrides for an element (called on unmount)
|
|
2161
|
+
*/
|
|
2162
|
+
async cleanupElement(element, context) {
|
|
2163
|
+
const elementId = element.i;
|
|
2164
|
+
const overrides = this.getOverrides(element);
|
|
2165
|
+
const state = this.elementStates.get(elementId);
|
|
2166
|
+
if (state?.abortController) {
|
|
2167
|
+
state.abortController.abort();
|
|
2168
|
+
}
|
|
2169
|
+
this.stopWatching(elementId);
|
|
2170
|
+
const cleanupOverrides = overrides.filter((o) => o.isCleanUp);
|
|
2171
|
+
if (cleanupOverrides.length > 0) {
|
|
2172
|
+
await this.processOverrides(elementId, cleanupOverrides, context, "onUnmount");
|
|
2173
|
+
}
|
|
2174
|
+
this.elementStates.delete(elementId);
|
|
2175
|
+
}
|
|
2176
|
+
/**
|
|
2177
|
+
* Process a list of overrides
|
|
2178
|
+
*/
|
|
2179
|
+
async processOverrides(elementId, overrides, context, eventType) {
|
|
2180
|
+
if (!overrides || overrides.length === 0) return;
|
|
2181
|
+
const validOverrides = overrides.filter((o) => o.plugins && o.plugins.length > 0);
|
|
2182
|
+
if (validOverrides.length === 0) return;
|
|
2183
|
+
const results = await Promise.allSettled(
|
|
2184
|
+
validOverrides.map(async (override) => {
|
|
2185
|
+
if (this.config.onOverrideTrigger) {
|
|
2186
|
+
this.config.onOverrideTrigger(elementId, override, eventType);
|
|
2187
|
+
}
|
|
2188
|
+
if (this.config.eventSystem && override.plugins) {
|
|
2189
|
+
const eventContext = {
|
|
2190
|
+
event: new CustomEvent(eventType),
|
|
2191
|
+
elementId,
|
|
2192
|
+
context,
|
|
2193
|
+
stateManager: this.config.stateManager
|
|
2194
|
+
};
|
|
2195
|
+
return this.config.eventSystem.executePlugins(override.plugins, eventContext);
|
|
2196
|
+
}
|
|
2197
|
+
return null;
|
|
2198
|
+
})
|
|
2199
|
+
);
|
|
2200
|
+
results.forEach((result, index) => {
|
|
2201
|
+
if (result.status === "rejected") {
|
|
2202
|
+
console.error(`[OverrideSystem] Override ${index} failed:`, result.reason);
|
|
2203
|
+
}
|
|
2204
|
+
});
|
|
2205
|
+
}
|
|
2206
|
+
/**
|
|
2207
|
+
* Start watching an element for dependency changes
|
|
2208
|
+
*/
|
|
2209
|
+
startWatching(element, context, intervalMs = 100) {
|
|
2210
|
+
const elementId = element.i;
|
|
2211
|
+
this.stopWatching(elementId);
|
|
2212
|
+
const overrides = this.getOverrides(element);
|
|
2213
|
+
const hasDependencies = overrides.some(
|
|
2214
|
+
(o) => !o.isCleanUp && o.dependencies && o.dependencies.length > 0
|
|
2215
|
+
);
|
|
2216
|
+
if (!hasDependencies) return;
|
|
2217
|
+
const interval = setInterval(() => {
|
|
2218
|
+
this.checkDependencies(element, context);
|
|
2219
|
+
}, intervalMs);
|
|
2220
|
+
this.watchIntervals.set(elementId, interval);
|
|
2221
|
+
}
|
|
2222
|
+
/**
|
|
2223
|
+
* Stop watching an element
|
|
2224
|
+
*/
|
|
2225
|
+
stopWatching(elementId) {
|
|
2226
|
+
const interval = this.watchIntervals.get(elementId);
|
|
2227
|
+
if (interval) {
|
|
2228
|
+
clearInterval(interval);
|
|
2229
|
+
this.watchIntervals.delete(elementId);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
/**
|
|
2233
|
+
* Destroy the override system
|
|
2234
|
+
*/
|
|
2235
|
+
destroy() {
|
|
2236
|
+
for (const interval of this.watchIntervals.values()) {
|
|
2237
|
+
clearInterval(interval);
|
|
2238
|
+
}
|
|
2239
|
+
this.watchIntervals.clear();
|
|
2240
|
+
for (const state of this.elementStates.values()) {
|
|
2241
|
+
if (state.abortController) {
|
|
2242
|
+
state.abortController.abort();
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
this.elementStates.clear();
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2248
|
+
function extractOverrideDependencies(element) {
|
|
2249
|
+
const overrides = element.configuration?._overrides_;
|
|
2250
|
+
if (!Array.isArray(overrides)) return [];
|
|
2251
|
+
const dependencies = [];
|
|
2252
|
+
for (const override of overrides) {
|
|
2253
|
+
if (override?.dependencies && Array.isArray(override.dependencies)) {
|
|
2254
|
+
dependencies.push(...override.dependencies);
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
return [...new Set(dependencies)];
|
|
2258
|
+
}
|
|
2259
|
+
function hasOverrides(element) {
|
|
2260
|
+
const overrides = element.configuration?._overrides_;
|
|
2261
|
+
return Array.isArray(overrides) && overrides.length > 0;
|
|
2262
|
+
}
|
|
2263
|
+
function hasDependencyOverrides(element) {
|
|
2264
|
+
const overrides = element.configuration?._overrides_;
|
|
2265
|
+
if (!Array.isArray(overrides)) return false;
|
|
2266
|
+
return overrides.some(
|
|
2267
|
+
(o) => !o?.isCleanUp && o?.dependencies && o.dependencies.length > 0
|
|
2268
|
+
);
|
|
2269
|
+
}
|
|
2270
|
+
function getMountOverrides(element) {
|
|
2271
|
+
const overrides = element.configuration?._overrides_;
|
|
2272
|
+
if (!Array.isArray(overrides)) return [];
|
|
2273
|
+
return overrides.filter((o) => o && !o.isCleanUp);
|
|
2274
|
+
}
|
|
2275
|
+
function getCleanupOverrides(element) {
|
|
2276
|
+
const overrides = element.configuration?._overrides_;
|
|
2277
|
+
if (!Array.isArray(overrides)) return [];
|
|
2278
|
+
return overrides.filter((o) => o && o.isCleanUp);
|
|
2279
|
+
}
|
|
2280
|
+
var defaultOverrideSystem = null;
|
|
2281
|
+
function getOverrideSystem(config) {
|
|
2282
|
+
if (!defaultOverrideSystem || config) {
|
|
2283
|
+
defaultOverrideSystem = new OverrideSystem(config);
|
|
2284
|
+
}
|
|
2285
|
+
return defaultOverrideSystem;
|
|
2286
|
+
}
|
|
2287
|
+
function resetOverrideSystem() {
|
|
2288
|
+
if (defaultOverrideSystem) {
|
|
2289
|
+
defaultOverrideSystem.destroy();
|
|
2290
|
+
defaultOverrideSystem = null;
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
|
|
2294
|
+
// src/renderer.ts
|
|
2295
|
+
var COMPONENT_TO_TAG = {
|
|
2296
|
+
container: "div",
|
|
2297
|
+
text: "span",
|
|
2298
|
+
button: "button",
|
|
2299
|
+
input: "input",
|
|
2300
|
+
image: "img",
|
|
2301
|
+
link: "a",
|
|
2302
|
+
form: "form",
|
|
2303
|
+
label: "label",
|
|
2304
|
+
textarea: "textarea",
|
|
2305
|
+
select: "select",
|
|
2306
|
+
option: "option",
|
|
2307
|
+
list: "ul",
|
|
2308
|
+
listItem: "li",
|
|
2309
|
+
heading: "h1",
|
|
2310
|
+
paragraph: "p",
|
|
2311
|
+
section: "section",
|
|
2312
|
+
article: "article",
|
|
2313
|
+
header: "header",
|
|
2314
|
+
footer: "footer",
|
|
2315
|
+
nav: "nav",
|
|
2316
|
+
aside: "aside",
|
|
2317
|
+
main: "main",
|
|
2318
|
+
span: "span",
|
|
2319
|
+
div: "div"
|
|
2320
|
+
};
|
|
2321
|
+
var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
|
|
2322
|
+
"input",
|
|
2323
|
+
"img",
|
|
2324
|
+
"br",
|
|
2325
|
+
"hr",
|
|
2326
|
+
"area",
|
|
2327
|
+
"base",
|
|
2328
|
+
"col",
|
|
2329
|
+
"embed",
|
|
2330
|
+
"link",
|
|
2331
|
+
"meta",
|
|
2332
|
+
"param",
|
|
2333
|
+
"source",
|
|
2334
|
+
"track",
|
|
2335
|
+
"wbr"
|
|
2336
|
+
]);
|
|
2337
|
+
function getElementTag(element) {
|
|
2338
|
+
const config = element.configuration;
|
|
2339
|
+
if (config?.tag) {
|
|
2340
|
+
return config.tag;
|
|
2341
|
+
}
|
|
2342
|
+
if (element.componentId && COMPONENT_TO_TAG[element.componentId]) {
|
|
2343
|
+
return COMPONENT_TO_TAG[element.componentId];
|
|
2344
|
+
}
|
|
2345
|
+
if (element.isGroup) {
|
|
2346
|
+
return "div";
|
|
2347
|
+
}
|
|
2348
|
+
return "div";
|
|
2349
|
+
}
|
|
2350
|
+
function isSelfClosing(tag) {
|
|
2351
|
+
return SELF_CLOSING_TAGS.has(tag.toLowerCase());
|
|
2352
|
+
}
|
|
2353
|
+
function buildTree(elements) {
|
|
2354
|
+
const tree = /* @__PURE__ */ new Map();
|
|
2355
|
+
for (const element of elements) {
|
|
2356
|
+
const parentId = element.parent || null;
|
|
2357
|
+
if (!tree.has(parentId)) {
|
|
2358
|
+
tree.set(parentId, []);
|
|
2359
|
+
}
|
|
2360
|
+
tree.get(parentId).push(element);
|
|
2361
|
+
}
|
|
2362
|
+
return tree;
|
|
2363
|
+
}
|
|
2364
|
+
function getTextContent(element, context) {
|
|
2365
|
+
const config = element.configuration;
|
|
2366
|
+
if (config?.dynamicText) {
|
|
2367
|
+
return resolveTemplate(config.dynamicText, context);
|
|
2368
|
+
}
|
|
2369
|
+
if (config?.text) {
|
|
2370
|
+
if (hasTemplateSyntax(config.text)) {
|
|
2371
|
+
return resolveTemplate(config.text, context);
|
|
2372
|
+
}
|
|
2373
|
+
return config.text;
|
|
2374
|
+
}
|
|
2375
|
+
return "";
|
|
2376
|
+
}
|
|
2377
|
+
function applyAttributes(domElement, element, context) {
|
|
2378
|
+
const config = element.configuration || {};
|
|
2379
|
+
const attributeMap = [
|
|
2380
|
+
{ key: "id", attr: "id" },
|
|
2381
|
+
{ key: "src", dynamicKey: "dynamicSrc", attr: "src" },
|
|
2382
|
+
{ key: "alt", attr: "alt" },
|
|
2383
|
+
{ key: "href", dynamicKey: "dynamicHref", attr: "href" },
|
|
2384
|
+
{ key: "target", attr: "target" },
|
|
2385
|
+
{ key: "placeholder", attr: "placeholder" },
|
|
2386
|
+
{ key: "type", attr: "type" },
|
|
2387
|
+
{ key: "name", attr: "name" },
|
|
2388
|
+
{ key: "value", dynamicKey: "dynamicValue", attr: "value" }
|
|
2389
|
+
];
|
|
2390
|
+
for (const { key, dynamicKey, attr } of attributeMap) {
|
|
2391
|
+
const dynamicValue = dynamicKey ? config[dynamicKey] : void 0;
|
|
2392
|
+
if (dynamicValue !== void 0 && dynamicValue !== null && dynamicValue !== "") {
|
|
2393
|
+
const resolved = resolveTemplate(String(dynamicValue), context);
|
|
2394
|
+
if (resolved) {
|
|
2395
|
+
domElement.setAttribute(attr, resolved);
|
|
2396
|
+
}
|
|
2397
|
+
continue;
|
|
2398
|
+
}
|
|
2399
|
+
const staticValue = config[key];
|
|
2400
|
+
if (staticValue !== void 0 && staticValue !== null && staticValue !== "") {
|
|
2401
|
+
const resolved = hasTemplateSyntax(String(staticValue)) ? resolveTemplate(String(staticValue), context) : String(staticValue);
|
|
2402
|
+
if (resolved) {
|
|
2403
|
+
domElement.setAttribute(attr, resolved);
|
|
2404
|
+
}
|
|
2405
|
+
}
|
|
2406
|
+
}
|
|
2407
|
+
if (config.disabled) domElement.setAttribute("disabled", "");
|
|
2408
|
+
if (config.required) domElement.setAttribute("required", "");
|
|
2409
|
+
if (config.readOnly) domElement.setAttribute("readonly", "");
|
|
2410
|
+
for (const [key, value] of Object.entries(config)) {
|
|
2411
|
+
if (key.startsWith("data-") && value !== void 0) {
|
|
2412
|
+
const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
|
|
2413
|
+
domElement.setAttribute(key, resolved);
|
|
2414
|
+
}
|
|
2415
|
+
}
|
|
2416
|
+
for (const [key, value] of Object.entries(config)) {
|
|
2417
|
+
if (key.startsWith("aria-") && value !== void 0) {
|
|
2418
|
+
const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
|
|
2419
|
+
domElement.setAttribute(key, resolved);
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
function resolveFunctionBinding(binding, context) {
|
|
2424
|
+
if (binding.source === "props" || binding.source === "parent") {
|
|
2425
|
+
const path = binding.path;
|
|
2426
|
+
if (!path) return void 0;
|
|
2427
|
+
const parts = path.split(".");
|
|
2428
|
+
let value = context.props;
|
|
2429
|
+
for (const part of parts) {
|
|
2430
|
+
if (value === null || value === void 0) return void 0;
|
|
2431
|
+
value = value[part];
|
|
2432
|
+
}
|
|
2433
|
+
if (typeof value === "function") {
|
|
2434
|
+
return value;
|
|
2435
|
+
}
|
|
2436
|
+
return void 0;
|
|
2437
|
+
}
|
|
2438
|
+
if (binding.source === "static" && typeof binding.value === "function") {
|
|
2439
|
+
return binding.value;
|
|
2440
|
+
}
|
|
2441
|
+
return void 0;
|
|
2442
|
+
}
|
|
2443
|
+
function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false, state) {
|
|
2444
|
+
const elementId = element.i;
|
|
1223
2445
|
if (eventHandlers && eventHandlers[elementId]) {
|
|
1224
2446
|
const handlers = eventHandlers[elementId];
|
|
1225
2447
|
for (const [eventName, handler] of Object.entries(handlers)) {
|
|
@@ -1228,6 +2450,28 @@ function attachEventHandlers(domElement, element, eventHandlers, context, elemen
|
|
|
1228
2450
|
domElement.addEventListener(domEventName, handler);
|
|
1229
2451
|
}
|
|
1230
2452
|
}
|
|
2453
|
+
const config = element.configuration || {};
|
|
2454
|
+
for (const eventPropName of Object.keys(EVENT_HANDLERS)) {
|
|
2455
|
+
const handlerConfig = config[eventPropName];
|
|
2456
|
+
if (handlerConfig && handlerConfig.plugins && handlerConfig.plugins.length > 0) {
|
|
2457
|
+
const domEventName = toDomEventName(eventPropName);
|
|
2458
|
+
if (!elementState.eventListeners.has(domEventName)) {
|
|
2459
|
+
if (state?.eventSystem) {
|
|
2460
|
+
const handler = state.eventSystem.createHandler(elementId, handlerConfig, context);
|
|
2461
|
+
elementState.eventListeners.set(domEventName, handler);
|
|
2462
|
+
domElement.addEventListener(domEventName, handler);
|
|
2463
|
+
} else {
|
|
2464
|
+
const handler = (e) => {
|
|
2465
|
+
if (handlerConfig.preventDefault) e.preventDefault();
|
|
2466
|
+
if (handlerConfig.stopPropagation) e.stopPropagation();
|
|
2467
|
+
console.log(`[Servly] Event ${eventPropName} triggered on ${elementId}`, handlerConfig.plugins);
|
|
2468
|
+
};
|
|
2469
|
+
elementState.eventListeners.set(domEventName, handler);
|
|
2470
|
+
domElement.addEventListener(domEventName, handler);
|
|
2471
|
+
}
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
}
|
|
1231
2475
|
const bindings = element.configuration?.bindings?.inputs;
|
|
1232
2476
|
if (bindings) {
|
|
1233
2477
|
for (const [propName, binding] of Object.entries(bindings)) {
|
|
@@ -1262,10 +2506,16 @@ function detachEventHandlers(elementState) {
|
|
|
1262
2506
|
}
|
|
1263
2507
|
elementState.eventListeners.clear();
|
|
1264
2508
|
}
|
|
1265
|
-
function createElement(element, context, eventHandlers, isRootElement = false) {
|
|
2509
|
+
function createElement(element, context, eventHandlers, isRootElement = false, state) {
|
|
1266
2510
|
const tag = getElementTag(element);
|
|
1267
2511
|
const domElement = document.createElement(tag);
|
|
1268
2512
|
domElement.setAttribute("data-servly-id", element.i);
|
|
2513
|
+
const slotName = element.slotName || element.configuration?.slotName;
|
|
2514
|
+
if (element.componentId === "slot" || slotName) {
|
|
2515
|
+
const name = slotName || element.i;
|
|
2516
|
+
domElement.setAttribute("data-slot", name);
|
|
2517
|
+
domElement.setAttribute("data-servly-slot", "true");
|
|
2518
|
+
}
|
|
1269
2519
|
const styles = buildElementStyles(element, context);
|
|
1270
2520
|
applyStyles(domElement, styles);
|
|
1271
2521
|
const className = buildClassName(element, context);
|
|
@@ -1288,7 +2538,7 @@ function createElement(element, context, eventHandlers, isRootElement = false) {
|
|
|
1288
2538
|
textContent,
|
|
1289
2539
|
eventListeners: /* @__PURE__ */ new Map()
|
|
1290
2540
|
};
|
|
1291
|
-
attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement);
|
|
2541
|
+
attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement, state);
|
|
1292
2542
|
return elementState;
|
|
1293
2543
|
}
|
|
1294
2544
|
var globalRenderingStack = /* @__PURE__ */ new Set();
|
|
@@ -1349,8 +2599,81 @@ function renderComponentRef(element, container, context, state) {
|
|
|
1349
2599
|
globalRenderingStack.delete(refId);
|
|
1350
2600
|
}
|
|
1351
2601
|
}
|
|
2602
|
+
function extractViewId(binding) {
|
|
2603
|
+
if (!binding) return null;
|
|
2604
|
+
if (typeof binding === "string") return binding;
|
|
2605
|
+
if (binding.source === "static" && typeof binding.value === "string") return binding.value;
|
|
2606
|
+
if (binding.source === "node" && binding.binding?.viewId) return binding.binding.viewId;
|
|
2607
|
+
if (binding.source === "view" && typeof binding.value === "string") return binding.value;
|
|
2608
|
+
if (binding.viewId) return binding.viewId;
|
|
2609
|
+
if (binding.type === "view" && binding.viewId) return binding.viewId;
|
|
2610
|
+
return null;
|
|
2611
|
+
}
|
|
2612
|
+
function resolveComponentViewInputs(bindings, context, parentInputs) {
|
|
2613
|
+
if (!bindings) return {};
|
|
2614
|
+
const resolved = {};
|
|
2615
|
+
for (const [key, binding] of Object.entries(bindings)) {
|
|
2616
|
+
if (!binding) continue;
|
|
2617
|
+
const source = (binding.source || "").toLowerCase();
|
|
2618
|
+
switch (source) {
|
|
2619
|
+
case "static":
|
|
2620
|
+
case "value":
|
|
2621
|
+
case "constant":
|
|
2622
|
+
resolved[key] = binding.value;
|
|
2623
|
+
break;
|
|
2624
|
+
case "state":
|
|
2625
|
+
if (binding.path && context.state) {
|
|
2626
|
+
resolved[key] = getValueByPath2(context.state, binding.path);
|
|
2627
|
+
}
|
|
2628
|
+
break;
|
|
2629
|
+
case "props":
|
|
2630
|
+
case "parent":
|
|
2631
|
+
case "input":
|
|
2632
|
+
if (binding.path) {
|
|
2633
|
+
const source2 = parentInputs || context.props;
|
|
2634
|
+
const resolvedValue = getValueByPath2(source2, binding.path);
|
|
2635
|
+
if (resolvedValue !== void 0) {
|
|
2636
|
+
resolved[key] = resolvedValue;
|
|
2637
|
+
} else {
|
|
2638
|
+
resolved[key] = binding.value;
|
|
2639
|
+
}
|
|
2640
|
+
} else {
|
|
2641
|
+
resolved[key] = binding.value;
|
|
2642
|
+
}
|
|
2643
|
+
break;
|
|
2644
|
+
case "node":
|
|
2645
|
+
if (binding.binding?.viewId) {
|
|
2646
|
+
resolved[key] = binding.binding.viewId;
|
|
2647
|
+
} else if (binding.binding) {
|
|
2648
|
+
resolved[key] = binding.binding;
|
|
2649
|
+
} else {
|
|
2650
|
+
resolved[key] = binding.value;
|
|
2651
|
+
}
|
|
2652
|
+
break;
|
|
2653
|
+
default:
|
|
2654
|
+
resolved[key] = binding.value;
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
return resolved;
|
|
2658
|
+
}
|
|
2659
|
+
function getValueByPath2(obj, path) {
|
|
2660
|
+
if (!obj || !path) return void 0;
|
|
2661
|
+
const parts = path.split(".");
|
|
2662
|
+
let current = obj;
|
|
2663
|
+
for (const part of parts) {
|
|
2664
|
+
if (current === null || current === void 0) return void 0;
|
|
2665
|
+
current = current[part];
|
|
2666
|
+
}
|
|
2667
|
+
return current;
|
|
2668
|
+
}
|
|
1352
2669
|
function renderElement(element, tree, context, eventHandlers, elementStates, state, isRootElement = false) {
|
|
1353
|
-
|
|
2670
|
+
if (element.isComponentView) {
|
|
2671
|
+
return renderComponentViewElement(element, tree, context, eventHandlers, elementStates, state, isRootElement);
|
|
2672
|
+
}
|
|
2673
|
+
if (element.componentId === "slot") {
|
|
2674
|
+
return renderSlotElement(element, tree, context, eventHandlers, elementStates, state, isRootElement);
|
|
2675
|
+
}
|
|
2676
|
+
const elementState = createElement(element, context, eventHandlers, isRootElement, state);
|
|
1354
2677
|
elementStates.set(element.i, elementState);
|
|
1355
2678
|
const config = element.configuration;
|
|
1356
2679
|
if (config?.componentViewRef) {
|
|
@@ -1367,8 +2690,147 @@ function renderElement(element, tree, context, eventHandlers, elementStates, sta
|
|
|
1367
2690
|
}
|
|
1368
2691
|
return elementState.domElement;
|
|
1369
2692
|
}
|
|
2693
|
+
function renderComponentViewElement(element, tree, context, eventHandlers, elementStates, state, isRootElement) {
|
|
2694
|
+
const componentViewId = `${element.componentId}-${element.i}`;
|
|
2695
|
+
if (globalRenderingStack.has(componentViewId)) {
|
|
2696
|
+
const placeholder = document.createElement("div");
|
|
2697
|
+
placeholder.className = "border-2 border-red-500 border-dashed p-4 bg-red-50";
|
|
2698
|
+
placeholder.innerHTML = `<p class="text-red-600 text-sm">Recursive component: ${element.componentId}</p>`;
|
|
2699
|
+
return placeholder;
|
|
2700
|
+
}
|
|
2701
|
+
let viewLayout;
|
|
2702
|
+
if (state.views?.has(element.componentId)) {
|
|
2703
|
+
const view = state.views.get(element.componentId);
|
|
2704
|
+
viewLayout = view?.layout;
|
|
2705
|
+
}
|
|
2706
|
+
if (!viewLayout && state.componentRegistry) {
|
|
2707
|
+
const component = state.componentRegistry.get(element.componentId);
|
|
2708
|
+
if (component) {
|
|
2709
|
+
viewLayout = component.layout;
|
|
2710
|
+
}
|
|
2711
|
+
}
|
|
2712
|
+
if (!viewLayout) {
|
|
2713
|
+
const placeholder = document.createElement("div");
|
|
2714
|
+
placeholder.className = "border-2 border-yellow-500 border-dashed p-4 bg-yellow-50";
|
|
2715
|
+
placeholder.innerHTML = `<p class="text-yellow-600 text-sm">Component not found: ${element.componentId}</p>`;
|
|
2716
|
+
return placeholder;
|
|
2717
|
+
}
|
|
2718
|
+
const bindings = element.configuration?.bindings?.inputs || {};
|
|
2719
|
+
const resolvedInputs = resolveComponentViewInputs(bindings, context, context.props);
|
|
2720
|
+
const componentContext = {
|
|
2721
|
+
props: { ...context.props, ...resolvedInputs },
|
|
2722
|
+
state: context.state,
|
|
2723
|
+
context: context.context
|
|
2724
|
+
};
|
|
2725
|
+
globalRenderingStack.add(componentViewId);
|
|
2726
|
+
try {
|
|
2727
|
+
const wrapper = document.createElement("div");
|
|
2728
|
+
wrapper.id = element.i;
|
|
2729
|
+
wrapper.className = "contents";
|
|
2730
|
+
const viewTree = buildTree(viewLayout);
|
|
2731
|
+
const viewRoots = viewLayout.filter((el) => !el.parent || el.parent === null);
|
|
2732
|
+
const nestedState = {
|
|
2733
|
+
...state,
|
|
2734
|
+
elements: viewLayout,
|
|
2735
|
+
context: componentContext,
|
|
2736
|
+
elementStates: /* @__PURE__ */ new Map(),
|
|
2737
|
+
rootElement: null,
|
|
2738
|
+
renderingStack: new Set(state.renderingStack)
|
|
2739
|
+
};
|
|
2740
|
+
nestedState.renderingStack.add(componentViewId);
|
|
2741
|
+
for (const root of viewRoots) {
|
|
2742
|
+
const rootElement = renderElement(
|
|
2743
|
+
root,
|
|
2744
|
+
viewTree,
|
|
2745
|
+
componentContext,
|
|
2746
|
+
eventHandlers,
|
|
2747
|
+
nestedState.elementStates,
|
|
2748
|
+
nestedState,
|
|
2749
|
+
true
|
|
2750
|
+
);
|
|
2751
|
+
wrapper.appendChild(rootElement);
|
|
2752
|
+
}
|
|
2753
|
+
const elementState = {
|
|
2754
|
+
element,
|
|
2755
|
+
domElement: wrapper,
|
|
2756
|
+
styles: {},
|
|
2757
|
+
className: "contents",
|
|
2758
|
+
textContent: "",
|
|
2759
|
+
eventListeners: /* @__PURE__ */ new Map()
|
|
2760
|
+
};
|
|
2761
|
+
elementStates.set(element.i, elementState);
|
|
2762
|
+
return wrapper;
|
|
2763
|
+
} finally {
|
|
2764
|
+
globalRenderingStack.delete(componentViewId);
|
|
2765
|
+
}
|
|
2766
|
+
}
|
|
2767
|
+
function renderSlotElement(element, tree, context, eventHandlers, elementStates, state, isRootElement) {
|
|
2768
|
+
const elementState = createElement(element, context, eventHandlers, isRootElement, state);
|
|
2769
|
+
elementStates.set(element.i, elementState);
|
|
2770
|
+
const bindings = element.configuration?.bindings?.inputs || {};
|
|
2771
|
+
let childViewId = extractViewId(bindings.child) || extractViewId(bindings.children) || extractViewId(bindings.content);
|
|
2772
|
+
if (!childViewId && context.props) {
|
|
2773
|
+
childViewId = extractViewId(context.props.child) || extractViewId(context.props.children) || extractViewId(context.props.content);
|
|
2774
|
+
}
|
|
2775
|
+
if (childViewId && typeof childViewId === "string") {
|
|
2776
|
+
let viewLayout;
|
|
2777
|
+
if (state.views?.has(childViewId)) {
|
|
2778
|
+
const view = state.views.get(childViewId);
|
|
2779
|
+
viewLayout = view?.layout;
|
|
2780
|
+
}
|
|
2781
|
+
if (!viewLayout && state.componentRegistry) {
|
|
2782
|
+
const component = state.componentRegistry.get(childViewId);
|
|
2783
|
+
if (component) {
|
|
2784
|
+
viewLayout = component.layout;
|
|
2785
|
+
}
|
|
2786
|
+
}
|
|
2787
|
+
if (viewLayout) {
|
|
2788
|
+
const viewTree = buildTree(viewLayout);
|
|
2789
|
+
const viewRoots = viewLayout.filter((el) => !el.parent || el.parent === null);
|
|
2790
|
+
const nestedState = {
|
|
2791
|
+
...state,
|
|
2792
|
+
elements: viewLayout,
|
|
2793
|
+
elementStates: /* @__PURE__ */ new Map(),
|
|
2794
|
+
rootElement: null
|
|
2795
|
+
};
|
|
2796
|
+
for (const root of viewRoots) {
|
|
2797
|
+
const rootElement = renderElement(
|
|
2798
|
+
root,
|
|
2799
|
+
viewTree,
|
|
2800
|
+
context,
|
|
2801
|
+
eventHandlers,
|
|
2802
|
+
nestedState.elementStates,
|
|
2803
|
+
nestedState,
|
|
2804
|
+
false
|
|
2805
|
+
);
|
|
2806
|
+
elementState.domElement.appendChild(rootElement);
|
|
2807
|
+
}
|
|
2808
|
+
return elementState.domElement;
|
|
2809
|
+
}
|
|
2810
|
+
}
|
|
2811
|
+
const children = tree.get(element.i) || [];
|
|
2812
|
+
for (const child of children) {
|
|
2813
|
+
const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state, false);
|
|
2814
|
+
elementState.domElement.appendChild(childElement);
|
|
2815
|
+
}
|
|
2816
|
+
return elementState.domElement;
|
|
2817
|
+
}
|
|
1370
2818
|
function render(options) {
|
|
1371
|
-
const {
|
|
2819
|
+
const {
|
|
2820
|
+
container,
|
|
2821
|
+
elements,
|
|
2822
|
+
context,
|
|
2823
|
+
eventHandlers,
|
|
2824
|
+
componentRegistry,
|
|
2825
|
+
onDependencyNeeded,
|
|
2826
|
+
views,
|
|
2827
|
+
enableStateManager,
|
|
2828
|
+
initialState,
|
|
2829
|
+
onStateChange,
|
|
2830
|
+
pluginExecutors,
|
|
2831
|
+
onNavigate,
|
|
2832
|
+
onApiCall
|
|
2833
|
+
} = options;
|
|
1372
2834
|
const startTime = performance.now();
|
|
1373
2835
|
const memorySampler = getMemorySampler();
|
|
1374
2836
|
const longTaskObserver = getLongTaskObserver();
|
|
@@ -1377,6 +2839,29 @@ function render(options) {
|
|
|
1377
2839
|
const rootElements = elements.filter((el) => !el.parent || el.parent === null);
|
|
1378
2840
|
const componentId = rootElements[0]?.componentId || "unknown";
|
|
1379
2841
|
const version = "latest";
|
|
2842
|
+
let stateManager;
|
|
2843
|
+
if (enableStateManager) {
|
|
2844
|
+
stateManager = new StateManager({
|
|
2845
|
+
initialState: initialState || context.state,
|
|
2846
|
+
onStateChange: onStateChange ? (event) => onStateChange({
|
|
2847
|
+
key: event.key,
|
|
2848
|
+
value: event.value,
|
|
2849
|
+
previousValue: event.previousValue
|
|
2850
|
+
}) : void 0
|
|
2851
|
+
});
|
|
2852
|
+
}
|
|
2853
|
+
const eventSystem = new EventSystem({
|
|
2854
|
+
stateManager,
|
|
2855
|
+
pluginExecutors,
|
|
2856
|
+
onNavigate,
|
|
2857
|
+
onApiCall
|
|
2858
|
+
});
|
|
2859
|
+
const overrideSystem = new OverrideSystem({
|
|
2860
|
+
eventSystem,
|
|
2861
|
+
stateManager
|
|
2862
|
+
});
|
|
2863
|
+
const hasAnyOverrides = elements.some((el) => hasOverrides(el));
|
|
2864
|
+
const hasAnyDependencyOverrides = elements.some((el) => hasDependencyOverrides(el));
|
|
1380
2865
|
try {
|
|
1381
2866
|
const tree = buildTree(elements);
|
|
1382
2867
|
const state = {
|
|
@@ -1388,7 +2873,12 @@ function render(options) {
|
|
|
1388
2873
|
rootElement: null,
|
|
1389
2874
|
componentRegistry,
|
|
1390
2875
|
onDependencyNeeded,
|
|
1391
|
-
renderingStack: /* @__PURE__ */ new Set()
|
|
2876
|
+
renderingStack: /* @__PURE__ */ new Set(),
|
|
2877
|
+
views,
|
|
2878
|
+
eventSystem,
|
|
2879
|
+
stateManager,
|
|
2880
|
+
overrideSystem,
|
|
2881
|
+
enableOverrides: hasAnyOverrides
|
|
1392
2882
|
};
|
|
1393
2883
|
container.innerHTML = "";
|
|
1394
2884
|
if (rootElements.length === 0) {
|
|
@@ -1426,6 +2916,16 @@ function render(options) {
|
|
|
1426
2916
|
state.rootElement = wrapper;
|
|
1427
2917
|
container.appendChild(wrapper);
|
|
1428
2918
|
}
|
|
2919
|
+
if (hasAnyOverrides && overrideSystem) {
|
|
2920
|
+
for (const element of elements) {
|
|
2921
|
+
if (hasOverrides(element)) {
|
|
2922
|
+
overrideSystem.initializeElement(element, context);
|
|
2923
|
+
if (hasDependencyOverrides(element)) {
|
|
2924
|
+
overrideSystem.startWatching(element, context);
|
|
2925
|
+
}
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
1429
2929
|
const duration = performance.now() - startTime;
|
|
1430
2930
|
const memoryAfter = memorySampler.sample();
|
|
1431
2931
|
const longTasks = longTaskObserver.stop();
|
|
@@ -1444,6 +2944,7 @@ function render(options) {
|
|
|
1444
2944
|
};
|
|
1445
2945
|
} catch (error) {
|
|
1446
2946
|
longTaskObserver.stop();
|
|
2947
|
+
overrideSystem.destroy();
|
|
1447
2948
|
analytics.trackError(componentId, version, error, {
|
|
1448
2949
|
errorType: "render"
|
|
1449
2950
|
});
|
|
@@ -1474,12 +2975,23 @@ function update(state, newContext) {
|
|
|
1474
2975
|
}
|
|
1475
2976
|
}
|
|
1476
2977
|
function destroy(state) {
|
|
2978
|
+
if (state.overrideSystem && state.enableOverrides) {
|
|
2979
|
+
for (const element of state.elements) {
|
|
2980
|
+
if (hasOverrides(element)) {
|
|
2981
|
+
state.overrideSystem.cleanupElement(element, state.context);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
state.overrideSystem.destroy();
|
|
2985
|
+
}
|
|
1477
2986
|
for (const elementState of state.elementStates.values()) {
|
|
1478
2987
|
detachEventHandlers(elementState);
|
|
1479
2988
|
if (elementState.nestedRender) {
|
|
1480
2989
|
elementState.nestedRender.destroy();
|
|
1481
2990
|
}
|
|
1482
2991
|
}
|
|
2992
|
+
if (state.eventSystem) {
|
|
2993
|
+
state.eventSystem.destroy();
|
|
2994
|
+
}
|
|
1483
2995
|
state.elementStates.clear();
|
|
1484
2996
|
if (state.rootElement && state.rootElement.parentNode) {
|
|
1485
2997
|
state.rootElement.parentNode.removeChild(state.rootElement);
|
|
@@ -1546,6 +3058,200 @@ function renderDynamicList(options) {
|
|
|
1546
3058
|
}
|
|
1547
3059
|
return results;
|
|
1548
3060
|
}
|
|
3061
|
+
function renderNode(options) {
|
|
3062
|
+
const {
|
|
3063
|
+
container,
|
|
3064
|
+
elements,
|
|
3065
|
+
nodeId,
|
|
3066
|
+
context,
|
|
3067
|
+
includeChildren = true,
|
|
3068
|
+
eventHandlers,
|
|
3069
|
+
componentRegistry,
|
|
3070
|
+
views
|
|
3071
|
+
} = options;
|
|
3072
|
+
const targetNode = elements.find((el) => el.i === nodeId);
|
|
3073
|
+
if (!targetNode) {
|
|
3074
|
+
console.error(`renderNode: Node not found: ${nodeId}`);
|
|
3075
|
+
return null;
|
|
3076
|
+
}
|
|
3077
|
+
if (!includeChildren) {
|
|
3078
|
+
const singleElementLayout = [targetNode];
|
|
3079
|
+
return render({
|
|
3080
|
+
container,
|
|
3081
|
+
elements: singleElementLayout,
|
|
3082
|
+
context,
|
|
3083
|
+
eventHandlers,
|
|
3084
|
+
componentRegistry,
|
|
3085
|
+
views
|
|
3086
|
+
});
|
|
3087
|
+
}
|
|
3088
|
+
const descendantIds = /* @__PURE__ */ new Set();
|
|
3089
|
+
const collectDescendants = (parentId) => {
|
|
3090
|
+
for (const el of elements) {
|
|
3091
|
+
if (el.parent === parentId) {
|
|
3092
|
+
descendantIds.add(el.i);
|
|
3093
|
+
collectDescendants(el.i);
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
};
|
|
3097
|
+
descendantIds.add(nodeId);
|
|
3098
|
+
collectDescendants(nodeId);
|
|
3099
|
+
const nodeElements = elements.filter((el) => descendantIds.has(el.i));
|
|
3100
|
+
const rootedElements = nodeElements.map(
|
|
3101
|
+
(el) => el.i === nodeId ? { ...el, parent: null } : el
|
|
3102
|
+
);
|
|
3103
|
+
return render({
|
|
3104
|
+
container,
|
|
3105
|
+
elements: rootedElements,
|
|
3106
|
+
context,
|
|
3107
|
+
eventHandlers,
|
|
3108
|
+
componentRegistry,
|
|
3109
|
+
views
|
|
3110
|
+
});
|
|
3111
|
+
}
|
|
3112
|
+
function renderInShadow(options) {
|
|
3113
|
+
const { container, mode = "open", styles, injectTailwind: shouldInjectTailwind, ...renderOptions } = options;
|
|
3114
|
+
const shadowRoot = container.attachShadow({ mode });
|
|
3115
|
+
const innerContainer = document.createElement("div");
|
|
3116
|
+
innerContainer.className = "servly-shadow-container";
|
|
3117
|
+
shadowRoot.appendChild(innerContainer);
|
|
3118
|
+
if (styles) {
|
|
3119
|
+
const styleEl = document.createElement("style");
|
|
3120
|
+
styleEl.textContent = styles;
|
|
3121
|
+
shadowRoot.insertBefore(styleEl, innerContainer);
|
|
3122
|
+
}
|
|
3123
|
+
if (shouldInjectTailwind) {
|
|
3124
|
+
const tailwindLink = document.createElement("link");
|
|
3125
|
+
tailwindLink.rel = "stylesheet";
|
|
3126
|
+
tailwindLink.href = "https://cdn.tailwindcss.com";
|
|
3127
|
+
shadowRoot.insertBefore(tailwindLink, innerContainer);
|
|
3128
|
+
}
|
|
3129
|
+
const result = render({
|
|
3130
|
+
...renderOptions,
|
|
3131
|
+
container: innerContainer
|
|
3132
|
+
});
|
|
3133
|
+
return {
|
|
3134
|
+
...result,
|
|
3135
|
+
shadowRoot
|
|
3136
|
+
};
|
|
3137
|
+
}
|
|
3138
|
+
async function createServlyRenderer(options) {
|
|
3139
|
+
const {
|
|
3140
|
+
container: containerOption,
|
|
3141
|
+
injectTailwind: shouldInjectTailwind = true,
|
|
3142
|
+
tailwindConfig,
|
|
3143
|
+
initialState,
|
|
3144
|
+
onStateChange,
|
|
3145
|
+
onNavigate
|
|
3146
|
+
} = options;
|
|
3147
|
+
let container;
|
|
3148
|
+
if (typeof containerOption === "string") {
|
|
3149
|
+
const el = document.querySelector(containerOption);
|
|
3150
|
+
if (!el) {
|
|
3151
|
+
throw new Error(`Container not found: ${containerOption}`);
|
|
3152
|
+
}
|
|
3153
|
+
container = el;
|
|
3154
|
+
} else {
|
|
3155
|
+
container = containerOption;
|
|
3156
|
+
}
|
|
3157
|
+
if (shouldInjectTailwind) {
|
|
3158
|
+
const { initServlyTailwind: initServlyTailwind2 } = await import("./tailwind-CGAHPC3O.js");
|
|
3159
|
+
await initServlyTailwind2(tailwindConfig);
|
|
3160
|
+
}
|
|
3161
|
+
const activeRenders = [];
|
|
3162
|
+
return {
|
|
3163
|
+
render: (elements, context = { props: {} }) => {
|
|
3164
|
+
const result = render({
|
|
3165
|
+
container,
|
|
3166
|
+
elements,
|
|
3167
|
+
context,
|
|
3168
|
+
enableStateManager: true,
|
|
3169
|
+
initialState,
|
|
3170
|
+
onStateChange,
|
|
3171
|
+
onNavigate
|
|
3172
|
+
});
|
|
3173
|
+
activeRenders.push(result);
|
|
3174
|
+
return result;
|
|
3175
|
+
},
|
|
3176
|
+
renderNode: (elements, nodeId, context = { props: {} }) => {
|
|
3177
|
+
const result = renderNode({
|
|
3178
|
+
container,
|
|
3179
|
+
elements,
|
|
3180
|
+
nodeId,
|
|
3181
|
+
context
|
|
3182
|
+
});
|
|
3183
|
+
if (result) {
|
|
3184
|
+
activeRenders.push(result);
|
|
3185
|
+
}
|
|
3186
|
+
return result;
|
|
3187
|
+
},
|
|
3188
|
+
renderDynamicList,
|
|
3189
|
+
destroy: () => {
|
|
3190
|
+
for (const result of activeRenders) {
|
|
3191
|
+
result.destroy();
|
|
3192
|
+
}
|
|
3193
|
+
activeRenders.length = 0;
|
|
3194
|
+
container.innerHTML = "";
|
|
3195
|
+
}
|
|
3196
|
+
};
|
|
3197
|
+
}
|
|
3198
|
+
function createViewsMap(views) {
|
|
3199
|
+
const viewsMap = /* @__PURE__ */ new Map();
|
|
3200
|
+
for (const view of views) {
|
|
3201
|
+
const id = view.id || view._id;
|
|
3202
|
+
if (id && view.layout) {
|
|
3203
|
+
viewsMap.set(id, {
|
|
3204
|
+
id,
|
|
3205
|
+
layout: view.layout,
|
|
3206
|
+
props: view.props
|
|
3207
|
+
});
|
|
3208
|
+
}
|
|
3209
|
+
}
|
|
3210
|
+
return viewsMap;
|
|
3211
|
+
}
|
|
3212
|
+
function extractReferencedViewIds(elements) {
|
|
3213
|
+
const viewIds = /* @__PURE__ */ new Set();
|
|
3214
|
+
for (const element of elements) {
|
|
3215
|
+
if (element.isComponentView && element.componentId) {
|
|
3216
|
+
viewIds.add(element.componentId);
|
|
3217
|
+
}
|
|
3218
|
+
if (element.configuration?.componentViewRef) {
|
|
3219
|
+
viewIds.add(element.configuration.componentViewRef);
|
|
3220
|
+
}
|
|
3221
|
+
const bindings = element.configuration?.bindings?.inputs;
|
|
3222
|
+
if (bindings) {
|
|
3223
|
+
for (const binding of Object.values(bindings)) {
|
|
3224
|
+
if (binding && typeof binding === "object") {
|
|
3225
|
+
if (binding.source === "node" && binding.binding?.viewId) {
|
|
3226
|
+
viewIds.add(binding.binding.viewId);
|
|
3227
|
+
}
|
|
3228
|
+
if (binding.viewId) {
|
|
3229
|
+
viewIds.add(binding.viewId);
|
|
3230
|
+
}
|
|
3231
|
+
}
|
|
3232
|
+
}
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
return Array.from(viewIds);
|
|
3236
|
+
}
|
|
3237
|
+
function collectAllViewDependencies(views, startViewId) {
|
|
3238
|
+
const collected = /* @__PURE__ */ new Set();
|
|
3239
|
+
const toProcess = [startViewId];
|
|
3240
|
+
while (toProcess.length > 0) {
|
|
3241
|
+
const viewId = toProcess.pop();
|
|
3242
|
+
if (collected.has(viewId)) continue;
|
|
3243
|
+
collected.add(viewId);
|
|
3244
|
+
const view = views.get(viewId);
|
|
3245
|
+
if (!view) continue;
|
|
3246
|
+
const referencedIds = extractReferencedViewIds(view.layout);
|
|
3247
|
+
for (const refId of referencedIds) {
|
|
3248
|
+
if (!collected.has(refId)) {
|
|
3249
|
+
toProcess.push(refId);
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
}
|
|
3253
|
+
return collected;
|
|
3254
|
+
}
|
|
1549
3255
|
|
|
1550
3256
|
// src/cache.ts
|
|
1551
3257
|
var DEFAULT_CACHE_CONFIG = {
|
|
@@ -1819,6 +3525,18 @@ function calculateBackoffDelay(retryCount, config) {
|
|
|
1819
3525
|
function sleep(ms) {
|
|
1820
3526
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
1821
3527
|
}
|
|
3528
|
+
function buildViewsMap(views) {
|
|
3529
|
+
if (!views || views.length === 0) return void 0;
|
|
3530
|
+
const viewsMap = /* @__PURE__ */ new Map();
|
|
3531
|
+
for (const view of views) {
|
|
3532
|
+
viewsMap.set(view.id, {
|
|
3533
|
+
id: view.id,
|
|
3534
|
+
layout: view.layout,
|
|
3535
|
+
props: view.props
|
|
3536
|
+
});
|
|
3537
|
+
}
|
|
3538
|
+
return viewsMap;
|
|
3539
|
+
}
|
|
1822
3540
|
async function resolveVersionFromApi(id, specifier, apiKey) {
|
|
1823
3541
|
if (/^\d+\.\d+\.\d+$/.test(specifier)) {
|
|
1824
3542
|
return specifier;
|
|
@@ -1848,7 +3566,7 @@ async function resolveVersionFromApi(id, specifier, apiKey) {
|
|
|
1848
3566
|
return "latest";
|
|
1849
3567
|
}
|
|
1850
3568
|
}
|
|
1851
|
-
async function fetchFromRegistry(id, version, apiKey, includeBundle) {
|
|
3569
|
+
async function fetchFromRegistry(id, version, apiKey, includeBundle, includeViews) {
|
|
1852
3570
|
const baseUrl = getRegistryUrl();
|
|
1853
3571
|
const headers = {
|
|
1854
3572
|
"Content-Type": "application/json"
|
|
@@ -1867,6 +3585,9 @@ async function fetchFromRegistry(id, version, apiKey, includeBundle) {
|
|
|
1867
3585
|
if (includeBundle) {
|
|
1868
3586
|
url += (url.includes("?") ? "&" : "?") + "bundle=true";
|
|
1869
3587
|
}
|
|
3588
|
+
if (includeViews) {
|
|
3589
|
+
url += (url.includes("?") ? "&" : "?") + "includeViews=true";
|
|
3590
|
+
}
|
|
1870
3591
|
const response = await fetch(url, { headers });
|
|
1871
3592
|
if (!response.ok) {
|
|
1872
3593
|
if (response.status === 404) {
|
|
@@ -1900,7 +3621,9 @@ async function fetchComponent(id, options = {}) {
|
|
|
1900
3621
|
forceRefresh = false,
|
|
1901
3622
|
signal,
|
|
1902
3623
|
bundleStrategy = "eager",
|
|
1903
|
-
includeBundle = true
|
|
3624
|
+
includeBundle = true,
|
|
3625
|
+
includeViews = true
|
|
3626
|
+
// Default to true - fetch all views needed
|
|
1904
3627
|
} = options;
|
|
1905
3628
|
const fullRetryConfig = {
|
|
1906
3629
|
...DEFAULT_RETRY_CONFIG,
|
|
@@ -1914,6 +3637,7 @@ async function fetchComponent(id, options = {}) {
|
|
|
1914
3637
|
if (cached.bundle) {
|
|
1915
3638
|
registry = buildRegistryFromBundle(cached);
|
|
1916
3639
|
}
|
|
3640
|
+
const views = buildViewsMap(cached.views);
|
|
1917
3641
|
const duration = performance.now() - startTime;
|
|
1918
3642
|
analytics.trackFetch(id, cached.version, duration, true, {
|
|
1919
3643
|
cacheHit: true,
|
|
@@ -1923,7 +3647,8 @@ async function fetchComponent(id, options = {}) {
|
|
|
1923
3647
|
data: cached,
|
|
1924
3648
|
fromCache: true,
|
|
1925
3649
|
version: cached.version,
|
|
1926
|
-
registry
|
|
3650
|
+
registry,
|
|
3651
|
+
views
|
|
1927
3652
|
};
|
|
1928
3653
|
}
|
|
1929
3654
|
}
|
|
@@ -1935,11 +3660,13 @@ async function fetchComponent(id, options = {}) {
|
|
|
1935
3660
|
if (cached.bundle) {
|
|
1936
3661
|
registry = buildRegistryFromBundle(cached);
|
|
1937
3662
|
}
|
|
3663
|
+
const views = buildViewsMap(cached.views);
|
|
1938
3664
|
return {
|
|
1939
3665
|
data: cached,
|
|
1940
3666
|
fromCache: true,
|
|
1941
3667
|
version: resolvedVersion,
|
|
1942
|
-
registry
|
|
3668
|
+
registry,
|
|
3669
|
+
views
|
|
1943
3670
|
};
|
|
1944
3671
|
}
|
|
1945
3672
|
}
|
|
@@ -1950,7 +3677,7 @@ async function fetchComponent(id, options = {}) {
|
|
|
1950
3677
|
throw new Error("Fetch aborted");
|
|
1951
3678
|
}
|
|
1952
3679
|
try {
|
|
1953
|
-
const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle);
|
|
3680
|
+
const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle, includeViews);
|
|
1954
3681
|
setInCache(id, resolvedVersion, data, cacheStrategy, cacheConfig);
|
|
1955
3682
|
if (version !== resolvedVersion) {
|
|
1956
3683
|
setInCache(id, version, data, cacheStrategy, cacheConfig);
|
|
@@ -1965,6 +3692,7 @@ async function fetchComponent(id, options = {}) {
|
|
|
1965
3692
|
version: entry.resolved || entry.version
|
|
1966
3693
|
}));
|
|
1967
3694
|
}
|
|
3695
|
+
const views = buildViewsMap(data.views);
|
|
1968
3696
|
const duration = performance.now() - startTime;
|
|
1969
3697
|
analytics.trackFetch(id, resolvedVersion, duration, false, {
|
|
1970
3698
|
cacheHit: false,
|
|
@@ -1976,7 +3704,8 @@ async function fetchComponent(id, options = {}) {
|
|
|
1976
3704
|
fromCache: false,
|
|
1977
3705
|
version: resolvedVersion,
|
|
1978
3706
|
registry,
|
|
1979
|
-
pendingDependencies
|
|
3707
|
+
pendingDependencies,
|
|
3708
|
+
views
|
|
1980
3709
|
};
|
|
1981
3710
|
} catch (error) {
|
|
1982
3711
|
lastError = error instanceof Error ? error : new Error(String(error));
|
|
@@ -2347,13 +4076,13 @@ function validateAssertion(container, assertion) {
|
|
|
2347
4076
|
message: `Element "${assertion.selector}" not found`
|
|
2348
4077
|
};
|
|
2349
4078
|
}
|
|
2350
|
-
const
|
|
4079
|
+
const hasClass2 = elements[0].classList.contains(assertion.expected);
|
|
2351
4080
|
return {
|
|
2352
4081
|
assertion,
|
|
2353
|
-
passed:
|
|
4082
|
+
passed: hasClass2,
|
|
2354
4083
|
actual: Array.from(elements[0].classList),
|
|
2355
4084
|
expected: assertion.expected,
|
|
2356
|
-
message:
|
|
4085
|
+
message: hasClass2 ? `Element has class "${assertion.expected}"` : `Element does not have class "${assertion.expected}"`
|
|
2357
4086
|
};
|
|
2358
4087
|
case "style":
|
|
2359
4088
|
if (elements.length === 0) {
|
|
@@ -2474,9 +4203,16 @@ export {
|
|
|
2474
4203
|
AnalyticsCollector,
|
|
2475
4204
|
DEFAULT_CACHE_CONFIG,
|
|
2476
4205
|
DEFAULT_RETRY_CONFIG,
|
|
4206
|
+
DEFAULT_SERVLY_TAILWIND_CONFIG,
|
|
4207
|
+
EVENT_HANDLERS,
|
|
4208
|
+
EventSystem,
|
|
2477
4209
|
LongTaskObserver,
|
|
2478
4210
|
MemorySampler,
|
|
4211
|
+
OverrideSystem,
|
|
2479
4212
|
SessionManager,
|
|
4213
|
+
StateManager,
|
|
4214
|
+
addClass,
|
|
4215
|
+
addCustomStyles,
|
|
2480
4216
|
analytics,
|
|
2481
4217
|
applyStyles,
|
|
2482
4218
|
batchFetchComponents,
|
|
@@ -2490,13 +4226,20 @@ export {
|
|
|
2490
4226
|
clearMemoryCache,
|
|
2491
4227
|
clearStyles,
|
|
2492
4228
|
collectAllDependencies,
|
|
4229
|
+
collectAllViewDependencies,
|
|
2493
4230
|
compareVersions,
|
|
2494
4231
|
configureAnalytics,
|
|
2495
4232
|
createRegistry,
|
|
4233
|
+
createServlyRenderer,
|
|
4234
|
+
createViewsMap,
|
|
4235
|
+
deepMerge,
|
|
4236
|
+
deleteValueByPath,
|
|
2496
4237
|
detectCircularDependencies,
|
|
2497
4238
|
extractBindingKeys,
|
|
2498
4239
|
extractDependencies,
|
|
2499
4240
|
extractDependenciesFromCode,
|
|
4241
|
+
extractOverrideDependencies,
|
|
4242
|
+
extractReferencedViewIds,
|
|
2500
4243
|
fetchComponent,
|
|
2501
4244
|
fetchComponentWithDependencies,
|
|
2502
4245
|
formatStyleValue,
|
|
@@ -2504,25 +4247,52 @@ export {
|
|
|
2504
4247
|
generateTestCases,
|
|
2505
4248
|
getAnalytics,
|
|
2506
4249
|
getCacheKey,
|
|
4250
|
+
getCleanupOverrides,
|
|
2507
4251
|
getDependencyTree,
|
|
4252
|
+
getEventSystem,
|
|
2508
4253
|
getFromCache,
|
|
4254
|
+
getLocalStorage,
|
|
2509
4255
|
getLongTaskObserver,
|
|
2510
4256
|
getMemoryCacheSize,
|
|
2511
4257
|
getMemorySampler,
|
|
4258
|
+
getMountOverrides,
|
|
4259
|
+
getOverrideSystem,
|
|
2512
4260
|
getRegistryUrl,
|
|
2513
4261
|
getSessionManager,
|
|
4262
|
+
getSessionStorage,
|
|
4263
|
+
getTailwind,
|
|
4264
|
+
getUrlInfo,
|
|
4265
|
+
getValueByPath,
|
|
4266
|
+
goBack,
|
|
4267
|
+
goForward,
|
|
4268
|
+
hasClass,
|
|
4269
|
+
hasDependencyOverrides,
|
|
4270
|
+
hasOverrides,
|
|
2514
4271
|
hasTemplateSyntax,
|
|
4272
|
+
initServlyTailwind,
|
|
4273
|
+
injectTailwind,
|
|
2515
4274
|
invalidateCache,
|
|
2516
4275
|
isComponentAvailable,
|
|
4276
|
+
isTailwindLoaded,
|
|
2517
4277
|
isValidSpecifier,
|
|
4278
|
+
navigateTo,
|
|
2518
4279
|
parseVersion,
|
|
2519
4280
|
prefetchComponents,
|
|
2520
4281
|
processStyles,
|
|
4282
|
+
removeClass,
|
|
4283
|
+
removeCustomStyles,
|
|
4284
|
+
removeLocalStorage,
|
|
4285
|
+
removeSessionStorage,
|
|
4286
|
+
removeTailwind,
|
|
2521
4287
|
render,
|
|
2522
4288
|
renderDynamicList,
|
|
4289
|
+
renderInShadow,
|
|
4290
|
+
renderNode,
|
|
2523
4291
|
resetAnalytics,
|
|
4292
|
+
resetEventSystem,
|
|
2524
4293
|
resetLongTaskObserver,
|
|
2525
4294
|
resetMemorySampler,
|
|
4295
|
+
resetOverrideSystem,
|
|
2526
4296
|
resetSessionManager,
|
|
2527
4297
|
resolveBindingPath,
|
|
2528
4298
|
resolveTemplate,
|
|
@@ -2533,8 +4303,15 @@ export {
|
|
|
2533
4303
|
runTestCase,
|
|
2534
4304
|
satisfiesVersion,
|
|
2535
4305
|
setInCache,
|
|
4306
|
+
setLocalStorage,
|
|
2536
4307
|
setRegistryUrl,
|
|
4308
|
+
setSessionStorage,
|
|
4309
|
+
setValueByPath,
|
|
4310
|
+
toDomEventName,
|
|
4311
|
+
toReactEventName,
|
|
4312
|
+
toggleClass,
|
|
2537
4313
|
updateStyles,
|
|
4314
|
+
updateTailwindConfig,
|
|
2538
4315
|
validateAssertion,
|
|
2539
4316
|
validateProps
|
|
2540
4317
|
};
|