@servlyadmin/runtime-core 0.1.7 → 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/index.cjs CHANGED
@@ -20,6 +20,167 @@ var __copyProps = (to, from, except, desc) => {
20
20
  };
21
21
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
22
 
23
+ // src/tailwind.ts
24
+ var tailwind_exports = {};
25
+ __export(tailwind_exports, {
26
+ DEFAULT_SERVLY_TAILWIND_CONFIG: () => DEFAULT_SERVLY_TAILWIND_CONFIG,
27
+ addCustomStyles: () => addCustomStyles,
28
+ default: () => tailwind_default,
29
+ getTailwind: () => getTailwind,
30
+ initServlyTailwind: () => initServlyTailwind,
31
+ injectTailwind: () => injectTailwind,
32
+ isTailwindLoaded: () => isTailwindLoaded,
33
+ removeCustomStyles: () => removeCustomStyles,
34
+ removeTailwind: () => removeTailwind,
35
+ updateTailwindConfig: () => updateTailwindConfig
36
+ });
37
+ function injectTailwind(config = {}) {
38
+ return new Promise((resolve, reject) => {
39
+ if (tailwindInjected && tailwindScript) {
40
+ resolve();
41
+ return;
42
+ }
43
+ if (typeof document === "undefined") {
44
+ resolve();
45
+ return;
46
+ }
47
+ if (window.tailwind) {
48
+ tailwindInjected = true;
49
+ config.onReady?.();
50
+ resolve();
51
+ return;
52
+ }
53
+ const {
54
+ cdnUrl = DEFAULT_TAILWIND_CDN,
55
+ config: tailwindConfig,
56
+ plugins = [],
57
+ usePlayCdn = false,
58
+ onReady,
59
+ onError
60
+ } = config;
61
+ const script = document.createElement("script");
62
+ script.src = usePlayCdn ? `${cdnUrl}?plugins=forms,typography,aspect-ratio` : cdnUrl;
63
+ script.async = true;
64
+ script.onload = () => {
65
+ tailwindInjected = true;
66
+ tailwindScript = script;
67
+ if (tailwindConfig && window.tailwind) {
68
+ window.tailwind.config = tailwindConfig;
69
+ }
70
+ onReady?.();
71
+ resolve();
72
+ };
73
+ script.onerror = (event) => {
74
+ const error = new Error(`Failed to load Tailwind CSS from ${cdnUrl}`);
75
+ onError?.(error);
76
+ reject(error);
77
+ };
78
+ document.head.appendChild(script);
79
+ });
80
+ }
81
+ function removeTailwind() {
82
+ if (tailwindScript && tailwindScript.parentNode) {
83
+ tailwindScript.parentNode.removeChild(tailwindScript);
84
+ tailwindScript = null;
85
+ tailwindInjected = false;
86
+ delete window.tailwind;
87
+ }
88
+ }
89
+ function isTailwindLoaded() {
90
+ return tailwindInjected || !!window.tailwind;
91
+ }
92
+ function getTailwind() {
93
+ return window.tailwind;
94
+ }
95
+ function updateTailwindConfig(config) {
96
+ if (window.tailwind) {
97
+ window.tailwind.config = {
98
+ ...window.tailwind.config,
99
+ ...config
100
+ };
101
+ }
102
+ }
103
+ function addCustomStyles(css, id) {
104
+ if (typeof document === "undefined") {
105
+ throw new Error("addCustomStyles can only be used in browser environment");
106
+ }
107
+ const styleId = id || `servly-custom-styles-${Date.now()}`;
108
+ let existingStyle = document.getElementById(styleId);
109
+ if (existingStyle) {
110
+ existingStyle.textContent = css;
111
+ return existingStyle;
112
+ }
113
+ const style = document.createElement("style");
114
+ style.id = styleId;
115
+ style.textContent = css;
116
+ document.head.appendChild(style);
117
+ return style;
118
+ }
119
+ function removeCustomStyles(id) {
120
+ if (typeof document === "undefined") return;
121
+ const style = document.getElementById(id);
122
+ if (style && style.parentNode) {
123
+ style.parentNode.removeChild(style);
124
+ }
125
+ }
126
+ async function initServlyTailwind(customConfig) {
127
+ const config = customConfig ? { ...DEFAULT_SERVLY_TAILWIND_CONFIG, ...customConfig } : DEFAULT_SERVLY_TAILWIND_CONFIG;
128
+ await injectTailwind({
129
+ config,
130
+ usePlayCdn: true
131
+ });
132
+ }
133
+ var DEFAULT_TAILWIND_CDN, tailwindInjected, tailwindScript, DEFAULT_SERVLY_TAILWIND_CONFIG, tailwind_default;
134
+ var init_tailwind = __esm({
135
+ "src/tailwind.ts"() {
136
+ "use strict";
137
+ DEFAULT_TAILWIND_CDN = "https://cdn.tailwindcss.com";
138
+ tailwindInjected = false;
139
+ tailwindScript = null;
140
+ DEFAULT_SERVLY_TAILWIND_CONFIG = {
141
+ theme: {
142
+ extend: {
143
+ // Add any Servly-specific theme extensions here
144
+ }
145
+ },
146
+ // Safelist common dynamic classes
147
+ safelist: [
148
+ // Spacing
149
+ { pattern: /^(p|m|gap)-/ },
150
+ // Sizing
151
+ { pattern: /^(w|h|min-w|min-h|max-w|max-h)-/ },
152
+ // Flexbox
153
+ { pattern: /^(flex|justify|items|self)-/ },
154
+ // Grid
155
+ { pattern: /^(grid|col|row)-/ },
156
+ // Colors
157
+ { pattern: /^(bg|text|border|ring)-/ },
158
+ // Typography
159
+ { pattern: /^(font|text|leading|tracking)-/ },
160
+ // Borders
161
+ { pattern: /^(rounded|border)-/ },
162
+ // Effects
163
+ { pattern: /^(shadow|opacity|blur)-/ },
164
+ // Transforms
165
+ { pattern: /^(scale|rotate|translate|skew)-/ },
166
+ // Transitions
167
+ { pattern: /^(transition|duration|ease|delay)-/ }
168
+ ]
169
+ };
170
+ tailwind_default = {
171
+ injectTailwind,
172
+ removeTailwind,
173
+ isTailwindLoaded,
174
+ getTailwind,
175
+ updateTailwindConfig,
176
+ addCustomStyles,
177
+ removeCustomStyles,
178
+ initServlyTailwind,
179
+ DEFAULT_SERVLY_TAILWIND_CONFIG
180
+ };
181
+ }
182
+ });
183
+
23
184
  // src/registry.ts
24
185
  var registry_exports = {};
25
186
  __export(registry_exports, {
@@ -214,9 +375,16 @@ __export(index_exports, {
214
375
  AnalyticsCollector: () => AnalyticsCollector,
215
376
  DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG,
216
377
  DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
378
+ DEFAULT_SERVLY_TAILWIND_CONFIG: () => DEFAULT_SERVLY_TAILWIND_CONFIG,
379
+ EVENT_HANDLERS: () => EVENT_HANDLERS,
380
+ EventSystem: () => EventSystem,
217
381
  LongTaskObserver: () => LongTaskObserver,
218
382
  MemorySampler: () => MemorySampler,
383
+ OverrideSystem: () => OverrideSystem,
219
384
  SessionManager: () => SessionManager,
385
+ StateManager: () => StateManager,
386
+ addClass: () => addClass,
387
+ addCustomStyles: () => addCustomStyles,
220
388
  analytics: () => analytics,
221
389
  applyStyles: () => applyStyles,
222
390
  batchFetchComponents: () => batchFetchComponents,
@@ -230,13 +398,20 @@ __export(index_exports, {
230
398
  clearMemoryCache: () => clearMemoryCache,
231
399
  clearStyles: () => clearStyles,
232
400
  collectAllDependencies: () => collectAllDependencies,
401
+ collectAllViewDependencies: () => collectAllViewDependencies,
233
402
  compareVersions: () => compareVersions,
234
403
  configureAnalytics: () => configureAnalytics,
235
404
  createRegistry: () => createRegistry,
405
+ createServlyRenderer: () => createServlyRenderer,
406
+ createViewsMap: () => createViewsMap,
407
+ deepMerge: () => deepMerge,
408
+ deleteValueByPath: () => deleteValueByPath,
236
409
  detectCircularDependencies: () => detectCircularDependencies,
237
410
  extractBindingKeys: () => extractBindingKeys,
238
411
  extractDependencies: () => extractDependencies,
239
412
  extractDependenciesFromCode: () => extractDependenciesFromCode,
413
+ extractOverrideDependencies: () => extractOverrideDependencies,
414
+ extractReferencedViewIds: () => extractReferencedViewIds,
240
415
  fetchComponent: () => fetchComponent,
241
416
  fetchComponentWithDependencies: () => fetchComponentWithDependencies,
242
417
  formatStyleValue: () => formatStyleValue,
@@ -244,25 +419,52 @@ __export(index_exports, {
244
419
  generateTestCases: () => generateTestCases,
245
420
  getAnalytics: () => getAnalytics,
246
421
  getCacheKey: () => getCacheKey,
422
+ getCleanupOverrides: () => getCleanupOverrides,
247
423
  getDependencyTree: () => getDependencyTree,
424
+ getEventSystem: () => getEventSystem,
248
425
  getFromCache: () => getFromCache,
426
+ getLocalStorage: () => getLocalStorage,
249
427
  getLongTaskObserver: () => getLongTaskObserver,
250
428
  getMemoryCacheSize: () => getMemoryCacheSize,
251
429
  getMemorySampler: () => getMemorySampler,
430
+ getMountOverrides: () => getMountOverrides,
431
+ getOverrideSystem: () => getOverrideSystem,
252
432
  getRegistryUrl: () => getRegistryUrl,
253
433
  getSessionManager: () => getSessionManager,
434
+ getSessionStorage: () => getSessionStorage,
435
+ getTailwind: () => getTailwind,
436
+ getUrlInfo: () => getUrlInfo,
437
+ getValueByPath: () => getValueByPath,
438
+ goBack: () => goBack,
439
+ goForward: () => goForward,
440
+ hasClass: () => hasClass,
441
+ hasDependencyOverrides: () => hasDependencyOverrides,
442
+ hasOverrides: () => hasOverrides,
254
443
  hasTemplateSyntax: () => hasTemplateSyntax,
444
+ initServlyTailwind: () => initServlyTailwind,
445
+ injectTailwind: () => injectTailwind,
255
446
  invalidateCache: () => invalidateCache,
256
447
  isComponentAvailable: () => isComponentAvailable,
448
+ isTailwindLoaded: () => isTailwindLoaded,
257
449
  isValidSpecifier: () => isValidSpecifier,
450
+ navigateTo: () => navigateTo,
258
451
  parseVersion: () => parseVersion,
259
452
  prefetchComponents: () => prefetchComponents,
260
453
  processStyles: () => processStyles,
454
+ removeClass: () => removeClass,
455
+ removeCustomStyles: () => removeCustomStyles,
456
+ removeLocalStorage: () => removeLocalStorage,
457
+ removeSessionStorage: () => removeSessionStorage,
458
+ removeTailwind: () => removeTailwind,
261
459
  render: () => render,
262
460
  renderDynamicList: () => renderDynamicList,
461
+ renderInShadow: () => renderInShadow,
462
+ renderNode: () => renderNode,
263
463
  resetAnalytics: () => resetAnalytics,
464
+ resetEventSystem: () => resetEventSystem,
264
465
  resetLongTaskObserver: () => resetLongTaskObserver,
265
466
  resetMemorySampler: () => resetMemorySampler,
467
+ resetOverrideSystem: () => resetOverrideSystem,
266
468
  resetSessionManager: () => resetSessionManager,
267
469
  resolveBindingPath: () => resolveBindingPath,
268
470
  resolveTemplate: () => resolveTemplate,
@@ -273,8 +475,15 @@ __export(index_exports, {
273
475
  runTestCase: () => runTestCase,
274
476
  satisfiesVersion: () => satisfiesVersion,
275
477
  setInCache: () => setInCache,
478
+ setLocalStorage: () => setLocalStorage,
276
479
  setRegistryUrl: () => setRegistryUrl,
480
+ setSessionStorage: () => setSessionStorage,
481
+ setValueByPath: () => setValueByPath,
482
+ toDomEventName: () => toDomEventName,
483
+ toReactEventName: () => toReactEventName,
484
+ toggleClass: () => toggleClass,
277
485
  updateStyles: () => updateStyles,
486
+ updateTailwindConfig: () => updateTailwindConfig,
278
487
  validateAssertion: () => validateAssertion,
279
488
  validateProps: () => validateProps
280
489
  });
@@ -799,16 +1008,95 @@ var BINDING_SOURCES = [
799
1008
  "input",
800
1009
  "currentItem",
801
1010
  "localStore",
1011
+ "localStorage",
1012
+ "sessionStorage",
802
1013
  "config",
803
1014
  "element",
804
1015
  "self",
805
1016
  "params",
806
- "query"
1017
+ "query",
1018
+ "window",
1019
+ "bindings",
1020
+ "binding",
1021
+ "boundInputs",
1022
+ "parent"
807
1023
  ];
808
1024
  var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
809
1025
  function hasTemplateSyntax(value) {
810
1026
  return typeof value === "string" && value.includes("{{") && value.includes("}}");
811
1027
  }
1028
+ function getLocalStorageValue(key) {
1029
+ if (typeof localStorage === "undefined") return void 0;
1030
+ try {
1031
+ const stored = localStorage.getItem(key);
1032
+ if (stored === null) return void 0;
1033
+ try {
1034
+ return JSON.parse(stored);
1035
+ } catch {
1036
+ return stored;
1037
+ }
1038
+ } catch {
1039
+ return void 0;
1040
+ }
1041
+ }
1042
+ function getSessionStorageValue(key) {
1043
+ if (typeof sessionStorage === "undefined") return void 0;
1044
+ try {
1045
+ const stored = sessionStorage.getItem(key);
1046
+ if (stored === null) return void 0;
1047
+ try {
1048
+ return JSON.parse(stored);
1049
+ } catch {
1050
+ return stored;
1051
+ }
1052
+ } catch {
1053
+ return void 0;
1054
+ }
1055
+ }
1056
+ function getWindowInfo() {
1057
+ if (typeof window === "undefined") return {};
1058
+ const searchParams = {};
1059
+ try {
1060
+ const urlSearchParams = new URLSearchParams(window.location.search);
1061
+ urlSearchParams.forEach((value, key) => {
1062
+ searchParams[key] = value;
1063
+ });
1064
+ } catch {
1065
+ }
1066
+ return {
1067
+ href: window.location.href,
1068
+ pathname: window.location.pathname,
1069
+ search: window.location.search,
1070
+ hash: window.location.hash,
1071
+ origin: window.location.origin,
1072
+ protocol: window.location.protocol,
1073
+ host: window.location.host,
1074
+ hostname: window.location.hostname,
1075
+ port: window.location.port,
1076
+ searchParams,
1077
+ params: searchParams,
1078
+ innerWidth: window.innerWidth,
1079
+ innerHeight: window.innerHeight,
1080
+ screenWidth: window.screen?.width,
1081
+ screenHeight: window.screen?.height
1082
+ };
1083
+ }
1084
+ function navigatePath(obj, parts) {
1085
+ let current = obj;
1086
+ for (const part of parts) {
1087
+ if (current === null || current === void 0) return void 0;
1088
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1089
+ if (arrayMatch) {
1090
+ const [, propName, indexStr] = arrayMatch;
1091
+ current = current[propName];
1092
+ if (!Array.isArray(current)) return void 0;
1093
+ current = current[parseInt(indexStr, 10)];
1094
+ } else {
1095
+ current = current[part];
1096
+ }
1097
+ }
1098
+ return current;
1099
+ }
812
1100
  function resolveBindingPath(path, context) {
813
1101
  const trimmed = path.trim();
814
1102
  const parts = trimmed.split(".");
@@ -816,17 +1104,70 @@ function resolveBindingPath(path, context) {
816
1104
  return void 0;
817
1105
  }
818
1106
  const prefix = parts[0].toLowerCase();
1107
+ if (prefix === "localstore" || prefix === "localstorage") {
1108
+ if (parts.length === 1) {
1109
+ const all = {};
1110
+ if (typeof localStorage !== "undefined") {
1111
+ for (let i = 0; i < localStorage.length; i++) {
1112
+ const key2 = localStorage.key(i);
1113
+ if (key2) {
1114
+ all[key2] = getLocalStorageValue(key2);
1115
+ }
1116
+ }
1117
+ }
1118
+ return all;
1119
+ }
1120
+ const key = parts[1];
1121
+ const value = getLocalStorageValue(key);
1122
+ if (parts.length === 2) return value;
1123
+ return navigatePath(value, parts.slice(2));
1124
+ }
1125
+ if (prefix === "sessionstorage") {
1126
+ if (parts.length === 1) {
1127
+ const all = {};
1128
+ if (typeof sessionStorage !== "undefined") {
1129
+ for (let i = 0; i < sessionStorage.length; i++) {
1130
+ const key2 = sessionStorage.key(i);
1131
+ if (key2) {
1132
+ all[key2] = getSessionStorageValue(key2);
1133
+ }
1134
+ }
1135
+ }
1136
+ return all;
1137
+ }
1138
+ const key = parts[1];
1139
+ const value = getSessionStorageValue(key);
1140
+ if (parts.length === 2) return value;
1141
+ return navigatePath(value, parts.slice(2));
1142
+ }
1143
+ if (prefix === "window" || prefix === "url") {
1144
+ const windowInfo = getWindowInfo();
1145
+ if (parts.length === 1) return windowInfo;
1146
+ return navigatePath(windowInfo, parts.slice(1));
1147
+ }
1148
+ if (prefix === "params" || prefix === "query") {
1149
+ const windowInfo = getWindowInfo();
1150
+ const params = windowInfo.searchParams || {};
1151
+ if (parts.length === 1) return params;
1152
+ return navigatePath(params, parts.slice(1));
1153
+ }
819
1154
  let source;
820
1155
  let startIndex = 0;
821
- if (prefix === "props" || prefix === "input") {
1156
+ if (prefix === "props" || prefix === "input" || prefix === "bindings" || prefix === "binding" || prefix === "boundinputs" || prefix === "parent") {
822
1157
  source = context.props;
823
1158
  startIndex = 1;
824
1159
  } else if (prefix === "state" || prefix === "appstate") {
825
1160
  source = context.state;
826
1161
  startIndex = 1;
827
- } else if (prefix === "context") {
1162
+ } else if (prefix === "context" || prefix === "config") {
828
1163
  source = context.context;
829
1164
  startIndex = 1;
1165
+ } else if (prefix === "currentitem") {
1166
+ source = context.props;
1167
+ startIndex = 0;
1168
+ } else if (prefix === "self" || prefix === "element") {
1169
+ source = context.state;
1170
+ startIndex = 1;
830
1171
  } else if (BINDING_SOURCES.includes(prefix)) {
831
1172
  source = context.props;
832
1173
  startIndex = 1;
@@ -837,41 +1178,49 @@ function resolveBindingPath(path, context) {
837
1178
  if (!source) {
838
1179
  return void 0;
839
1180
  }
840
- let value = source;
841
- for (let i = startIndex; i < parts.length; i++) {
842
- if (value === null || value === void 0) {
843
- return void 0;
844
- }
845
- value = value[parts[i]];
846
- }
847
- return value;
1181
+ return navigatePath(source, parts.slice(startIndex));
848
1182
  }
849
1183
  function resolveExpression(expression, context) {
850
1184
  const trimmed = expression.trim();
851
- const defaultMatch = trimmed.match(/^(.+?)\|\|(.+)$/);
852
- if (defaultMatch) {
853
- const mainValue = resolveExpression(defaultMatch[1].trim(), context);
854
- if (mainValue !== void 0 && mainValue !== null && mainValue !== "") {
855
- return mainValue;
856
- }
857
- const defaultVal = defaultMatch[2].trim();
858
- if (defaultVal.startsWith('"') && defaultVal.endsWith('"') || defaultVal.startsWith("'") && defaultVal.endsWith("'")) {
859
- return defaultVal.slice(1, -1);
860
- }
861
- if (!isNaN(Number(defaultVal))) {
862
- return Number(defaultVal);
1185
+ const comparisonOperators = ["===", "!==", "==", "!=", ">=", "<=", ">", "<"];
1186
+ for (const op of comparisonOperators) {
1187
+ if (trimmed.includes(op)) {
1188
+ const [left, right] = trimmed.split(op, 2);
1189
+ const leftVal = resolveExpressionValue(left.trim(), context);
1190
+ const rightVal = resolveExpressionValue(right.trim(), context);
1191
+ switch (op) {
1192
+ case "===":
1193
+ return leftVal === rightVal;
1194
+ case "!==":
1195
+ return leftVal !== rightVal;
1196
+ case "==":
1197
+ return leftVal == rightVal;
1198
+ case "!=":
1199
+ return leftVal != rightVal;
1200
+ case ">":
1201
+ return leftVal > rightVal;
1202
+ case "<":
1203
+ return leftVal < rightVal;
1204
+ case ">=":
1205
+ return leftVal >= rightVal;
1206
+ case "<=":
1207
+ return leftVal <= rightVal;
1208
+ }
863
1209
  }
864
- if (defaultVal === "true") return true;
865
- if (defaultVal === "false") return false;
866
- return resolveExpression(defaultVal, context);
867
1210
  }
868
- const ternaryMatch = trimmed.match(/^(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/);
869
- if (ternaryMatch) {
870
- const condition = resolveExpression(ternaryMatch[1].trim(), context);
871
- if (condition) {
872
- return resolveTernaryValue(ternaryMatch[2].trim(), context);
1211
+ if (trimmed.startsWith("!") && !trimmed.startsWith("!=")) {
1212
+ const innerValue = resolveExpression(trimmed.slice(1).trim(), context);
1213
+ return !innerValue;
1214
+ }
1215
+ if (trimmed.includes("||")) {
1216
+ const parts = trimmed.split("||");
1217
+ for (let i = 0; i < parts.length; i++) {
1218
+ const part = parts[i].trim();
1219
+ const value = resolveExpressionValue(part, context);
1220
+ if (value || i === parts.length - 1) {
1221
+ return value;
1222
+ }
873
1223
  }
874
- return resolveTernaryValue(ternaryMatch[3].trim(), context);
875
1224
  }
876
1225
  if (trimmed.includes("&&")) {
877
1226
  const parts = trimmed.split("&&");
@@ -881,6 +1230,28 @@ function resolveExpression(expression, context) {
881
1230
  }
882
1231
  return resolveExpression(parts[parts.length - 1].trim(), context);
883
1232
  }
1233
+ const ternaryMatch = trimmed.match(/^(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/);
1234
+ if (ternaryMatch) {
1235
+ const condition = resolveExpression(ternaryMatch[1].trim(), context);
1236
+ if (condition) {
1237
+ return resolveTernaryValue(ternaryMatch[2].trim(), context);
1238
+ }
1239
+ return resolveTernaryValue(ternaryMatch[3].trim(), context);
1240
+ }
1241
+ return resolveExpressionValue(trimmed, context);
1242
+ }
1243
+ function resolveExpressionValue(value, context) {
1244
+ const trimmed = value.trim();
1245
+ if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
1246
+ return trimmed.slice(1, -1);
1247
+ }
1248
+ if (!isNaN(Number(trimmed)) && trimmed !== "") {
1249
+ return Number(trimmed);
1250
+ }
1251
+ if (trimmed === "true") return true;
1252
+ if (trimmed === "false") return false;
1253
+ if (trimmed === "null") return null;
1254
+ if (trimmed === "undefined") return void 0;
884
1255
  return resolveBindingPath(trimmed, context);
885
1256
  }
886
1257
  function resolveTernaryValue(value, context) {
@@ -912,7 +1283,7 @@ function resolveTemplate(template, context, componentId) {
912
1283
  }
913
1284
  return String(value);
914
1285
  }
915
- return template.replace(TEMPLATE_REGEX, (match, expression) => {
1286
+ return template.replace(TEMPLATE_REGEX, (_match, expression) => {
916
1287
  const value = resolveExpression(expression, context);
917
1288
  if (value === void 0 || value === null) {
918
1289
  return "";
@@ -1342,131 +1713,1180 @@ function resetLongTaskObserver() {
1342
1713
  longTaskObserverInstance = null;
1343
1714
  }
1344
1715
 
1345
- // src/renderer.ts
1346
- var COMPONENT_TO_TAG = {
1347
- container: "div",
1348
- text: "span",
1349
- button: "button",
1350
- input: "input",
1351
- image: "img",
1352
- link: "a",
1353
- form: "form",
1354
- label: "label",
1355
- textarea: "textarea",
1356
- select: "select",
1357
- option: "option",
1358
- list: "ul",
1359
- listItem: "li",
1360
- heading: "h1",
1361
- paragraph: "p",
1362
- section: "section",
1363
- article: "article",
1364
- header: "header",
1365
- footer: "footer",
1366
- nav: "nav",
1367
- aside: "aside",
1368
- main: "main",
1369
- span: "span",
1370
- div: "div"
1371
- };
1372
- var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
1373
- "input",
1374
- "img",
1375
- "br",
1376
- "hr",
1377
- "area",
1378
- "base",
1379
- "col",
1380
- "embed",
1381
- "link",
1382
- "meta",
1383
- "param",
1384
- "source",
1385
- "track",
1386
- "wbr"
1387
- ]);
1388
- function getElementTag(element) {
1389
- const config = element.configuration;
1390
- if (config?.tag) {
1391
- return config.tag;
1716
+ // src/stateManager.ts
1717
+ var StateManager = class {
1718
+ constructor(config = {}) {
1719
+ this.state = {};
1720
+ this.listeners = /* @__PURE__ */ new Set();
1721
+ this.config = config;
1722
+ this.state = config.initialState || {};
1723
+ if (config.persistToLocalStorage && typeof localStorage !== "undefined") {
1724
+ this.loadFromLocalStorage();
1725
+ }
1726
+ if (config.onStateChange) {
1727
+ this.listeners.add(config.onStateChange);
1728
+ }
1392
1729
  }
1393
- if (element.componentId && COMPONENT_TO_TAG[element.componentId]) {
1394
- return COMPONENT_TO_TAG[element.componentId];
1730
+ /**
1731
+ * Get value by path from state
1732
+ */
1733
+ get(path) {
1734
+ return getValueByPath(this.state, path);
1395
1735
  }
1396
- if (element.isGroup) {
1397
- return "div";
1736
+ /**
1737
+ * Get the entire state object
1738
+ */
1739
+ getState() {
1740
+ return { ...this.state };
1398
1741
  }
1399
- return "div";
1400
- }
1401
- function isSelfClosing(tag) {
1402
- return SELF_CLOSING_TAGS.has(tag.toLowerCase());
1403
- }
1404
- function buildTree(elements) {
1405
- const tree = /* @__PURE__ */ new Map();
1406
- for (const element of elements) {
1407
- const parentId = element.parent || null;
1408
- if (!tree.has(parentId)) {
1409
- tree.set(parentId, []);
1410
- }
1411
- tree.get(parentId).push(element);
1742
+ /**
1743
+ * Set a value in state
1744
+ */
1745
+ set(key, value, elementId) {
1746
+ const previousValue = this.get(key);
1747
+ setValueByPath(this.state, key, value);
1748
+ this.notifyChange({
1749
+ key,
1750
+ value,
1751
+ previousValue,
1752
+ operation: "set",
1753
+ elementId,
1754
+ timestamp: Date.now()
1755
+ });
1412
1756
  }
1413
- return tree;
1414
- }
1415
- function getTextContent(element, context) {
1416
- const config = element.configuration;
1417
- if (config?.dynamicText) {
1418
- return resolveTemplate(config.dynamicText, context);
1757
+ /**
1758
+ * Merge an object into state at the given path
1759
+ */
1760
+ merge(key, value, deep = false, elementId) {
1761
+ const previousValue = this.get(key);
1762
+ const currentValue = previousValue || {};
1763
+ const newValue = deep ? deepMerge(currentValue, value) : { ...currentValue, ...value };
1764
+ setValueByPath(this.state, key, newValue);
1765
+ this.notifyChange({
1766
+ key,
1767
+ value: newValue,
1768
+ previousValue,
1769
+ operation: "merge",
1770
+ elementId,
1771
+ timestamp: Date.now()
1772
+ });
1419
1773
  }
1420
- if (config?.text) {
1421
- if (hasTemplateSyntax(config.text)) {
1422
- return resolveTemplate(config.text, context);
1423
- }
1424
- return config.text;
1774
+ /**
1775
+ * Delete a key from state
1776
+ */
1777
+ delete(key, elementId) {
1778
+ const previousValue = this.get(key);
1779
+ deleteValueByPath(this.state, key);
1780
+ this.notifyChange({
1781
+ key,
1782
+ value: void 0,
1783
+ previousValue,
1784
+ operation: "delete",
1785
+ elementId,
1786
+ timestamp: Date.now()
1787
+ });
1425
1788
  }
1426
- return "";
1427
- }
1428
- function applyAttributes(domElement, element, context) {
1429
- const config = element.configuration || {};
1430
- const attributeMap = [
1431
- { key: "id", attr: "id" },
1432
- { key: "src", dynamicKey: "dynamicSrc", attr: "src" },
1433
- { key: "alt", attr: "alt" },
1434
- { key: "href", dynamicKey: "dynamicHref", attr: "href" },
1435
- { key: "target", attr: "target" },
1436
- { key: "placeholder", attr: "placeholder" },
1437
- { key: "type", attr: "type" },
1438
- { key: "name", attr: "name" },
1439
- { key: "value", dynamicKey: "dynamicValue", attr: "value" }
1440
- ];
1441
- for (const { key, dynamicKey, attr } of attributeMap) {
1442
- const dynamicValue = dynamicKey ? config[dynamicKey] : void 0;
1443
- if (dynamicValue !== void 0 && dynamicValue !== null && dynamicValue !== "") {
1444
- const resolved = resolveTemplate(String(dynamicValue), context);
1445
- if (resolved) {
1446
- domElement.setAttribute(attr, resolved);
1789
+ /**
1790
+ * Append to an array in state
1791
+ */
1792
+ append(key, value, elementId) {
1793
+ const previousValue = this.get(key);
1794
+ const currentArray = Array.isArray(previousValue) ? [...previousValue] : [];
1795
+ currentArray.push(value);
1796
+ setValueByPath(this.state, key, currentArray);
1797
+ this.notifyChange({
1798
+ key,
1799
+ value: currentArray,
1800
+ previousValue,
1801
+ operation: "append",
1802
+ elementId,
1803
+ timestamp: Date.now()
1804
+ });
1805
+ }
1806
+ /**
1807
+ * Prepend to an array in state
1808
+ */
1809
+ prepend(key, value, elementId) {
1810
+ const previousValue = this.get(key);
1811
+ const currentArray = Array.isArray(previousValue) ? [...previousValue] : [];
1812
+ currentArray.unshift(value);
1813
+ setValueByPath(this.state, key, currentArray);
1814
+ this.notifyChange({
1815
+ key,
1816
+ value: currentArray,
1817
+ previousValue,
1818
+ operation: "prepend",
1819
+ elementId,
1820
+ timestamp: Date.now()
1821
+ });
1822
+ }
1823
+ /**
1824
+ * Toggle a boolean value in state
1825
+ */
1826
+ toggle(key, elementId) {
1827
+ const previousValue = this.get(key);
1828
+ const newValue = !previousValue;
1829
+ setValueByPath(this.state, key, newValue);
1830
+ this.notifyChange({
1831
+ key,
1832
+ value: newValue,
1833
+ previousValue,
1834
+ operation: "toggle",
1835
+ elementId,
1836
+ timestamp: Date.now()
1837
+ });
1838
+ }
1839
+ /**
1840
+ * Subscribe to state changes
1841
+ */
1842
+ subscribe(listener) {
1843
+ this.listeners.add(listener);
1844
+ return () => this.listeners.delete(listener);
1845
+ }
1846
+ /**
1847
+ * Notify all listeners of a state change
1848
+ */
1849
+ notifyChange(event) {
1850
+ if (this.config.persistToLocalStorage) {
1851
+ this.saveToLocalStorage();
1852
+ }
1853
+ for (const listener of this.listeners) {
1854
+ try {
1855
+ listener(event);
1856
+ } catch (error) {
1857
+ console.error("State change listener error:", error);
1447
1858
  }
1448
- continue;
1449
1859
  }
1450
- const staticValue = config[key];
1451
- if (staticValue !== void 0 && staticValue !== null && staticValue !== "") {
1452
- const resolved = hasTemplateSyntax(String(staticValue)) ? resolveTemplate(String(staticValue), context) : String(staticValue);
1453
- if (resolved) {
1454
- domElement.setAttribute(attr, resolved);
1860
+ }
1861
+ /**
1862
+ * Load state from localStorage
1863
+ */
1864
+ loadFromLocalStorage() {
1865
+ try {
1866
+ const prefix = this.config.localStoragePrefix || "servly_state_";
1867
+ const stored = localStorage.getItem(`${prefix}state`);
1868
+ if (stored) {
1869
+ const parsed = JSON.parse(stored);
1870
+ this.state = { ...this.state, ...parsed };
1455
1871
  }
1872
+ } catch (error) {
1873
+ console.warn("Failed to load state from localStorage:", error);
1456
1874
  }
1457
1875
  }
1458
- if (config.disabled) domElement.setAttribute("disabled", "");
1459
- if (config.required) domElement.setAttribute("required", "");
1460
- if (config.readOnly) domElement.setAttribute("readonly", "");
1461
- for (const [key, value] of Object.entries(config)) {
1462
- if (key.startsWith("data-") && value !== void 0) {
1463
- const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
1464
- domElement.setAttribute(key, resolved);
1876
+ /**
1877
+ * Save state to localStorage
1878
+ */
1879
+ saveToLocalStorage() {
1880
+ try {
1881
+ const prefix = this.config.localStoragePrefix || "servly_state_";
1882
+ localStorage.setItem(`${prefix}state`, JSON.stringify(this.state));
1883
+ } catch (error) {
1884
+ console.warn("Failed to save state to localStorage:", error);
1465
1885
  }
1466
1886
  }
1467
- for (const [key, value] of Object.entries(config)) {
1468
- if (key.startsWith("aria-") && value !== void 0) {
1469
- const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
1887
+ /**
1888
+ * Clear all state
1889
+ */
1890
+ clear() {
1891
+ const previousState = { ...this.state };
1892
+ this.state = {};
1893
+ if (this.config.persistToLocalStorage) {
1894
+ try {
1895
+ const prefix = this.config.localStoragePrefix || "servly_state_";
1896
+ localStorage.removeItem(`${prefix}state`);
1897
+ } catch (error) {
1898
+ console.warn("Failed to clear localStorage:", error);
1899
+ }
1900
+ }
1901
+ this.notifyChange({
1902
+ key: "",
1903
+ value: {},
1904
+ previousValue: previousState,
1905
+ operation: "delete",
1906
+ timestamp: Date.now()
1907
+ });
1908
+ }
1909
+ };
1910
+ function getValueByPath(obj, path) {
1911
+ if (!obj || !path) return void 0;
1912
+ const parts = path.split(".");
1913
+ let current = obj;
1914
+ for (const part of parts) {
1915
+ if (current === null || current === void 0) return void 0;
1916
+ const arrayMatch = part.match(/^(\w+)\[(\d+)\]$/);
1917
+ if (arrayMatch) {
1918
+ const [, propName, indexStr] = arrayMatch;
1919
+ current = current[propName];
1920
+ if (!Array.isArray(current)) return void 0;
1921
+ current = current[parseInt(indexStr, 10)];
1922
+ } else {
1923
+ current = current[part];
1924
+ }
1925
+ }
1926
+ return current;
1927
+ }
1928
+ function setValueByPath(obj, path, value) {
1929
+ if (!obj || !path) return;
1930
+ const parts = path.split(".");
1931
+ let current = obj;
1932
+ for (let i = 0; i < parts.length - 1; i++) {
1933
+ const part = parts[i];
1934
+ const arrayMatch2 = part.match(/^(\w+)\[(\d+)\]$/);
1935
+ if (arrayMatch2) {
1936
+ const [, propName, indexStr] = arrayMatch2;
1937
+ if (!current[propName]) current[propName] = [];
1938
+ const index = parseInt(indexStr, 10);
1939
+ if (!current[propName][index]) current[propName][index] = {};
1940
+ current = current[propName][index];
1941
+ } else {
1942
+ if (!current[part]) current[part] = {};
1943
+ current = current[part];
1944
+ }
1945
+ }
1946
+ const lastPart = parts[parts.length - 1];
1947
+ const arrayMatch = lastPart.match(/^(\w+)\[(\d+)\]$/);
1948
+ if (arrayMatch) {
1949
+ const [, propName, indexStr] = arrayMatch;
1950
+ if (!current[propName]) current[propName] = [];
1951
+ current[propName][parseInt(indexStr, 10)] = value;
1952
+ } else {
1953
+ current[lastPart] = value;
1954
+ }
1955
+ }
1956
+ function deleteValueByPath(obj, path) {
1957
+ if (!obj || !path) return;
1958
+ const parts = path.split(".");
1959
+ let current = obj;
1960
+ for (let i = 0; i < parts.length - 1; i++) {
1961
+ const part = parts[i];
1962
+ if (current[part] === void 0) return;
1963
+ current = current[part];
1964
+ }
1965
+ const lastPart = parts[parts.length - 1];
1966
+ delete current[lastPart];
1967
+ }
1968
+ function deepMerge(target, source) {
1969
+ if (!source) return target;
1970
+ if (!target) return source;
1971
+ const result = { ...target };
1972
+ for (const key of Object.keys(source)) {
1973
+ if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key]) && target[key] && typeof target[key] === "object" && !Array.isArray(target[key])) {
1974
+ result[key] = deepMerge(target[key], source[key]);
1975
+ } else {
1976
+ result[key] = source[key];
1977
+ }
1978
+ }
1979
+ return result;
1980
+ }
1981
+ function addClass(currentClasses, classToAdd) {
1982
+ const classes = currentClasses.split(/\s+/).filter(Boolean);
1983
+ if (!classes.includes(classToAdd)) {
1984
+ classes.push(classToAdd);
1985
+ }
1986
+ return classes.join(" ");
1987
+ }
1988
+ function removeClass(currentClasses, classToRemove) {
1989
+ return currentClasses.split(/\s+/).filter((cls) => cls && cls !== classToRemove).join(" ");
1990
+ }
1991
+ function toggleClass(currentClasses, classToToggle) {
1992
+ const classes = currentClasses.split(/\s+/).filter(Boolean);
1993
+ const index = classes.indexOf(classToToggle);
1994
+ if (index > -1) {
1995
+ classes.splice(index, 1);
1996
+ } else {
1997
+ classes.push(classToToggle);
1998
+ }
1999
+ return classes.join(" ");
2000
+ }
2001
+ function hasClass(currentClasses, classToCheck) {
2002
+ return currentClasses.split(/\s+/).includes(classToCheck);
2003
+ }
2004
+ function getLocalStorage(key, defaultValue) {
2005
+ if (typeof localStorage === "undefined") return defaultValue;
2006
+ try {
2007
+ const stored = localStorage.getItem(key);
2008
+ if (stored === null) return defaultValue;
2009
+ return JSON.parse(stored);
2010
+ } catch {
2011
+ return localStorage.getItem(key) ?? defaultValue;
2012
+ }
2013
+ }
2014
+ function setLocalStorage(key, value) {
2015
+ if (typeof localStorage === "undefined") return;
2016
+ try {
2017
+ localStorage.setItem(key, JSON.stringify(value));
2018
+ } catch (error) {
2019
+ console.warn("Failed to set localStorage:", error);
2020
+ }
2021
+ }
2022
+ function removeLocalStorage(key) {
2023
+ if (typeof localStorage === "undefined") return;
2024
+ localStorage.removeItem(key);
2025
+ }
2026
+ function getSessionStorage(key, defaultValue) {
2027
+ if (typeof sessionStorage === "undefined") return defaultValue;
2028
+ try {
2029
+ const stored = sessionStorage.getItem(key);
2030
+ if (stored === null) return defaultValue;
2031
+ return JSON.parse(stored);
2032
+ } catch {
2033
+ return sessionStorage.getItem(key) ?? defaultValue;
2034
+ }
2035
+ }
2036
+ function setSessionStorage(key, value) {
2037
+ if (typeof sessionStorage === "undefined") return;
2038
+ try {
2039
+ sessionStorage.setItem(key, JSON.stringify(value));
2040
+ } catch (error) {
2041
+ console.warn("Failed to set sessionStorage:", error);
2042
+ }
2043
+ }
2044
+ function removeSessionStorage(key) {
2045
+ if (typeof sessionStorage === "undefined") return;
2046
+ sessionStorage.removeItem(key);
2047
+ }
2048
+ function navigateTo(url, options = {}) {
2049
+ if (typeof window === "undefined") return;
2050
+ const { replace = false, state, newTab = false } = options;
2051
+ if (newTab) {
2052
+ window.open(url, "_blank");
2053
+ return;
2054
+ }
2055
+ if (url.startsWith("http://") || url.startsWith("https://")) {
2056
+ if (replace) {
2057
+ window.location.replace(url);
2058
+ } else {
2059
+ window.location.href = url;
2060
+ }
2061
+ return;
2062
+ }
2063
+ if (url.startsWith("#")) {
2064
+ window.location.hash = url;
2065
+ return;
2066
+ }
2067
+ if (replace) {
2068
+ window.history.replaceState(state, "", url);
2069
+ } else {
2070
+ window.history.pushState(state, "", url);
2071
+ }
2072
+ window.dispatchEvent(new PopStateEvent("popstate", { state }));
2073
+ }
2074
+ function goBack() {
2075
+ if (typeof window === "undefined") return;
2076
+ window.history.back();
2077
+ }
2078
+ function goForward() {
2079
+ if (typeof window === "undefined") return;
2080
+ window.history.forward();
2081
+ }
2082
+ function getUrlInfo() {
2083
+ if (typeof window === "undefined") {
2084
+ return {
2085
+ href: "",
2086
+ pathname: "",
2087
+ search: "",
2088
+ hash: "",
2089
+ searchParams: {}
2090
+ };
2091
+ }
2092
+ const searchParams = {};
2093
+ const urlSearchParams = new URLSearchParams(window.location.search);
2094
+ urlSearchParams.forEach((value, key) => {
2095
+ searchParams[key] = value;
2096
+ });
2097
+ return {
2098
+ href: window.location.href,
2099
+ pathname: window.location.pathname,
2100
+ search: window.location.search,
2101
+ hash: window.location.hash,
2102
+ searchParams
2103
+ };
2104
+ }
2105
+
2106
+ // src/eventSystem.ts
2107
+ var builtInPlugins = {
2108
+ /**
2109
+ * Set state value
2110
+ * Mirrors: state-setState from actions.ts
2111
+ */
2112
+ "state-setState": (action, ctx) => {
2113
+ const { stateConfig } = action.config || {};
2114
+ if (!stateConfig || !ctx.stateManager) return;
2115
+ const config = typeof stateConfig === "string" ? JSON.parse(stateConfig) : stateConfig;
2116
+ const { key, value, operation = "set" } = config;
2117
+ if (!key) return;
2118
+ switch (operation) {
2119
+ case "set":
2120
+ ctx.stateManager.set(key, value, ctx.elementId);
2121
+ break;
2122
+ case "merge":
2123
+ ctx.stateManager.merge(key, value, false, ctx.elementId);
2124
+ break;
2125
+ case "deepMerge":
2126
+ ctx.stateManager.merge(key, value, true, ctx.elementId);
2127
+ break;
2128
+ case "toggle":
2129
+ ctx.stateManager.toggle(key, ctx.elementId);
2130
+ break;
2131
+ case "append":
2132
+ ctx.stateManager.append(key, value, ctx.elementId);
2133
+ break;
2134
+ case "prepend":
2135
+ ctx.stateManager.prepend(key, value, ctx.elementId);
2136
+ break;
2137
+ case "delete":
2138
+ ctx.stateManager.delete(key, ctx.elementId);
2139
+ break;
2140
+ case "increment":
2141
+ const currentVal = ctx.stateManager.get(key) || 0;
2142
+ ctx.stateManager.set(key, currentVal + (value || 1), ctx.elementId);
2143
+ break;
2144
+ case "decrement":
2145
+ const currVal = ctx.stateManager.get(key) || 0;
2146
+ ctx.stateManager.set(key, currVal - (value || 1), ctx.elementId);
2147
+ break;
2148
+ }
2149
+ return { success: true, key, operation };
2150
+ },
2151
+ /**
2152
+ * Navigate to URL
2153
+ * Mirrors: navigateTo from actions.ts
2154
+ */
2155
+ "navigateTo": (action, ctx) => {
2156
+ const { url, replace, newTab, state } = action.config || {};
2157
+ if (!url) return;
2158
+ navigateTo(url, { replace, newTab, state });
2159
+ return { success: true, url };
2160
+ },
2161
+ /**
2162
+ * Set localStorage value
2163
+ */
2164
+ "localStorage-set": (action, ctx) => {
2165
+ const { key, value } = action.config || {};
2166
+ if (!key) return;
2167
+ setLocalStorage(key, value);
2168
+ return { success: true, key };
2169
+ },
2170
+ /**
2171
+ * Get localStorage value
2172
+ */
2173
+ "localStorage-get": (action, ctx) => {
2174
+ const { key, defaultValue } = action.config || {};
2175
+ if (!key) return defaultValue;
2176
+ return getLocalStorage(key, defaultValue);
2177
+ },
2178
+ /**
2179
+ * Remove localStorage value
2180
+ */
2181
+ "localStorage-remove": (action, ctx) => {
2182
+ const { key } = action.config || {};
2183
+ if (!key) return;
2184
+ if (typeof localStorage !== "undefined") {
2185
+ localStorage.removeItem(key);
2186
+ }
2187
+ return { success: true, key };
2188
+ },
2189
+ /**
2190
+ * Set sessionStorage value
2191
+ */
2192
+ "sessionStorage-set": (action, ctx) => {
2193
+ const { key, value } = action.config || {};
2194
+ if (!key) return;
2195
+ setSessionStorage(key, value);
2196
+ return { success: true, key };
2197
+ },
2198
+ /**
2199
+ * Get sessionStorage value
2200
+ */
2201
+ "sessionStorage-get": (action, ctx) => {
2202
+ const { key, defaultValue } = action.config || {};
2203
+ if (!key) return defaultValue;
2204
+ return getSessionStorage(key, defaultValue);
2205
+ },
2206
+ /**
2207
+ * Console log (for debugging)
2208
+ */
2209
+ "console-log": (action, ctx) => {
2210
+ const { message, data } = action.config || {};
2211
+ console.log("[Servly]", message, data);
2212
+ return { success: true };
2213
+ },
2214
+ /**
2215
+ * Show alert
2216
+ */
2217
+ "alert": (action, ctx) => {
2218
+ const { message } = action.config || {};
2219
+ if (typeof alert !== "undefined") {
2220
+ alert(message);
2221
+ }
2222
+ return { success: true };
2223
+ },
2224
+ /**
2225
+ * Copy to clipboard
2226
+ */
2227
+ "clipboard-copy": async (action, ctx) => {
2228
+ const { text } = action.config || {};
2229
+ if (!text || typeof navigator === "undefined") return { success: false };
2230
+ try {
2231
+ await navigator.clipboard.writeText(text);
2232
+ return { success: true };
2233
+ } catch (error) {
2234
+ return { success: false, error };
2235
+ }
2236
+ },
2237
+ /**
2238
+ * Scroll to element
2239
+ */
2240
+ "scrollTo": (action, ctx) => {
2241
+ const { selector, behavior = "smooth", block = "start" } = action.config || {};
2242
+ if (!selector || typeof document === "undefined") return;
2243
+ const element = document.querySelector(selector);
2244
+ if (element) {
2245
+ element.scrollIntoView({ behavior, block });
2246
+ return { success: true };
2247
+ }
2248
+ return { success: false, error: "Element not found" };
2249
+ },
2250
+ /**
2251
+ * Focus element
2252
+ */
2253
+ "focus": (action, ctx) => {
2254
+ const { selector } = action.config || {};
2255
+ if (!selector || typeof document === "undefined") return;
2256
+ const element = document.querySelector(selector);
2257
+ if (element && typeof element.focus === "function") {
2258
+ element.focus();
2259
+ return { success: true };
2260
+ }
2261
+ return { success: false, error: "Element not found" };
2262
+ },
2263
+ /**
2264
+ * Blur element
2265
+ */
2266
+ "blur": (action, ctx) => {
2267
+ const { selector } = action.config || {};
2268
+ if (!selector || typeof document === "undefined") return;
2269
+ const element = document.querySelector(selector);
2270
+ if (element && typeof element.blur === "function") {
2271
+ element.blur();
2272
+ return { success: true };
2273
+ }
2274
+ return { success: false, error: "Element not found" };
2275
+ },
2276
+ /**
2277
+ * Add class to element
2278
+ */
2279
+ "addClass": (action, ctx) => {
2280
+ const { selector, className } = action.config || {};
2281
+ if (!selector || !className || typeof document === "undefined") return;
2282
+ const element = document.querySelector(selector);
2283
+ if (element) {
2284
+ element.classList.add(className);
2285
+ return { success: true };
2286
+ }
2287
+ return { success: false, error: "Element not found" };
2288
+ },
2289
+ /**
2290
+ * Remove class from element
2291
+ */
2292
+ "removeClass": (action, ctx) => {
2293
+ const { selector, className } = action.config || {};
2294
+ if (!selector || !className || typeof document === "undefined") return;
2295
+ const element = document.querySelector(selector);
2296
+ if (element) {
2297
+ element.classList.remove(className);
2298
+ return { success: true };
2299
+ }
2300
+ return { success: false, error: "Element not found" };
2301
+ },
2302
+ /**
2303
+ * Toggle class on element
2304
+ */
2305
+ "toggleClass": (action, ctx) => {
2306
+ const { selector, className } = action.config || {};
2307
+ if (!selector || !className || typeof document === "undefined") return;
2308
+ const element = document.querySelector(selector);
2309
+ if (element) {
2310
+ element.classList.toggle(className);
2311
+ return { success: true };
2312
+ }
2313
+ return { success: false, error: "Element not found" };
2314
+ },
2315
+ /**
2316
+ * Set element attribute
2317
+ */
2318
+ "setAttribute": (action, ctx) => {
2319
+ const { selector, attribute, value } = action.config || {};
2320
+ if (!selector || !attribute || typeof document === "undefined") return;
2321
+ const element = document.querySelector(selector);
2322
+ if (element) {
2323
+ element.setAttribute(attribute, value);
2324
+ return { success: true };
2325
+ }
2326
+ return { success: false, error: "Element not found" };
2327
+ },
2328
+ /**
2329
+ * Remove element attribute
2330
+ */
2331
+ "removeAttribute": (action, ctx) => {
2332
+ const { selector, attribute } = action.config || {};
2333
+ if (!selector || !attribute || typeof document === "undefined") return;
2334
+ const element = document.querySelector(selector);
2335
+ if (element) {
2336
+ element.removeAttribute(attribute);
2337
+ return { success: true };
2338
+ }
2339
+ return { success: false, error: "Element not found" };
2340
+ },
2341
+ /**
2342
+ * Dispatch custom event
2343
+ */
2344
+ "dispatchEvent": (action, ctx) => {
2345
+ const { selector, eventName, detail } = action.config || {};
2346
+ if (!eventName || typeof document === "undefined") return;
2347
+ const target = selector ? document.querySelector(selector) : document;
2348
+ if (target) {
2349
+ const event = new CustomEvent(eventName, { detail, bubbles: true });
2350
+ target.dispatchEvent(event);
2351
+ return { success: true };
2352
+ }
2353
+ return { success: false, error: "Target not found" };
2354
+ },
2355
+ /**
2356
+ * Delay execution
2357
+ */
2358
+ "delay": async (action, ctx) => {
2359
+ const { ms = 0 } = action.config || {};
2360
+ await new Promise((resolve) => setTimeout(resolve, ms));
2361
+ return { success: true };
2362
+ },
2363
+ /**
2364
+ * Conditional execution
2365
+ */
2366
+ "condition": (action, ctx) => {
2367
+ const { condition, thenActions, elseActions } = action.config || {};
2368
+ return { condition, thenActions, elseActions };
2369
+ }
2370
+ };
2371
+ var EventSystem = class {
2372
+ constructor(config = {}) {
2373
+ this.debounceTimers = /* @__PURE__ */ new Map();
2374
+ this.throttleTimers = /* @__PURE__ */ new Map();
2375
+ this.config = config;
2376
+ this.pluginExecutors = {
2377
+ ...builtInPlugins,
2378
+ ...config.pluginExecutors
2379
+ };
2380
+ }
2381
+ /**
2382
+ * Register a custom plugin executor
2383
+ */
2384
+ registerPlugin(key, executor) {
2385
+ this.pluginExecutors[key] = executor;
2386
+ }
2387
+ /**
2388
+ * Create an event handler from Servly plugin format
2389
+ */
2390
+ createHandler(elementId, handlerConfig, context, options = {}) {
2391
+ return (event) => {
2392
+ if (handlerConfig.preventDefault || options.preventDefault) {
2393
+ event.preventDefault();
2394
+ }
2395
+ if (handlerConfig.stopPropagation || options.stopPropagation) {
2396
+ event.stopPropagation();
2397
+ }
2398
+ if (this.config.onEvent) {
2399
+ this.config.onEvent(event.type, elementId, event);
2400
+ }
2401
+ if (handlerConfig.plugins && handlerConfig.plugins.length > 0) {
2402
+ this.executePlugins(handlerConfig.plugins, {
2403
+ event,
2404
+ elementId,
2405
+ context,
2406
+ stateManager: this.config.stateManager
2407
+ });
2408
+ }
2409
+ };
2410
+ }
2411
+ /**
2412
+ * Execute a sequence of plugin actions
2413
+ */
2414
+ async executePlugins(plugins, eventContext) {
2415
+ const results = [];
2416
+ for (const action of plugins) {
2417
+ try {
2418
+ const executor = this.pluginExecutors[action.key];
2419
+ if (executor) {
2420
+ const result = await executor(action, eventContext);
2421
+ results.push(result);
2422
+ if (this.config.onPluginExecute) {
2423
+ this.config.onPluginExecute(action, result);
2424
+ }
2425
+ } else {
2426
+ console.warn(`[EventSystem] Unknown plugin: ${action.key}`);
2427
+ results.push({ error: `Unknown plugin: ${action.key}` });
2428
+ }
2429
+ } catch (error) {
2430
+ console.error(`[EventSystem] Plugin error (${action.key}):`, error);
2431
+ results.push({ error });
2432
+ }
2433
+ }
2434
+ return results;
2435
+ }
2436
+ /**
2437
+ * Create a debounced event handler
2438
+ */
2439
+ createDebouncedHandler(elementId, handler, delay) {
2440
+ const key = `${elementId}-debounce`;
2441
+ return (event) => {
2442
+ const existingTimer = this.debounceTimers.get(key);
2443
+ if (existingTimer) {
2444
+ clearTimeout(existingTimer);
2445
+ }
2446
+ const timer = setTimeout(() => {
2447
+ handler(event);
2448
+ this.debounceTimers.delete(key);
2449
+ }, delay);
2450
+ this.debounceTimers.set(key, timer);
2451
+ };
2452
+ }
2453
+ /**
2454
+ * Create a throttled event handler
2455
+ */
2456
+ createThrottledHandler(elementId, handler, delay) {
2457
+ const key = `${elementId}-throttle`;
2458
+ return (event) => {
2459
+ if (this.throttleTimers.get(key)) {
2460
+ return;
2461
+ }
2462
+ handler(event);
2463
+ this.throttleTimers.set(key, true);
2464
+ setTimeout(() => {
2465
+ this.throttleTimers.delete(key);
2466
+ }, delay);
2467
+ };
2468
+ }
2469
+ /**
2470
+ * Clean up all timers
2471
+ */
2472
+ destroy() {
2473
+ for (const timer of this.debounceTimers.values()) {
2474
+ clearTimeout(timer);
2475
+ }
2476
+ this.debounceTimers.clear();
2477
+ this.throttleTimers.clear();
2478
+ }
2479
+ };
2480
+ var EVENT_HANDLERS = {
2481
+ onClick: "click",
2482
+ onDoubleClick: "dblclick",
2483
+ onMouseDown: "mousedown",
2484
+ onMouseUp: "mouseup",
2485
+ onMouseEnter: "mouseenter",
2486
+ onMouseLeave: "mouseleave",
2487
+ onMouseMove: "mousemove",
2488
+ onMouseOver: "mouseover",
2489
+ onMouseOut: "mouseout",
2490
+ onKeyDown: "keydown",
2491
+ onKeyUp: "keyup",
2492
+ onKeyPress: "keypress",
2493
+ onFocus: "focus",
2494
+ onBlur: "blur",
2495
+ onChange: "change",
2496
+ onInput: "input",
2497
+ onSubmit: "submit",
2498
+ onReset: "reset",
2499
+ onScroll: "scroll",
2500
+ onWheel: "wheel",
2501
+ onDragStart: "dragstart",
2502
+ onDrag: "drag",
2503
+ onDragEnd: "dragend",
2504
+ onDragEnter: "dragenter",
2505
+ onDragLeave: "dragleave",
2506
+ onDragOver: "dragover",
2507
+ onDrop: "drop",
2508
+ onTouchStart: "touchstart",
2509
+ onTouchMove: "touchmove",
2510
+ onTouchEnd: "touchend",
2511
+ onTouchCancel: "touchcancel",
2512
+ onContextMenu: "contextmenu",
2513
+ onCopy: "copy",
2514
+ onCut: "cut",
2515
+ onPaste: "paste",
2516
+ onLoad: "load",
2517
+ onError: "error",
2518
+ onAnimationStart: "animationstart",
2519
+ onAnimationEnd: "animationend",
2520
+ onAnimationIteration: "animationiteration",
2521
+ onTransitionEnd: "transitionend"
2522
+ };
2523
+ function toDomEventName(reactEventName) {
2524
+ return EVENT_HANDLERS[reactEventName] || reactEventName.replace(/^on/, "").toLowerCase();
2525
+ }
2526
+ function toReactEventName(domEventName) {
2527
+ const entry = Object.entries(EVENT_HANDLERS).find(([, dom]) => dom === domEventName);
2528
+ return entry ? entry[0] : `on${domEventName.charAt(0).toUpperCase()}${domEventName.slice(1)}`;
2529
+ }
2530
+ var defaultEventSystem = null;
2531
+ function getEventSystem(config) {
2532
+ if (!defaultEventSystem || config) {
2533
+ defaultEventSystem = new EventSystem(config);
2534
+ }
2535
+ return defaultEventSystem;
2536
+ }
2537
+ function resetEventSystem() {
2538
+ if (defaultEventSystem) {
2539
+ defaultEventSystem.destroy();
2540
+ defaultEventSystem = null;
2541
+ }
2542
+ }
2543
+
2544
+ // src/overrides.ts
2545
+ var OverrideSystem = class {
2546
+ constructor(config = {}) {
2547
+ this.elementStates = /* @__PURE__ */ new Map();
2548
+ this.watchIntervals = /* @__PURE__ */ new Map();
2549
+ this.config = config;
2550
+ }
2551
+ /**
2552
+ * Get overrides from an element
2553
+ */
2554
+ getOverrides(element) {
2555
+ const rawOverrides = element.configuration?._overrides_;
2556
+ if (!rawOverrides) return [];
2557
+ if (Array.isArray(rawOverrides)) {
2558
+ return rawOverrides.filter((o) => o && typeof o === "object");
2559
+ }
2560
+ if (typeof rawOverrides === "object") {
2561
+ console.warn("[OverrideSystem] Legacy object override format detected, ignoring");
2562
+ return [];
2563
+ }
2564
+ return [];
2565
+ }
2566
+ /**
2567
+ * Initialize overrides for an element (called on mount)
2568
+ */
2569
+ async initializeElement(element, context) {
2570
+ const elementId = element.i;
2571
+ const overrides = this.getOverrides(element);
2572
+ if (overrides.length === 0) return;
2573
+ const state = {
2574
+ previousValues: /* @__PURE__ */ new Map(),
2575
+ initialized: false,
2576
+ abortController: new AbortController()
2577
+ };
2578
+ this.elementStates.set(elementId, state);
2579
+ const mountOverrides = overrides.filter((o) => !o.isCleanUp);
2580
+ overrides.forEach((override, index) => {
2581
+ if (override.isCleanUp) return;
2582
+ if (!override.dependencies || override.dependencies.length === 0) return;
2583
+ const initialValues = override.dependencies.map(
2584
+ (dep) => resolveTemplate(dep, context)
2585
+ );
2586
+ state.previousValues.set(index, initialValues);
2587
+ });
2588
+ await this.processOverrides(elementId, mountOverrides, context, "onMount");
2589
+ state.initialized = true;
2590
+ }
2591
+ /**
2592
+ * Check and process dependency changes for an element
2593
+ */
2594
+ async checkDependencies(element, context) {
2595
+ const elementId = element.i;
2596
+ const overrides = this.getOverrides(element);
2597
+ const state = this.elementStates.get(elementId);
2598
+ if (!state || !state.initialized) return;
2599
+ const overridesToTrigger = [];
2600
+ overrides.forEach((override, index) => {
2601
+ if (override.isCleanUp) return;
2602
+ if (!override.dependencies || override.dependencies.length === 0) return;
2603
+ const currentValues = override.dependencies.map(
2604
+ (dep) => resolveTemplate(dep, context)
2605
+ );
2606
+ const previousValues = state.previousValues.get(index) || [];
2607
+ let hasChanged = false;
2608
+ if (previousValues.length !== currentValues.length) {
2609
+ hasChanged = true;
2610
+ } else {
2611
+ for (let i = 0; i < currentValues.length; i++) {
2612
+ if (JSON.stringify(previousValues[i]) !== JSON.stringify(currentValues[i])) {
2613
+ hasChanged = true;
2614
+ break;
2615
+ }
2616
+ }
2617
+ }
2618
+ if (hasChanged) {
2619
+ overridesToTrigger.push(override);
2620
+ state.previousValues.set(index, currentValues);
2621
+ if (this.config.onDependencyChange) {
2622
+ this.config.onDependencyChange(elementId, override.dependencies, currentValues);
2623
+ }
2624
+ }
2625
+ });
2626
+ if (overridesToTrigger.length > 0) {
2627
+ await this.processOverrides(elementId, overridesToTrigger, context, "onDependencyChange");
2628
+ }
2629
+ }
2630
+ /**
2631
+ * Cleanup overrides for an element (called on unmount)
2632
+ */
2633
+ async cleanupElement(element, context) {
2634
+ const elementId = element.i;
2635
+ const overrides = this.getOverrides(element);
2636
+ const state = this.elementStates.get(elementId);
2637
+ if (state?.abortController) {
2638
+ state.abortController.abort();
2639
+ }
2640
+ this.stopWatching(elementId);
2641
+ const cleanupOverrides = overrides.filter((o) => o.isCleanUp);
2642
+ if (cleanupOverrides.length > 0) {
2643
+ await this.processOverrides(elementId, cleanupOverrides, context, "onUnmount");
2644
+ }
2645
+ this.elementStates.delete(elementId);
2646
+ }
2647
+ /**
2648
+ * Process a list of overrides
2649
+ */
2650
+ async processOverrides(elementId, overrides, context, eventType) {
2651
+ if (!overrides || overrides.length === 0) return;
2652
+ const validOverrides = overrides.filter((o) => o.plugins && o.plugins.length > 0);
2653
+ if (validOverrides.length === 0) return;
2654
+ const results = await Promise.allSettled(
2655
+ validOverrides.map(async (override) => {
2656
+ if (this.config.onOverrideTrigger) {
2657
+ this.config.onOverrideTrigger(elementId, override, eventType);
2658
+ }
2659
+ if (this.config.eventSystem && override.plugins) {
2660
+ const eventContext = {
2661
+ event: new CustomEvent(eventType),
2662
+ elementId,
2663
+ context,
2664
+ stateManager: this.config.stateManager
2665
+ };
2666
+ return this.config.eventSystem.executePlugins(override.plugins, eventContext);
2667
+ }
2668
+ return null;
2669
+ })
2670
+ );
2671
+ results.forEach((result, index) => {
2672
+ if (result.status === "rejected") {
2673
+ console.error(`[OverrideSystem] Override ${index} failed:`, result.reason);
2674
+ }
2675
+ });
2676
+ }
2677
+ /**
2678
+ * Start watching an element for dependency changes
2679
+ */
2680
+ startWatching(element, context, intervalMs = 100) {
2681
+ const elementId = element.i;
2682
+ this.stopWatching(elementId);
2683
+ const overrides = this.getOverrides(element);
2684
+ const hasDependencies = overrides.some(
2685
+ (o) => !o.isCleanUp && o.dependencies && o.dependencies.length > 0
2686
+ );
2687
+ if (!hasDependencies) return;
2688
+ const interval = setInterval(() => {
2689
+ this.checkDependencies(element, context);
2690
+ }, intervalMs);
2691
+ this.watchIntervals.set(elementId, interval);
2692
+ }
2693
+ /**
2694
+ * Stop watching an element
2695
+ */
2696
+ stopWatching(elementId) {
2697
+ const interval = this.watchIntervals.get(elementId);
2698
+ if (interval) {
2699
+ clearInterval(interval);
2700
+ this.watchIntervals.delete(elementId);
2701
+ }
2702
+ }
2703
+ /**
2704
+ * Destroy the override system
2705
+ */
2706
+ destroy() {
2707
+ for (const interval of this.watchIntervals.values()) {
2708
+ clearInterval(interval);
2709
+ }
2710
+ this.watchIntervals.clear();
2711
+ for (const state of this.elementStates.values()) {
2712
+ if (state.abortController) {
2713
+ state.abortController.abort();
2714
+ }
2715
+ }
2716
+ this.elementStates.clear();
2717
+ }
2718
+ };
2719
+ function extractOverrideDependencies(element) {
2720
+ const overrides = element.configuration?._overrides_;
2721
+ if (!Array.isArray(overrides)) return [];
2722
+ const dependencies = [];
2723
+ for (const override of overrides) {
2724
+ if (override?.dependencies && Array.isArray(override.dependencies)) {
2725
+ dependencies.push(...override.dependencies);
2726
+ }
2727
+ }
2728
+ return [...new Set(dependencies)];
2729
+ }
2730
+ function hasOverrides(element) {
2731
+ const overrides = element.configuration?._overrides_;
2732
+ return Array.isArray(overrides) && overrides.length > 0;
2733
+ }
2734
+ function hasDependencyOverrides(element) {
2735
+ const overrides = element.configuration?._overrides_;
2736
+ if (!Array.isArray(overrides)) return false;
2737
+ return overrides.some(
2738
+ (o) => !o?.isCleanUp && o?.dependencies && o.dependencies.length > 0
2739
+ );
2740
+ }
2741
+ function getMountOverrides(element) {
2742
+ const overrides = element.configuration?._overrides_;
2743
+ if (!Array.isArray(overrides)) return [];
2744
+ return overrides.filter((o) => o && !o.isCleanUp);
2745
+ }
2746
+ function getCleanupOverrides(element) {
2747
+ const overrides = element.configuration?._overrides_;
2748
+ if (!Array.isArray(overrides)) return [];
2749
+ return overrides.filter((o) => o && o.isCleanUp);
2750
+ }
2751
+ var defaultOverrideSystem = null;
2752
+ function getOverrideSystem(config) {
2753
+ if (!defaultOverrideSystem || config) {
2754
+ defaultOverrideSystem = new OverrideSystem(config);
2755
+ }
2756
+ return defaultOverrideSystem;
2757
+ }
2758
+ function resetOverrideSystem() {
2759
+ if (defaultOverrideSystem) {
2760
+ defaultOverrideSystem.destroy();
2761
+ defaultOverrideSystem = null;
2762
+ }
2763
+ }
2764
+
2765
+ // src/renderer.ts
2766
+ var COMPONENT_TO_TAG = {
2767
+ container: "div",
2768
+ text: "span",
2769
+ button: "button",
2770
+ input: "input",
2771
+ image: "img",
2772
+ link: "a",
2773
+ form: "form",
2774
+ label: "label",
2775
+ textarea: "textarea",
2776
+ select: "select",
2777
+ option: "option",
2778
+ list: "ul",
2779
+ listItem: "li",
2780
+ heading: "h1",
2781
+ paragraph: "p",
2782
+ section: "section",
2783
+ article: "article",
2784
+ header: "header",
2785
+ footer: "footer",
2786
+ nav: "nav",
2787
+ aside: "aside",
2788
+ main: "main",
2789
+ span: "span",
2790
+ div: "div"
2791
+ };
2792
+ var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
2793
+ "input",
2794
+ "img",
2795
+ "br",
2796
+ "hr",
2797
+ "area",
2798
+ "base",
2799
+ "col",
2800
+ "embed",
2801
+ "link",
2802
+ "meta",
2803
+ "param",
2804
+ "source",
2805
+ "track",
2806
+ "wbr"
2807
+ ]);
2808
+ function getElementTag(element) {
2809
+ const config = element.configuration;
2810
+ if (config?.tag) {
2811
+ return config.tag;
2812
+ }
2813
+ if (element.componentId && COMPONENT_TO_TAG[element.componentId]) {
2814
+ return COMPONENT_TO_TAG[element.componentId];
2815
+ }
2816
+ if (element.isGroup) {
2817
+ return "div";
2818
+ }
2819
+ return "div";
2820
+ }
2821
+ function isSelfClosing(tag) {
2822
+ return SELF_CLOSING_TAGS.has(tag.toLowerCase());
2823
+ }
2824
+ function buildTree(elements) {
2825
+ const tree = /* @__PURE__ */ new Map();
2826
+ for (const element of elements) {
2827
+ const parentId = element.parent || null;
2828
+ if (!tree.has(parentId)) {
2829
+ tree.set(parentId, []);
2830
+ }
2831
+ tree.get(parentId).push(element);
2832
+ }
2833
+ return tree;
2834
+ }
2835
+ function getTextContent(element, context) {
2836
+ const config = element.configuration;
2837
+ if (config?.dynamicText) {
2838
+ return resolveTemplate(config.dynamicText, context);
2839
+ }
2840
+ if (config?.text) {
2841
+ if (hasTemplateSyntax(config.text)) {
2842
+ return resolveTemplate(config.text, context);
2843
+ }
2844
+ return config.text;
2845
+ }
2846
+ return "";
2847
+ }
2848
+ function applyAttributes(domElement, element, context) {
2849
+ const config = element.configuration || {};
2850
+ const attributeMap = [
2851
+ { key: "id", attr: "id" },
2852
+ { key: "src", dynamicKey: "dynamicSrc", attr: "src" },
2853
+ { key: "alt", attr: "alt" },
2854
+ { key: "href", dynamicKey: "dynamicHref", attr: "href" },
2855
+ { key: "target", attr: "target" },
2856
+ { key: "placeholder", attr: "placeholder" },
2857
+ { key: "type", attr: "type" },
2858
+ { key: "name", attr: "name" },
2859
+ { key: "value", dynamicKey: "dynamicValue", attr: "value" }
2860
+ ];
2861
+ for (const { key, dynamicKey, attr } of attributeMap) {
2862
+ const dynamicValue = dynamicKey ? config[dynamicKey] : void 0;
2863
+ if (dynamicValue !== void 0 && dynamicValue !== null && dynamicValue !== "") {
2864
+ const resolved = resolveTemplate(String(dynamicValue), context);
2865
+ if (resolved) {
2866
+ domElement.setAttribute(attr, resolved);
2867
+ }
2868
+ continue;
2869
+ }
2870
+ const staticValue = config[key];
2871
+ if (staticValue !== void 0 && staticValue !== null && staticValue !== "") {
2872
+ const resolved = hasTemplateSyntax(String(staticValue)) ? resolveTemplate(String(staticValue), context) : String(staticValue);
2873
+ if (resolved) {
2874
+ domElement.setAttribute(attr, resolved);
2875
+ }
2876
+ }
2877
+ }
2878
+ if (config.disabled) domElement.setAttribute("disabled", "");
2879
+ if (config.required) domElement.setAttribute("required", "");
2880
+ if (config.readOnly) domElement.setAttribute("readonly", "");
2881
+ for (const [key, value] of Object.entries(config)) {
2882
+ if (key.startsWith("data-") && value !== void 0) {
2883
+ const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
2884
+ domElement.setAttribute(key, resolved);
2885
+ }
2886
+ }
2887
+ for (const [key, value] of Object.entries(config)) {
2888
+ if (key.startsWith("aria-") && value !== void 0) {
2889
+ const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
1470
2890
  domElement.setAttribute(key, resolved);
1471
2891
  }
1472
2892
  }
@@ -1491,7 +2911,7 @@ function resolveFunctionBinding(binding, context) {
1491
2911
  }
1492
2912
  return void 0;
1493
2913
  }
1494
- function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false) {
2914
+ function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false, state) {
1495
2915
  const elementId = element.i;
1496
2916
  if (eventHandlers && eventHandlers[elementId]) {
1497
2917
  const handlers = eventHandlers[elementId];
@@ -1501,6 +2921,28 @@ function attachEventHandlers(domElement, element, eventHandlers, context, elemen
1501
2921
  domElement.addEventListener(domEventName, handler);
1502
2922
  }
1503
2923
  }
2924
+ const config = element.configuration || {};
2925
+ for (const eventPropName of Object.keys(EVENT_HANDLERS)) {
2926
+ const handlerConfig = config[eventPropName];
2927
+ if (handlerConfig && handlerConfig.plugins && handlerConfig.plugins.length > 0) {
2928
+ const domEventName = toDomEventName(eventPropName);
2929
+ if (!elementState.eventListeners.has(domEventName)) {
2930
+ if (state?.eventSystem) {
2931
+ const handler = state.eventSystem.createHandler(elementId, handlerConfig, context);
2932
+ elementState.eventListeners.set(domEventName, handler);
2933
+ domElement.addEventListener(domEventName, handler);
2934
+ } else {
2935
+ const handler = (e) => {
2936
+ if (handlerConfig.preventDefault) e.preventDefault();
2937
+ if (handlerConfig.stopPropagation) e.stopPropagation();
2938
+ console.log(`[Servly] Event ${eventPropName} triggered on ${elementId}`, handlerConfig.plugins);
2939
+ };
2940
+ elementState.eventListeners.set(domEventName, handler);
2941
+ domElement.addEventListener(domEventName, handler);
2942
+ }
2943
+ }
2944
+ }
2945
+ }
1504
2946
  const bindings = element.configuration?.bindings?.inputs;
1505
2947
  if (bindings) {
1506
2948
  for (const [propName, binding] of Object.entries(bindings)) {
@@ -1535,10 +2977,16 @@ function detachEventHandlers(elementState) {
1535
2977
  }
1536
2978
  elementState.eventListeners.clear();
1537
2979
  }
1538
- function createElement(element, context, eventHandlers, isRootElement = false) {
2980
+ function createElement(element, context, eventHandlers, isRootElement = false, state) {
1539
2981
  const tag = getElementTag(element);
1540
2982
  const domElement = document.createElement(tag);
1541
2983
  domElement.setAttribute("data-servly-id", element.i);
2984
+ const slotName = element.slotName || element.configuration?.slotName;
2985
+ if (element.componentId === "slot" || slotName) {
2986
+ const name = slotName || element.i;
2987
+ domElement.setAttribute("data-slot", name);
2988
+ domElement.setAttribute("data-servly-slot", "true");
2989
+ }
1542
2990
  const styles = buildElementStyles(element, context);
1543
2991
  applyStyles(domElement, styles);
1544
2992
  const className = buildClassName(element, context);
@@ -1561,7 +3009,7 @@ function createElement(element, context, eventHandlers, isRootElement = false) {
1561
3009
  textContent,
1562
3010
  eventListeners: /* @__PURE__ */ new Map()
1563
3011
  };
1564
- attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement);
3012
+ attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement, state);
1565
3013
  return elementState;
1566
3014
  }
1567
3015
  var globalRenderingStack = /* @__PURE__ */ new Set();
@@ -1622,8 +3070,81 @@ function renderComponentRef(element, container, context, state) {
1622
3070
  globalRenderingStack.delete(refId);
1623
3071
  }
1624
3072
  }
3073
+ function extractViewId(binding) {
3074
+ if (!binding) return null;
3075
+ if (typeof binding === "string") return binding;
3076
+ if (binding.source === "static" && typeof binding.value === "string") return binding.value;
3077
+ if (binding.source === "node" && binding.binding?.viewId) return binding.binding.viewId;
3078
+ if (binding.source === "view" && typeof binding.value === "string") return binding.value;
3079
+ if (binding.viewId) return binding.viewId;
3080
+ if (binding.type === "view" && binding.viewId) return binding.viewId;
3081
+ return null;
3082
+ }
3083
+ function resolveComponentViewInputs(bindings, context, parentInputs) {
3084
+ if (!bindings) return {};
3085
+ const resolved = {};
3086
+ for (const [key, binding] of Object.entries(bindings)) {
3087
+ if (!binding) continue;
3088
+ const source = (binding.source || "").toLowerCase();
3089
+ switch (source) {
3090
+ case "static":
3091
+ case "value":
3092
+ case "constant":
3093
+ resolved[key] = binding.value;
3094
+ break;
3095
+ case "state":
3096
+ if (binding.path && context.state) {
3097
+ resolved[key] = getValueByPath2(context.state, binding.path);
3098
+ }
3099
+ break;
3100
+ case "props":
3101
+ case "parent":
3102
+ case "input":
3103
+ if (binding.path) {
3104
+ const source2 = parentInputs || context.props;
3105
+ const resolvedValue = getValueByPath2(source2, binding.path);
3106
+ if (resolvedValue !== void 0) {
3107
+ resolved[key] = resolvedValue;
3108
+ } else {
3109
+ resolved[key] = binding.value;
3110
+ }
3111
+ } else {
3112
+ resolved[key] = binding.value;
3113
+ }
3114
+ break;
3115
+ case "node":
3116
+ if (binding.binding?.viewId) {
3117
+ resolved[key] = binding.binding.viewId;
3118
+ } else if (binding.binding) {
3119
+ resolved[key] = binding.binding;
3120
+ } else {
3121
+ resolved[key] = binding.value;
3122
+ }
3123
+ break;
3124
+ default:
3125
+ resolved[key] = binding.value;
3126
+ }
3127
+ }
3128
+ return resolved;
3129
+ }
3130
+ function getValueByPath2(obj, path) {
3131
+ if (!obj || !path) return void 0;
3132
+ const parts = path.split(".");
3133
+ let current = obj;
3134
+ for (const part of parts) {
3135
+ if (current === null || current === void 0) return void 0;
3136
+ current = current[part];
3137
+ }
3138
+ return current;
3139
+ }
1625
3140
  function renderElement(element, tree, context, eventHandlers, elementStates, state, isRootElement = false) {
1626
- const elementState = createElement(element, context, eventHandlers, isRootElement);
3141
+ if (element.isComponentView) {
3142
+ return renderComponentViewElement(element, tree, context, eventHandlers, elementStates, state, isRootElement);
3143
+ }
3144
+ if (element.componentId === "slot") {
3145
+ return renderSlotElement(element, tree, context, eventHandlers, elementStates, state, isRootElement);
3146
+ }
3147
+ const elementState = createElement(element, context, eventHandlers, isRootElement, state);
1627
3148
  elementStates.set(element.i, elementState);
1628
3149
  const config = element.configuration;
1629
3150
  if (config?.componentViewRef) {
@@ -1640,8 +3161,147 @@ function renderElement(element, tree, context, eventHandlers, elementStates, sta
1640
3161
  }
1641
3162
  return elementState.domElement;
1642
3163
  }
3164
+ function renderComponentViewElement(element, tree, context, eventHandlers, elementStates, state, isRootElement) {
3165
+ const componentViewId = `${element.componentId}-${element.i}`;
3166
+ if (globalRenderingStack.has(componentViewId)) {
3167
+ const placeholder = document.createElement("div");
3168
+ placeholder.className = "border-2 border-red-500 border-dashed p-4 bg-red-50";
3169
+ placeholder.innerHTML = `<p class="text-red-600 text-sm">Recursive component: ${element.componentId}</p>`;
3170
+ return placeholder;
3171
+ }
3172
+ let viewLayout;
3173
+ if (state.views?.has(element.componentId)) {
3174
+ const view = state.views.get(element.componentId);
3175
+ viewLayout = view?.layout;
3176
+ }
3177
+ if (!viewLayout && state.componentRegistry) {
3178
+ const component = state.componentRegistry.get(element.componentId);
3179
+ if (component) {
3180
+ viewLayout = component.layout;
3181
+ }
3182
+ }
3183
+ if (!viewLayout) {
3184
+ const placeholder = document.createElement("div");
3185
+ placeholder.className = "border-2 border-yellow-500 border-dashed p-4 bg-yellow-50";
3186
+ placeholder.innerHTML = `<p class="text-yellow-600 text-sm">Component not found: ${element.componentId}</p>`;
3187
+ return placeholder;
3188
+ }
3189
+ const bindings = element.configuration?.bindings?.inputs || {};
3190
+ const resolvedInputs = resolveComponentViewInputs(bindings, context, context.props);
3191
+ const componentContext = {
3192
+ props: { ...context.props, ...resolvedInputs },
3193
+ state: context.state,
3194
+ context: context.context
3195
+ };
3196
+ globalRenderingStack.add(componentViewId);
3197
+ try {
3198
+ const wrapper = document.createElement("div");
3199
+ wrapper.id = element.i;
3200
+ wrapper.className = "contents";
3201
+ const viewTree = buildTree(viewLayout);
3202
+ const viewRoots = viewLayout.filter((el) => !el.parent || el.parent === null);
3203
+ const nestedState = {
3204
+ ...state,
3205
+ elements: viewLayout,
3206
+ context: componentContext,
3207
+ elementStates: /* @__PURE__ */ new Map(),
3208
+ rootElement: null,
3209
+ renderingStack: new Set(state.renderingStack)
3210
+ };
3211
+ nestedState.renderingStack.add(componentViewId);
3212
+ for (const root of viewRoots) {
3213
+ const rootElement = renderElement(
3214
+ root,
3215
+ viewTree,
3216
+ componentContext,
3217
+ eventHandlers,
3218
+ nestedState.elementStates,
3219
+ nestedState,
3220
+ true
3221
+ );
3222
+ wrapper.appendChild(rootElement);
3223
+ }
3224
+ const elementState = {
3225
+ element,
3226
+ domElement: wrapper,
3227
+ styles: {},
3228
+ className: "contents",
3229
+ textContent: "",
3230
+ eventListeners: /* @__PURE__ */ new Map()
3231
+ };
3232
+ elementStates.set(element.i, elementState);
3233
+ return wrapper;
3234
+ } finally {
3235
+ globalRenderingStack.delete(componentViewId);
3236
+ }
3237
+ }
3238
+ function renderSlotElement(element, tree, context, eventHandlers, elementStates, state, isRootElement) {
3239
+ const elementState = createElement(element, context, eventHandlers, isRootElement, state);
3240
+ elementStates.set(element.i, elementState);
3241
+ const bindings = element.configuration?.bindings?.inputs || {};
3242
+ let childViewId = extractViewId(bindings.child) || extractViewId(bindings.children) || extractViewId(bindings.content);
3243
+ if (!childViewId && context.props) {
3244
+ childViewId = extractViewId(context.props.child) || extractViewId(context.props.children) || extractViewId(context.props.content);
3245
+ }
3246
+ if (childViewId && typeof childViewId === "string") {
3247
+ let viewLayout;
3248
+ if (state.views?.has(childViewId)) {
3249
+ const view = state.views.get(childViewId);
3250
+ viewLayout = view?.layout;
3251
+ }
3252
+ if (!viewLayout && state.componentRegistry) {
3253
+ const component = state.componentRegistry.get(childViewId);
3254
+ if (component) {
3255
+ viewLayout = component.layout;
3256
+ }
3257
+ }
3258
+ if (viewLayout) {
3259
+ const viewTree = buildTree(viewLayout);
3260
+ const viewRoots = viewLayout.filter((el) => !el.parent || el.parent === null);
3261
+ const nestedState = {
3262
+ ...state,
3263
+ elements: viewLayout,
3264
+ elementStates: /* @__PURE__ */ new Map(),
3265
+ rootElement: null
3266
+ };
3267
+ for (const root of viewRoots) {
3268
+ const rootElement = renderElement(
3269
+ root,
3270
+ viewTree,
3271
+ context,
3272
+ eventHandlers,
3273
+ nestedState.elementStates,
3274
+ nestedState,
3275
+ false
3276
+ );
3277
+ elementState.domElement.appendChild(rootElement);
3278
+ }
3279
+ return elementState.domElement;
3280
+ }
3281
+ }
3282
+ const children = tree.get(element.i) || [];
3283
+ for (const child of children) {
3284
+ const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state, false);
3285
+ elementState.domElement.appendChild(childElement);
3286
+ }
3287
+ return elementState.domElement;
3288
+ }
1643
3289
  function render(options) {
1644
- const { container, elements, context, eventHandlers, componentRegistry, onDependencyNeeded } = options;
3290
+ const {
3291
+ container,
3292
+ elements,
3293
+ context,
3294
+ eventHandlers,
3295
+ componentRegistry,
3296
+ onDependencyNeeded,
3297
+ views,
3298
+ enableStateManager,
3299
+ initialState,
3300
+ onStateChange,
3301
+ pluginExecutors,
3302
+ onNavigate,
3303
+ onApiCall
3304
+ } = options;
1645
3305
  const startTime = performance.now();
1646
3306
  const memorySampler = getMemorySampler();
1647
3307
  const longTaskObserver = getLongTaskObserver();
@@ -1650,6 +3310,29 @@ function render(options) {
1650
3310
  const rootElements = elements.filter((el) => !el.parent || el.parent === null);
1651
3311
  const componentId = rootElements[0]?.componentId || "unknown";
1652
3312
  const version = "latest";
3313
+ let stateManager;
3314
+ if (enableStateManager) {
3315
+ stateManager = new StateManager({
3316
+ initialState: initialState || context.state,
3317
+ onStateChange: onStateChange ? (event) => onStateChange({
3318
+ key: event.key,
3319
+ value: event.value,
3320
+ previousValue: event.previousValue
3321
+ }) : void 0
3322
+ });
3323
+ }
3324
+ const eventSystem = new EventSystem({
3325
+ stateManager,
3326
+ pluginExecutors,
3327
+ onNavigate,
3328
+ onApiCall
3329
+ });
3330
+ const overrideSystem = new OverrideSystem({
3331
+ eventSystem,
3332
+ stateManager
3333
+ });
3334
+ const hasAnyOverrides = elements.some((el) => hasOverrides(el));
3335
+ const hasAnyDependencyOverrides = elements.some((el) => hasDependencyOverrides(el));
1653
3336
  try {
1654
3337
  const tree = buildTree(elements);
1655
3338
  const state = {
@@ -1661,7 +3344,12 @@ function render(options) {
1661
3344
  rootElement: null,
1662
3345
  componentRegistry,
1663
3346
  onDependencyNeeded,
1664
- renderingStack: /* @__PURE__ */ new Set()
3347
+ renderingStack: /* @__PURE__ */ new Set(),
3348
+ views,
3349
+ eventSystem,
3350
+ stateManager,
3351
+ overrideSystem,
3352
+ enableOverrides: hasAnyOverrides
1665
3353
  };
1666
3354
  container.innerHTML = "";
1667
3355
  if (rootElements.length === 0) {
@@ -1699,6 +3387,16 @@ function render(options) {
1699
3387
  state.rootElement = wrapper;
1700
3388
  container.appendChild(wrapper);
1701
3389
  }
3390
+ if (hasAnyOverrides && overrideSystem) {
3391
+ for (const element of elements) {
3392
+ if (hasOverrides(element)) {
3393
+ overrideSystem.initializeElement(element, context);
3394
+ if (hasDependencyOverrides(element)) {
3395
+ overrideSystem.startWatching(element, context);
3396
+ }
3397
+ }
3398
+ }
3399
+ }
1702
3400
  const duration = performance.now() - startTime;
1703
3401
  const memoryAfter = memorySampler.sample();
1704
3402
  const longTasks = longTaskObserver.stop();
@@ -1717,6 +3415,7 @@ function render(options) {
1717
3415
  };
1718
3416
  } catch (error) {
1719
3417
  longTaskObserver.stop();
3418
+ overrideSystem.destroy();
1720
3419
  analytics.trackError(componentId, version, error, {
1721
3420
  errorType: "render"
1722
3421
  });
@@ -1747,12 +3446,23 @@ function update(state, newContext) {
1747
3446
  }
1748
3447
  }
1749
3448
  function destroy(state) {
3449
+ if (state.overrideSystem && state.enableOverrides) {
3450
+ for (const element of state.elements) {
3451
+ if (hasOverrides(element)) {
3452
+ state.overrideSystem.cleanupElement(element, state.context);
3453
+ }
3454
+ }
3455
+ state.overrideSystem.destroy();
3456
+ }
1750
3457
  for (const elementState of state.elementStates.values()) {
1751
3458
  detachEventHandlers(elementState);
1752
3459
  if (elementState.nestedRender) {
1753
3460
  elementState.nestedRender.destroy();
1754
3461
  }
1755
3462
  }
3463
+ if (state.eventSystem) {
3464
+ state.eventSystem.destroy();
3465
+ }
1756
3466
  state.elementStates.clear();
1757
3467
  if (state.rootElement && state.rootElement.parentNode) {
1758
3468
  state.rootElement.parentNode.removeChild(state.rootElement);
@@ -1819,6 +3529,200 @@ function renderDynamicList(options) {
1819
3529
  }
1820
3530
  return results;
1821
3531
  }
3532
+ function renderNode(options) {
3533
+ const {
3534
+ container,
3535
+ elements,
3536
+ nodeId,
3537
+ context,
3538
+ includeChildren = true,
3539
+ eventHandlers,
3540
+ componentRegistry,
3541
+ views
3542
+ } = options;
3543
+ const targetNode = elements.find((el) => el.i === nodeId);
3544
+ if (!targetNode) {
3545
+ console.error(`renderNode: Node not found: ${nodeId}`);
3546
+ return null;
3547
+ }
3548
+ if (!includeChildren) {
3549
+ const singleElementLayout = [targetNode];
3550
+ return render({
3551
+ container,
3552
+ elements: singleElementLayout,
3553
+ context,
3554
+ eventHandlers,
3555
+ componentRegistry,
3556
+ views
3557
+ });
3558
+ }
3559
+ const descendantIds = /* @__PURE__ */ new Set();
3560
+ const collectDescendants = (parentId) => {
3561
+ for (const el of elements) {
3562
+ if (el.parent === parentId) {
3563
+ descendantIds.add(el.i);
3564
+ collectDescendants(el.i);
3565
+ }
3566
+ }
3567
+ };
3568
+ descendantIds.add(nodeId);
3569
+ collectDescendants(nodeId);
3570
+ const nodeElements = elements.filter((el) => descendantIds.has(el.i));
3571
+ const rootedElements = nodeElements.map(
3572
+ (el) => el.i === nodeId ? { ...el, parent: null } : el
3573
+ );
3574
+ return render({
3575
+ container,
3576
+ elements: rootedElements,
3577
+ context,
3578
+ eventHandlers,
3579
+ componentRegistry,
3580
+ views
3581
+ });
3582
+ }
3583
+ function renderInShadow(options) {
3584
+ const { container, mode = "open", styles, injectTailwind: shouldInjectTailwind, ...renderOptions } = options;
3585
+ const shadowRoot = container.attachShadow({ mode });
3586
+ const innerContainer = document.createElement("div");
3587
+ innerContainer.className = "servly-shadow-container";
3588
+ shadowRoot.appendChild(innerContainer);
3589
+ if (styles) {
3590
+ const styleEl = document.createElement("style");
3591
+ styleEl.textContent = styles;
3592
+ shadowRoot.insertBefore(styleEl, innerContainer);
3593
+ }
3594
+ if (shouldInjectTailwind) {
3595
+ const tailwindLink = document.createElement("link");
3596
+ tailwindLink.rel = "stylesheet";
3597
+ tailwindLink.href = "https://cdn.tailwindcss.com";
3598
+ shadowRoot.insertBefore(tailwindLink, innerContainer);
3599
+ }
3600
+ const result = render({
3601
+ ...renderOptions,
3602
+ container: innerContainer
3603
+ });
3604
+ return {
3605
+ ...result,
3606
+ shadowRoot
3607
+ };
3608
+ }
3609
+ async function createServlyRenderer(options) {
3610
+ const {
3611
+ container: containerOption,
3612
+ injectTailwind: shouldInjectTailwind = true,
3613
+ tailwindConfig,
3614
+ initialState,
3615
+ onStateChange,
3616
+ onNavigate
3617
+ } = options;
3618
+ let container;
3619
+ if (typeof containerOption === "string") {
3620
+ const el = document.querySelector(containerOption);
3621
+ if (!el) {
3622
+ throw new Error(`Container not found: ${containerOption}`);
3623
+ }
3624
+ container = el;
3625
+ } else {
3626
+ container = containerOption;
3627
+ }
3628
+ if (shouldInjectTailwind) {
3629
+ const { initServlyTailwind: initServlyTailwind2 } = await Promise.resolve().then(() => (init_tailwind(), tailwind_exports));
3630
+ await initServlyTailwind2(tailwindConfig);
3631
+ }
3632
+ const activeRenders = [];
3633
+ return {
3634
+ render: (elements, context = { props: {} }) => {
3635
+ const result = render({
3636
+ container,
3637
+ elements,
3638
+ context,
3639
+ enableStateManager: true,
3640
+ initialState,
3641
+ onStateChange,
3642
+ onNavigate
3643
+ });
3644
+ activeRenders.push(result);
3645
+ return result;
3646
+ },
3647
+ renderNode: (elements, nodeId, context = { props: {} }) => {
3648
+ const result = renderNode({
3649
+ container,
3650
+ elements,
3651
+ nodeId,
3652
+ context
3653
+ });
3654
+ if (result) {
3655
+ activeRenders.push(result);
3656
+ }
3657
+ return result;
3658
+ },
3659
+ renderDynamicList,
3660
+ destroy: () => {
3661
+ for (const result of activeRenders) {
3662
+ result.destroy();
3663
+ }
3664
+ activeRenders.length = 0;
3665
+ container.innerHTML = "";
3666
+ }
3667
+ };
3668
+ }
3669
+ function createViewsMap(views) {
3670
+ const viewsMap = /* @__PURE__ */ new Map();
3671
+ for (const view of views) {
3672
+ const id = view.id || view._id;
3673
+ if (id && view.layout) {
3674
+ viewsMap.set(id, {
3675
+ id,
3676
+ layout: view.layout,
3677
+ props: view.props
3678
+ });
3679
+ }
3680
+ }
3681
+ return viewsMap;
3682
+ }
3683
+ function extractReferencedViewIds(elements) {
3684
+ const viewIds = /* @__PURE__ */ new Set();
3685
+ for (const element of elements) {
3686
+ if (element.isComponentView && element.componentId) {
3687
+ viewIds.add(element.componentId);
3688
+ }
3689
+ if (element.configuration?.componentViewRef) {
3690
+ viewIds.add(element.configuration.componentViewRef);
3691
+ }
3692
+ const bindings = element.configuration?.bindings?.inputs;
3693
+ if (bindings) {
3694
+ for (const binding of Object.values(bindings)) {
3695
+ if (binding && typeof binding === "object") {
3696
+ if (binding.source === "node" && binding.binding?.viewId) {
3697
+ viewIds.add(binding.binding.viewId);
3698
+ }
3699
+ if (binding.viewId) {
3700
+ viewIds.add(binding.viewId);
3701
+ }
3702
+ }
3703
+ }
3704
+ }
3705
+ }
3706
+ return Array.from(viewIds);
3707
+ }
3708
+ function collectAllViewDependencies(views, startViewId) {
3709
+ const collected = /* @__PURE__ */ new Set();
3710
+ const toProcess = [startViewId];
3711
+ while (toProcess.length > 0) {
3712
+ const viewId = toProcess.pop();
3713
+ if (collected.has(viewId)) continue;
3714
+ collected.add(viewId);
3715
+ const view = views.get(viewId);
3716
+ if (!view) continue;
3717
+ const referencedIds = extractReferencedViewIds(view.layout);
3718
+ for (const refId of referencedIds) {
3719
+ if (!collected.has(refId)) {
3720
+ toProcess.push(refId);
3721
+ }
3722
+ }
3723
+ }
3724
+ return collected;
3725
+ }
1822
3726
 
1823
3727
  // src/cache.ts
1824
3728
  var DEFAULT_CACHE_CONFIG = {
@@ -2093,6 +3997,18 @@ function calculateBackoffDelay(retryCount, config) {
2093
3997
  function sleep(ms) {
2094
3998
  return new Promise((resolve) => setTimeout(resolve, ms));
2095
3999
  }
4000
+ function buildViewsMap(views) {
4001
+ if (!views || views.length === 0) return void 0;
4002
+ const viewsMap = /* @__PURE__ */ new Map();
4003
+ for (const view of views) {
4004
+ viewsMap.set(view.id, {
4005
+ id: view.id,
4006
+ layout: view.layout,
4007
+ props: view.props
4008
+ });
4009
+ }
4010
+ return viewsMap;
4011
+ }
2096
4012
  async function resolveVersionFromApi(id, specifier, apiKey) {
2097
4013
  if (/^\d+\.\d+\.\d+$/.test(specifier)) {
2098
4014
  return specifier;
@@ -2122,7 +4038,7 @@ async function resolveVersionFromApi(id, specifier, apiKey) {
2122
4038
  return "latest";
2123
4039
  }
2124
4040
  }
2125
- async function fetchFromRegistry(id, version, apiKey, includeBundle) {
4041
+ async function fetchFromRegistry(id, version, apiKey, includeBundle, includeViews) {
2126
4042
  const baseUrl = getRegistryUrl();
2127
4043
  const headers = {
2128
4044
  "Content-Type": "application/json"
@@ -2141,6 +4057,9 @@ async function fetchFromRegistry(id, version, apiKey, includeBundle) {
2141
4057
  if (includeBundle) {
2142
4058
  url += (url.includes("?") ? "&" : "?") + "bundle=true";
2143
4059
  }
4060
+ if (includeViews) {
4061
+ url += (url.includes("?") ? "&" : "?") + "includeViews=true";
4062
+ }
2144
4063
  const response = await fetch(url, { headers });
2145
4064
  if (!response.ok) {
2146
4065
  if (response.status === 404) {
@@ -2174,7 +4093,9 @@ async function fetchComponent(id, options = {}) {
2174
4093
  forceRefresh = false,
2175
4094
  signal,
2176
4095
  bundleStrategy = "eager",
2177
- includeBundle = true
4096
+ includeBundle = true,
4097
+ includeViews = true
4098
+ // Default to true - fetch all views needed
2178
4099
  } = options;
2179
4100
  const fullRetryConfig = {
2180
4101
  ...DEFAULT_RETRY_CONFIG,
@@ -2188,6 +4109,7 @@ async function fetchComponent(id, options = {}) {
2188
4109
  if (cached.bundle) {
2189
4110
  registry = buildRegistryFromBundle(cached);
2190
4111
  }
4112
+ const views = buildViewsMap(cached.views);
2191
4113
  const duration = performance.now() - startTime;
2192
4114
  analytics.trackFetch(id, cached.version, duration, true, {
2193
4115
  cacheHit: true,
@@ -2197,7 +4119,8 @@ async function fetchComponent(id, options = {}) {
2197
4119
  data: cached,
2198
4120
  fromCache: true,
2199
4121
  version: cached.version,
2200
- registry
4122
+ registry,
4123
+ views
2201
4124
  };
2202
4125
  }
2203
4126
  }
@@ -2209,11 +4132,13 @@ async function fetchComponent(id, options = {}) {
2209
4132
  if (cached.bundle) {
2210
4133
  registry = buildRegistryFromBundle(cached);
2211
4134
  }
4135
+ const views = buildViewsMap(cached.views);
2212
4136
  return {
2213
4137
  data: cached,
2214
4138
  fromCache: true,
2215
4139
  version: resolvedVersion,
2216
- registry
4140
+ registry,
4141
+ views
2217
4142
  };
2218
4143
  }
2219
4144
  }
@@ -2224,7 +4149,7 @@ async function fetchComponent(id, options = {}) {
2224
4149
  throw new Error("Fetch aborted");
2225
4150
  }
2226
4151
  try {
2227
- const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle);
4152
+ const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle, includeViews);
2228
4153
  setInCache(id, resolvedVersion, data, cacheStrategy, cacheConfig);
2229
4154
  if (version !== resolvedVersion) {
2230
4155
  setInCache(id, version, data, cacheStrategy, cacheConfig);
@@ -2239,6 +4164,7 @@ async function fetchComponent(id, options = {}) {
2239
4164
  version: entry.resolved || entry.version
2240
4165
  }));
2241
4166
  }
4167
+ const views = buildViewsMap(data.views);
2242
4168
  const duration = performance.now() - startTime;
2243
4169
  analytics.trackFetch(id, resolvedVersion, duration, false, {
2244
4170
  cacheHit: false,
@@ -2250,7 +4176,8 @@ async function fetchComponent(id, options = {}) {
2250
4176
  fromCache: false,
2251
4177
  version: resolvedVersion,
2252
4178
  registry,
2253
- pendingDependencies
4179
+ pendingDependencies,
4180
+ views
2254
4181
  };
2255
4182
  } catch (error) {
2256
4183
  lastError = error instanceof Error ? error : new Error(String(error));
@@ -2621,13 +4548,13 @@ function validateAssertion(container, assertion) {
2621
4548
  message: `Element "${assertion.selector}" not found`
2622
4549
  };
2623
4550
  }
2624
- const hasClass = elements[0].classList.contains(assertion.expected);
4551
+ const hasClass2 = elements[0].classList.contains(assertion.expected);
2625
4552
  return {
2626
4553
  assertion,
2627
- passed: hasClass,
4554
+ passed: hasClass2,
2628
4555
  actual: Array.from(elements[0].classList),
2629
4556
  expected: assertion.expected,
2630
- message: hasClass ? `Element has class "${assertion.expected}"` : `Element does not have class "${assertion.expected}"`
4557
+ message: hasClass2 ? `Element has class "${assertion.expected}"` : `Element does not have class "${assertion.expected}"`
2631
4558
  };
2632
4559
  case "style":
2633
4560
  if (elements.length === 0) {
@@ -2747,14 +4674,22 @@ function getSampleValue(def) {
2747
4674
 
2748
4675
  // src/index.ts
2749
4676
  init_registry();
4677
+ init_tailwind();
2750
4678
  // Annotate the CommonJS export names for ESM import in node:
2751
4679
  0 && (module.exports = {
2752
4680
  AnalyticsCollector,
2753
4681
  DEFAULT_CACHE_CONFIG,
2754
4682
  DEFAULT_RETRY_CONFIG,
4683
+ DEFAULT_SERVLY_TAILWIND_CONFIG,
4684
+ EVENT_HANDLERS,
4685
+ EventSystem,
2755
4686
  LongTaskObserver,
2756
4687
  MemorySampler,
4688
+ OverrideSystem,
2757
4689
  SessionManager,
4690
+ StateManager,
4691
+ addClass,
4692
+ addCustomStyles,
2758
4693
  analytics,
2759
4694
  applyStyles,
2760
4695
  batchFetchComponents,
@@ -2768,13 +4703,20 @@ init_registry();
2768
4703
  clearMemoryCache,
2769
4704
  clearStyles,
2770
4705
  collectAllDependencies,
4706
+ collectAllViewDependencies,
2771
4707
  compareVersions,
2772
4708
  configureAnalytics,
2773
4709
  createRegistry,
4710
+ createServlyRenderer,
4711
+ createViewsMap,
4712
+ deepMerge,
4713
+ deleteValueByPath,
2774
4714
  detectCircularDependencies,
2775
4715
  extractBindingKeys,
2776
4716
  extractDependencies,
2777
4717
  extractDependenciesFromCode,
4718
+ extractOverrideDependencies,
4719
+ extractReferencedViewIds,
2778
4720
  fetchComponent,
2779
4721
  fetchComponentWithDependencies,
2780
4722
  formatStyleValue,
@@ -2782,25 +4724,52 @@ init_registry();
2782
4724
  generateTestCases,
2783
4725
  getAnalytics,
2784
4726
  getCacheKey,
4727
+ getCleanupOverrides,
2785
4728
  getDependencyTree,
4729
+ getEventSystem,
2786
4730
  getFromCache,
4731
+ getLocalStorage,
2787
4732
  getLongTaskObserver,
2788
4733
  getMemoryCacheSize,
2789
4734
  getMemorySampler,
4735
+ getMountOverrides,
4736
+ getOverrideSystem,
2790
4737
  getRegistryUrl,
2791
4738
  getSessionManager,
4739
+ getSessionStorage,
4740
+ getTailwind,
4741
+ getUrlInfo,
4742
+ getValueByPath,
4743
+ goBack,
4744
+ goForward,
4745
+ hasClass,
4746
+ hasDependencyOverrides,
4747
+ hasOverrides,
2792
4748
  hasTemplateSyntax,
4749
+ initServlyTailwind,
4750
+ injectTailwind,
2793
4751
  invalidateCache,
2794
4752
  isComponentAvailable,
4753
+ isTailwindLoaded,
2795
4754
  isValidSpecifier,
4755
+ navigateTo,
2796
4756
  parseVersion,
2797
4757
  prefetchComponents,
2798
4758
  processStyles,
4759
+ removeClass,
4760
+ removeCustomStyles,
4761
+ removeLocalStorage,
4762
+ removeSessionStorage,
4763
+ removeTailwind,
2799
4764
  render,
2800
4765
  renderDynamicList,
4766
+ renderInShadow,
4767
+ renderNode,
2801
4768
  resetAnalytics,
4769
+ resetEventSystem,
2802
4770
  resetLongTaskObserver,
2803
4771
  resetMemorySampler,
4772
+ resetOverrideSystem,
2804
4773
  resetSessionManager,
2805
4774
  resolveBindingPath,
2806
4775
  resolveTemplate,
@@ -2811,8 +4780,15 @@ init_registry();
2811
4780
  runTestCase,
2812
4781
  satisfiesVersion,
2813
4782
  setInCache,
4783
+ setLocalStorage,
2814
4784
  setRegistryUrl,
4785
+ setSessionStorage,
4786
+ setValueByPath,
4787
+ toDomEventName,
4788
+ toReactEventName,
4789
+ toggleClass,
2815
4790
  updateStyles,
4791
+ updateTailwindConfig,
2816
4792
  validateAssertion,
2817
4793
  validateProps
2818
4794
  });