@servlyadmin/runtime-core 0.1.45 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +215 -1
- package/dist/index.cjs +623 -1
- package/dist/index.js +615 -1
- package/package.json +3 -3
- package/dist/index.d.cts +0 -2076
- package/dist/index.d.ts +0 -2076
package/dist/index.cjs
CHANGED
|
@@ -720,6 +720,7 @@ __export(index_exports, {
|
|
|
720
720
|
extractDependenciesFromCode: () => extractDependenciesFromCode,
|
|
721
721
|
extractOverrideDependencies: () => extractOverrideDependencies,
|
|
722
722
|
extractReferencedViewIds: () => extractReferencedViewIds,
|
|
723
|
+
extractSlotBindings: () => extractSlotBindings,
|
|
723
724
|
fetchComponent: () => fetchComponent,
|
|
724
725
|
fetchComponentWithDependencies: () => fetchComponentWithDependencies,
|
|
725
726
|
formatStyleValue: () => formatStyleValue,
|
|
@@ -773,9 +774,16 @@ __export(index_exports, {
|
|
|
773
774
|
loadFont: () => loadFont,
|
|
774
775
|
loadFonts: () => loadFonts,
|
|
775
776
|
markElementReady: () => markElementReady,
|
|
777
|
+
mount: () => mount,
|
|
778
|
+
mountData: () => mountData,
|
|
776
779
|
navigateTo: () => navigateTo,
|
|
777
780
|
parseVersion: () => parseVersion,
|
|
781
|
+
prefetch: () => prefetch,
|
|
782
|
+
prefetchAll: () => prefetchAll,
|
|
778
783
|
prefetchComponents: () => prefetchComponents,
|
|
784
|
+
prefetchOnHover: () => prefetchOnHover,
|
|
785
|
+
prefetchOnIdle: () => prefetchOnIdle,
|
|
786
|
+
prefetchOnVisible: () => prefetchOnVisible,
|
|
779
787
|
preloadIcons: () => preloadIcons,
|
|
780
788
|
preloadTailwind: () => preloadTailwind,
|
|
781
789
|
preventFOUC: () => preventFOUC,
|
|
@@ -1517,8 +1525,96 @@ function resolveBindingPath(path, context) {
|
|
|
1517
1525
|
}
|
|
1518
1526
|
return navigatePath(source, parts.slice(startIndex));
|
|
1519
1527
|
}
|
|
1528
|
+
var FUNCTION_CALL_REGEX = /^(\w+)\s*\((.*)\)$/s;
|
|
1529
|
+
function executeGlobalFunction(funcName, argsStr, context) {
|
|
1530
|
+
if (context.functionMap?.[funcName]) {
|
|
1531
|
+
try {
|
|
1532
|
+
const args = parseFunctionArguments(argsStr, context);
|
|
1533
|
+
return context.functionMap[funcName](...args);
|
|
1534
|
+
} catch (error) {
|
|
1535
|
+
console.error(`[GlobalFunction] Error executing ${funcName}:`, error);
|
|
1536
|
+
return void 0;
|
|
1537
|
+
}
|
|
1538
|
+
}
|
|
1539
|
+
const func = context.globalFunctions?.find((f) => f.name === funcName);
|
|
1540
|
+
if (!func) {
|
|
1541
|
+
console.warn(`[GlobalFunction] Function not found: ${funcName}`);
|
|
1542
|
+
return void 0;
|
|
1543
|
+
}
|
|
1544
|
+
try {
|
|
1545
|
+
const args = parseFunctionArguments(argsStr, context);
|
|
1546
|
+
const paramNames = func.parameters.map((p) => p.name);
|
|
1547
|
+
const fnBody = `
|
|
1548
|
+
const state = __ctx__.state || {};
|
|
1549
|
+
const props = __ctx__.props || {};
|
|
1550
|
+
const config = __ctx__.configs || __ctx__.context || {};
|
|
1551
|
+
${func.code}
|
|
1552
|
+
`;
|
|
1553
|
+
const fn = new Function("__ctx__", ...paramNames, fnBody);
|
|
1554
|
+
return fn(context, ...args);
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
console.error(`[GlobalFunction] Error executing ${funcName}:`, error);
|
|
1557
|
+
return void 0;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
function parseFunctionArguments(argsStr, context) {
|
|
1561
|
+
if (!argsStr.trim()) return [];
|
|
1562
|
+
const args = [];
|
|
1563
|
+
let current = "";
|
|
1564
|
+
let depth = 0;
|
|
1565
|
+
let inString = false;
|
|
1566
|
+
let stringChar = "";
|
|
1567
|
+
for (let i = 0; i < argsStr.length; i++) {
|
|
1568
|
+
const char = argsStr[i];
|
|
1569
|
+
const prevChar = argsStr[i - 1];
|
|
1570
|
+
if ((char === '"' || char === "'") && prevChar !== "\\") {
|
|
1571
|
+
if (!inString) {
|
|
1572
|
+
inString = true;
|
|
1573
|
+
stringChar = char;
|
|
1574
|
+
} else if (char === stringChar) {
|
|
1575
|
+
inString = false;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
if (!inString) {
|
|
1579
|
+
if (char === "(" || char === "[" || char === "{") depth++;
|
|
1580
|
+
if (char === ")" || char === "]" || char === "}") depth--;
|
|
1581
|
+
}
|
|
1582
|
+
if (char === "," && depth === 0 && !inString) {
|
|
1583
|
+
args.push(parseArgumentValue(current.trim(), context));
|
|
1584
|
+
current = "";
|
|
1585
|
+
} else {
|
|
1586
|
+
current += char;
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
if (current.trim()) {
|
|
1590
|
+
args.push(parseArgumentValue(current.trim(), context));
|
|
1591
|
+
}
|
|
1592
|
+
return args;
|
|
1593
|
+
}
|
|
1594
|
+
function parseArgumentValue(value, context) {
|
|
1595
|
+
const trimmed = value.trim();
|
|
1596
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"') || trimmed.startsWith("'") && trimmed.endsWith("'")) {
|
|
1597
|
+
return trimmed.slice(1, -1);
|
|
1598
|
+
}
|
|
1599
|
+
if (!isNaN(Number(trimmed)) && trimmed !== "") {
|
|
1600
|
+
return Number(trimmed);
|
|
1601
|
+
}
|
|
1602
|
+
if (trimmed === "true") return true;
|
|
1603
|
+
if (trimmed === "false") return false;
|
|
1604
|
+
if (trimmed === "null") return null;
|
|
1605
|
+
if (trimmed === "undefined") return void 0;
|
|
1606
|
+
if (trimmed.startsWith("{{") && trimmed.endsWith("}}")) {
|
|
1607
|
+
return resolveTemplateValue(trimmed, context);
|
|
1608
|
+
}
|
|
1609
|
+
return resolveBindingPath(trimmed, context);
|
|
1610
|
+
}
|
|
1520
1611
|
function resolveExpression(expression, context) {
|
|
1521
1612
|
const trimmed = expression.trim();
|
|
1613
|
+
const funcMatch = trimmed.match(FUNCTION_CALL_REGEX);
|
|
1614
|
+
if (funcMatch) {
|
|
1615
|
+
const [, funcName, argsStr] = funcMatch;
|
|
1616
|
+
return executeGlobalFunction(funcName, argsStr, context);
|
|
1617
|
+
}
|
|
1522
1618
|
const comparisonOperators = ["===", "!==", "==", "!=", ">=", "<=", ">", "<"];
|
|
1523
1619
|
for (const op of comparisonOperators) {
|
|
1524
1620
|
if (trimmed.includes(op)) {
|
|
@@ -2435,6 +2531,203 @@ function getUrlInfo() {
|
|
|
2435
2531
|
}
|
|
2436
2532
|
|
|
2437
2533
|
// src/eventSystem.ts
|
|
2534
|
+
function createShortcuts(ctx) {
|
|
2535
|
+
return {
|
|
2536
|
+
/**
|
|
2537
|
+
* Render a dynamic list of items using a blueprint view
|
|
2538
|
+
* This is a simplified version for runtime - full implementation requires DOM access
|
|
2539
|
+
*/
|
|
2540
|
+
renderDynamicList: (options) => {
|
|
2541
|
+
const { blueprint, targetContainer, data = [], clearExisting = true, itemProps = {} } = options;
|
|
2542
|
+
const container = typeof document !== "undefined" ? document.querySelector(targetContainer) || document.querySelector(`[data-servly-id="${targetContainer.replace("#", "")}"]`) : null;
|
|
2543
|
+
if (!container) {
|
|
2544
|
+
console.warn(`[shortcuts.renderDynamicList] Container not found: ${targetContainer}`);
|
|
2545
|
+
return { success: false, error: "Container not found" };
|
|
2546
|
+
}
|
|
2547
|
+
if (clearExisting) {
|
|
2548
|
+
container.innerHTML = "";
|
|
2549
|
+
}
|
|
2550
|
+
const event = new CustomEvent("servly:renderDynamicList", {
|
|
2551
|
+
bubbles: true,
|
|
2552
|
+
detail: {
|
|
2553
|
+
blueprint,
|
|
2554
|
+
targetContainer,
|
|
2555
|
+
data,
|
|
2556
|
+
itemProps,
|
|
2557
|
+
container
|
|
2558
|
+
}
|
|
2559
|
+
});
|
|
2560
|
+
container.dispatchEvent(event);
|
|
2561
|
+
return { success: true, itemCount: data.length };
|
|
2562
|
+
},
|
|
2563
|
+
/**
|
|
2564
|
+
* Quick list rendering helper
|
|
2565
|
+
*/
|
|
2566
|
+
renderList: (blueprint, targetContainer, data, options = {}) => {
|
|
2567
|
+
return createShortcuts(ctx).renderDynamicList({
|
|
2568
|
+
blueprint,
|
|
2569
|
+
targetContainer,
|
|
2570
|
+
data,
|
|
2571
|
+
...options
|
|
2572
|
+
});
|
|
2573
|
+
},
|
|
2574
|
+
/**
|
|
2575
|
+
* Set state value
|
|
2576
|
+
*/
|
|
2577
|
+
setState: (key, value) => {
|
|
2578
|
+
if (ctx.stateManager) {
|
|
2579
|
+
ctx.stateManager.set(key, value, ctx.elementId);
|
|
2580
|
+
return { success: true };
|
|
2581
|
+
}
|
|
2582
|
+
return { success: false, error: "No state manager" };
|
|
2583
|
+
},
|
|
2584
|
+
/**
|
|
2585
|
+
* Get state value
|
|
2586
|
+
*/
|
|
2587
|
+
getState: (key) => {
|
|
2588
|
+
if (ctx.stateManager) {
|
|
2589
|
+
return ctx.stateManager.get(key);
|
|
2590
|
+
}
|
|
2591
|
+
return void 0;
|
|
2592
|
+
},
|
|
2593
|
+
/**
|
|
2594
|
+
* Toggle state value
|
|
2595
|
+
*/
|
|
2596
|
+
toggleState: (key) => {
|
|
2597
|
+
if (ctx.stateManager) {
|
|
2598
|
+
ctx.stateManager.toggle(key, ctx.elementId);
|
|
2599
|
+
return { success: true };
|
|
2600
|
+
}
|
|
2601
|
+
return { success: false, error: "No state manager" };
|
|
2602
|
+
},
|
|
2603
|
+
/**
|
|
2604
|
+
* Navigate to URL
|
|
2605
|
+
*/
|
|
2606
|
+
navigateTo: (url, options) => {
|
|
2607
|
+
navigateTo(url, options);
|
|
2608
|
+
return { success: true };
|
|
2609
|
+
},
|
|
2610
|
+
/**
|
|
2611
|
+
* Log to console (for debugging)
|
|
2612
|
+
*/
|
|
2613
|
+
log: (...args) => {
|
|
2614
|
+
console.log("[Servly]", ...args);
|
|
2615
|
+
},
|
|
2616
|
+
/**
|
|
2617
|
+
* Show alert
|
|
2618
|
+
*/
|
|
2619
|
+
alert: (message) => {
|
|
2620
|
+
if (typeof alert !== "undefined") {
|
|
2621
|
+
alert(message);
|
|
2622
|
+
}
|
|
2623
|
+
},
|
|
2624
|
+
/**
|
|
2625
|
+
* Get element by ID
|
|
2626
|
+
*/
|
|
2627
|
+
getElement: (id) => {
|
|
2628
|
+
if (typeof document === "undefined") return null;
|
|
2629
|
+
return document.querySelector(`[data-servly-id="${id}"]`) || document.getElementById(id);
|
|
2630
|
+
},
|
|
2631
|
+
/**
|
|
2632
|
+
* Set element text content
|
|
2633
|
+
*/
|
|
2634
|
+
setText: (selector, text) => {
|
|
2635
|
+
if (typeof document === "undefined") return { success: false };
|
|
2636
|
+
const el = document.querySelector(selector) || document.querySelector(`[data-servly-id="${selector.replace("#", "")}"]`);
|
|
2637
|
+
if (el) {
|
|
2638
|
+
el.textContent = text;
|
|
2639
|
+
return { success: true };
|
|
2640
|
+
}
|
|
2641
|
+
return { success: false, error: "Element not found" };
|
|
2642
|
+
},
|
|
2643
|
+
/**
|
|
2644
|
+
* Add class to element
|
|
2645
|
+
*/
|
|
2646
|
+
addClass: (selector, className) => {
|
|
2647
|
+
if (typeof document === "undefined") return { success: false };
|
|
2648
|
+
const el = document.querySelector(selector);
|
|
2649
|
+
if (el) {
|
|
2650
|
+
el.classList.add(className);
|
|
2651
|
+
return { success: true };
|
|
2652
|
+
}
|
|
2653
|
+
return { success: false, error: "Element not found" };
|
|
2654
|
+
},
|
|
2655
|
+
/**
|
|
2656
|
+
* Remove class from element
|
|
2657
|
+
*/
|
|
2658
|
+
removeClass: (selector, className) => {
|
|
2659
|
+
if (typeof document === "undefined") return { success: false };
|
|
2660
|
+
const el = document.querySelector(selector);
|
|
2661
|
+
if (el) {
|
|
2662
|
+
el.classList.remove(className);
|
|
2663
|
+
return { success: true };
|
|
2664
|
+
}
|
|
2665
|
+
return { success: false, error: "Element not found" };
|
|
2666
|
+
},
|
|
2667
|
+
/**
|
|
2668
|
+
* Toggle class on element
|
|
2669
|
+
*/
|
|
2670
|
+
toggleClass: (selector, className) => {
|
|
2671
|
+
if (typeof document === "undefined") return { success: false };
|
|
2672
|
+
const el = document.querySelector(selector);
|
|
2673
|
+
if (el) {
|
|
2674
|
+
el.classList.toggle(className);
|
|
2675
|
+
return { success: true };
|
|
2676
|
+
}
|
|
2677
|
+
return { success: false, error: "Element not found" };
|
|
2678
|
+
},
|
|
2679
|
+
/**
|
|
2680
|
+
* Local storage helpers
|
|
2681
|
+
*/
|
|
2682
|
+
localStorage: {
|
|
2683
|
+
get: (key, defaultValue) => getLocalStorage(key, defaultValue),
|
|
2684
|
+
set: (key, value) => setLocalStorage(key, value),
|
|
2685
|
+
remove: (key) => {
|
|
2686
|
+
if (typeof localStorage !== "undefined") {
|
|
2687
|
+
localStorage.removeItem(key);
|
|
2688
|
+
}
|
|
2689
|
+
}
|
|
2690
|
+
},
|
|
2691
|
+
/**
|
|
2692
|
+
* Session storage helpers
|
|
2693
|
+
*/
|
|
2694
|
+
sessionStorage: {
|
|
2695
|
+
get: (key, defaultValue) => getSessionStorage(key, defaultValue),
|
|
2696
|
+
set: (key, value) => setSessionStorage(key, value),
|
|
2697
|
+
remove: (key) => {
|
|
2698
|
+
if (typeof sessionStorage !== "undefined") {
|
|
2699
|
+
sessionStorage.removeItem(key);
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
},
|
|
2703
|
+
/**
|
|
2704
|
+
* Clipboard helpers
|
|
2705
|
+
*/
|
|
2706
|
+
clipboard: {
|
|
2707
|
+
copy: async (text) => {
|
|
2708
|
+
if (typeof navigator !== "undefined" && navigator.clipboard) {
|
|
2709
|
+
try {
|
|
2710
|
+
await navigator.clipboard.writeText(text);
|
|
2711
|
+
return { success: true };
|
|
2712
|
+
} catch (error) {
|
|
2713
|
+
return { success: false, error };
|
|
2714
|
+
}
|
|
2715
|
+
}
|
|
2716
|
+
return { success: false, error: "Clipboard not available" };
|
|
2717
|
+
}
|
|
2718
|
+
},
|
|
2719
|
+
/**
|
|
2720
|
+
* Delay execution
|
|
2721
|
+
*/
|
|
2722
|
+
delay: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
2723
|
+
/**
|
|
2724
|
+
* Current context accessors
|
|
2725
|
+
*/
|
|
2726
|
+
currentItem: ctx.currentItem,
|
|
2727
|
+
currentIndex: ctx.currentIndex,
|
|
2728
|
+
elementId: ctx.elementId
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2438
2731
|
var builtInPlugins = {
|
|
2439
2732
|
/**
|
|
2440
2733
|
* Set state value
|
|
@@ -2561,6 +2854,7 @@ var builtInPlugins = {
|
|
|
2561
2854
|
const code = action.code || action.config?.code;
|
|
2562
2855
|
if (!code) return { success: false, error: "No code provided" };
|
|
2563
2856
|
try {
|
|
2857
|
+
const shortcuts = createShortcuts(ctx);
|
|
2564
2858
|
const fn = new Function(
|
|
2565
2859
|
"event",
|
|
2566
2860
|
"props",
|
|
@@ -2569,6 +2863,7 @@ var builtInPlugins = {
|
|
|
2569
2863
|
"stateManager",
|
|
2570
2864
|
"currentItem",
|
|
2571
2865
|
"currentIndex",
|
|
2866
|
+
"shortcuts",
|
|
2572
2867
|
code
|
|
2573
2868
|
);
|
|
2574
2869
|
const result = fn(
|
|
@@ -2578,7 +2873,8 @@ var builtInPlugins = {
|
|
|
2578
2873
|
ctx.context.context || {},
|
|
2579
2874
|
ctx.stateManager,
|
|
2580
2875
|
ctx.currentItem,
|
|
2581
|
-
ctx.currentIndex
|
|
2876
|
+
ctx.currentIndex,
|
|
2877
|
+
shortcuts
|
|
2582
2878
|
);
|
|
2583
2879
|
return { success: true, result };
|
|
2584
2880
|
} catch (error) {
|
|
@@ -5282,6 +5578,275 @@ async function getDependencyTree(id, options = {}) {
|
|
|
5282
5578
|
return data.data;
|
|
5283
5579
|
}
|
|
5284
5580
|
|
|
5581
|
+
// src/mount.ts
|
|
5582
|
+
async function mount(options) {
|
|
5583
|
+
const {
|
|
5584
|
+
componentId,
|
|
5585
|
+
target,
|
|
5586
|
+
props = {},
|
|
5587
|
+
state = {},
|
|
5588
|
+
context = {},
|
|
5589
|
+
version = "latest",
|
|
5590
|
+
eventHandlers,
|
|
5591
|
+
fetchOptions = {},
|
|
5592
|
+
onReady,
|
|
5593
|
+
onError,
|
|
5594
|
+
onLoadStart,
|
|
5595
|
+
onLoadEnd,
|
|
5596
|
+
loadingComponent,
|
|
5597
|
+
errorComponent,
|
|
5598
|
+
loadingDelay = 0,
|
|
5599
|
+
minLoadingTime = 0
|
|
5600
|
+
} = options;
|
|
5601
|
+
const container = typeof target === "string" ? document.querySelector(target) : target;
|
|
5602
|
+
if (!container) {
|
|
5603
|
+
const err = new Error(`Target container not found: ${target}`);
|
|
5604
|
+
onError?.(err);
|
|
5605
|
+
throw err;
|
|
5606
|
+
}
|
|
5607
|
+
let loadingElement = null;
|
|
5608
|
+
let loadingTimeout = null;
|
|
5609
|
+
let loadingStartTime = null;
|
|
5610
|
+
const showLoading = () => {
|
|
5611
|
+
if (loadingComponent) {
|
|
5612
|
+
loadingStartTime = Date.now();
|
|
5613
|
+
if (typeof loadingComponent === "string") {
|
|
5614
|
+
loadingElement = document.createElement("div");
|
|
5615
|
+
loadingElement.innerHTML = loadingComponent;
|
|
5616
|
+
loadingElement = loadingElement.firstElementChild || loadingElement;
|
|
5617
|
+
} else {
|
|
5618
|
+
loadingElement = loadingComponent.cloneNode(true);
|
|
5619
|
+
}
|
|
5620
|
+
container.appendChild(loadingElement);
|
|
5621
|
+
}
|
|
5622
|
+
};
|
|
5623
|
+
const removeLoading = async () => {
|
|
5624
|
+
if (loadingTimeout) {
|
|
5625
|
+
clearTimeout(loadingTimeout);
|
|
5626
|
+
loadingTimeout = null;
|
|
5627
|
+
}
|
|
5628
|
+
if (loadingStartTime && minLoadingTime > 0) {
|
|
5629
|
+
const elapsed = Date.now() - loadingStartTime;
|
|
5630
|
+
if (elapsed < minLoadingTime) {
|
|
5631
|
+
await new Promise((resolve) => setTimeout(resolve, minLoadingTime - elapsed));
|
|
5632
|
+
}
|
|
5633
|
+
}
|
|
5634
|
+
if (loadingElement && loadingElement.parentNode) {
|
|
5635
|
+
loadingElement.parentNode.removeChild(loadingElement);
|
|
5636
|
+
loadingElement = null;
|
|
5637
|
+
}
|
|
5638
|
+
};
|
|
5639
|
+
const showError = (err) => {
|
|
5640
|
+
if (errorComponent) {
|
|
5641
|
+
const errorContent = errorComponent(err);
|
|
5642
|
+
if (typeof errorContent === "string") {
|
|
5643
|
+
container.innerHTML = errorContent;
|
|
5644
|
+
} else {
|
|
5645
|
+
container.innerHTML = "";
|
|
5646
|
+
container.appendChild(errorContent);
|
|
5647
|
+
}
|
|
5648
|
+
}
|
|
5649
|
+
};
|
|
5650
|
+
try {
|
|
5651
|
+
onLoadStart?.();
|
|
5652
|
+
if (loadingComponent) {
|
|
5653
|
+
if (loadingDelay > 0) {
|
|
5654
|
+
loadingTimeout = setTimeout(showLoading, loadingDelay);
|
|
5655
|
+
} else {
|
|
5656
|
+
showLoading();
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
5659
|
+
const fetchResult = await fetchComponentWithDependencies(componentId, {
|
|
5660
|
+
...fetchOptions,
|
|
5661
|
+
version
|
|
5662
|
+
});
|
|
5663
|
+
const { data, fromCache, version: resolvedVersion, registry, views } = fetchResult;
|
|
5664
|
+
await removeLoading();
|
|
5665
|
+
const bindingContext = {
|
|
5666
|
+
props,
|
|
5667
|
+
state,
|
|
5668
|
+
context
|
|
5669
|
+
};
|
|
5670
|
+
const renderResult = render({
|
|
5671
|
+
container,
|
|
5672
|
+
elements: data.layout,
|
|
5673
|
+
context: bindingContext,
|
|
5674
|
+
eventHandlers,
|
|
5675
|
+
componentRegistry: registry,
|
|
5676
|
+
views
|
|
5677
|
+
});
|
|
5678
|
+
const result = {
|
|
5679
|
+
update: (newContext) => {
|
|
5680
|
+
renderResult.update({
|
|
5681
|
+
props: newContext.props ?? props,
|
|
5682
|
+
state: newContext.state ?? state,
|
|
5683
|
+
context: newContext.context ?? context
|
|
5684
|
+
});
|
|
5685
|
+
},
|
|
5686
|
+
destroy: () => {
|
|
5687
|
+
renderResult.destroy();
|
|
5688
|
+
},
|
|
5689
|
+
rootElement: renderResult.rootElement,
|
|
5690
|
+
container,
|
|
5691
|
+
data,
|
|
5692
|
+
fromCache,
|
|
5693
|
+
version: resolvedVersion
|
|
5694
|
+
};
|
|
5695
|
+
onLoadEnd?.();
|
|
5696
|
+
onReady?.(result);
|
|
5697
|
+
return result;
|
|
5698
|
+
} catch (error) {
|
|
5699
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
5700
|
+
await removeLoading();
|
|
5701
|
+
showError(err);
|
|
5702
|
+
onLoadEnd?.();
|
|
5703
|
+
onError?.(err);
|
|
5704
|
+
throw err;
|
|
5705
|
+
}
|
|
5706
|
+
}
|
|
5707
|
+
function mountData(options) {
|
|
5708
|
+
const {
|
|
5709
|
+
data,
|
|
5710
|
+
target,
|
|
5711
|
+
props = {},
|
|
5712
|
+
state = {},
|
|
5713
|
+
context = {},
|
|
5714
|
+
eventHandlers
|
|
5715
|
+
} = options;
|
|
5716
|
+
const container = typeof target === "string" ? document.querySelector(target) : target;
|
|
5717
|
+
if (!container) {
|
|
5718
|
+
throw new Error(`Target container not found: ${target}`);
|
|
5719
|
+
}
|
|
5720
|
+
const bindingContext = {
|
|
5721
|
+
props,
|
|
5722
|
+
state,
|
|
5723
|
+
context
|
|
5724
|
+
};
|
|
5725
|
+
const renderResult = render({
|
|
5726
|
+
container,
|
|
5727
|
+
elements: data.layout,
|
|
5728
|
+
context: bindingContext,
|
|
5729
|
+
eventHandlers
|
|
5730
|
+
});
|
|
5731
|
+
return {
|
|
5732
|
+
update: (newContext) => {
|
|
5733
|
+
renderResult.update({
|
|
5734
|
+
props: newContext.props ?? props,
|
|
5735
|
+
state: newContext.state ?? state,
|
|
5736
|
+
context: newContext.context ?? context
|
|
5737
|
+
});
|
|
5738
|
+
},
|
|
5739
|
+
destroy: () => {
|
|
5740
|
+
renderResult.destroy();
|
|
5741
|
+
},
|
|
5742
|
+
rootElement: renderResult.rootElement,
|
|
5743
|
+
container,
|
|
5744
|
+
data
|
|
5745
|
+
};
|
|
5746
|
+
}
|
|
5747
|
+
|
|
5748
|
+
// src/prefetch.ts
|
|
5749
|
+
async function prefetch(componentId, version = "latest", options = {}) {
|
|
5750
|
+
const { includeDependencies = true, ...fetchOptions } = options;
|
|
5751
|
+
try {
|
|
5752
|
+
if (includeDependencies) {
|
|
5753
|
+
await fetchComponentWithDependencies(componentId, { ...fetchOptions, version });
|
|
5754
|
+
} else {
|
|
5755
|
+
await fetchComponent(componentId, { ...fetchOptions, version });
|
|
5756
|
+
}
|
|
5757
|
+
return true;
|
|
5758
|
+
} catch (error) {
|
|
5759
|
+
console.warn(`[Servly] Failed to prefetch ${componentId}:`, error);
|
|
5760
|
+
return false;
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
async function prefetchAll(components, options = {}) {
|
|
5764
|
+
const results = await Promise.allSettled(
|
|
5765
|
+
components.map((comp) => {
|
|
5766
|
+
const id = typeof comp === "string" ? comp : comp.id;
|
|
5767
|
+
const version = typeof comp === "string" ? "latest" : comp.version || "latest";
|
|
5768
|
+
return prefetch(id, version, options).then((success2) => ({ id, success: success2 }));
|
|
5769
|
+
})
|
|
5770
|
+
);
|
|
5771
|
+
const success = [];
|
|
5772
|
+
const failed = [];
|
|
5773
|
+
for (const result of results) {
|
|
5774
|
+
if (result.status === "fulfilled" && result.value.success) {
|
|
5775
|
+
success.push(result.value.id);
|
|
5776
|
+
} else {
|
|
5777
|
+
const id = result.status === "fulfilled" ? result.value.id : "unknown";
|
|
5778
|
+
failed.push(id);
|
|
5779
|
+
}
|
|
5780
|
+
}
|
|
5781
|
+
return { success, failed };
|
|
5782
|
+
}
|
|
5783
|
+
function prefetchOnVisible(target, components, options = {}) {
|
|
5784
|
+
const { rootMargin = "100px", threshold = 0, ...prefetchOptions } = options;
|
|
5785
|
+
const element = typeof target === "string" ? document.querySelector(target) : target;
|
|
5786
|
+
if (!element) {
|
|
5787
|
+
console.warn(`[Servly] prefetchOnVisible: Target not found: ${target}`);
|
|
5788
|
+
return () => {
|
|
5789
|
+
};
|
|
5790
|
+
}
|
|
5791
|
+
let hasPrefetched = false;
|
|
5792
|
+
const observer = new IntersectionObserver(
|
|
5793
|
+
(entries) => {
|
|
5794
|
+
for (const entry of entries) {
|
|
5795
|
+
if (entry.isIntersecting && !hasPrefetched) {
|
|
5796
|
+
hasPrefetched = true;
|
|
5797
|
+
prefetchAll(components, prefetchOptions);
|
|
5798
|
+
observer.disconnect();
|
|
5799
|
+
}
|
|
5800
|
+
}
|
|
5801
|
+
},
|
|
5802
|
+
{ rootMargin, threshold }
|
|
5803
|
+
);
|
|
5804
|
+
observer.observe(element);
|
|
5805
|
+
return () => observer.disconnect();
|
|
5806
|
+
}
|
|
5807
|
+
function prefetchOnIdle(components, options = {}) {
|
|
5808
|
+
const { timeout = 5e3, ...prefetchOptions } = options;
|
|
5809
|
+
const callback = () => {
|
|
5810
|
+
prefetchAll(components, prefetchOptions);
|
|
5811
|
+
};
|
|
5812
|
+
if ("requestIdleCallback" in window) {
|
|
5813
|
+
window.requestIdleCallback(callback, { timeout });
|
|
5814
|
+
} else {
|
|
5815
|
+
setTimeout(callback, 1);
|
|
5816
|
+
}
|
|
5817
|
+
}
|
|
5818
|
+
function prefetchOnHover(target, componentId, version = "latest", options = {}) {
|
|
5819
|
+
const { delay = 100, ...prefetchOptions } = options;
|
|
5820
|
+
const element = typeof target === "string" ? document.querySelector(target) : target;
|
|
5821
|
+
if (!element) {
|
|
5822
|
+
console.warn(`[Servly] prefetchOnHover: Target not found: ${target}`);
|
|
5823
|
+
return () => {
|
|
5824
|
+
};
|
|
5825
|
+
}
|
|
5826
|
+
let timeoutId = null;
|
|
5827
|
+
let hasPrefetched = false;
|
|
5828
|
+
const handleMouseEnter = () => {
|
|
5829
|
+
if (hasPrefetched) return;
|
|
5830
|
+
timeoutId = setTimeout(() => {
|
|
5831
|
+
hasPrefetched = true;
|
|
5832
|
+
prefetch(componentId, version, prefetchOptions);
|
|
5833
|
+
}, delay);
|
|
5834
|
+
};
|
|
5835
|
+
const handleMouseLeave = () => {
|
|
5836
|
+
if (timeoutId) {
|
|
5837
|
+
clearTimeout(timeoutId);
|
|
5838
|
+
timeoutId = null;
|
|
5839
|
+
}
|
|
5840
|
+
};
|
|
5841
|
+
element.addEventListener("mouseenter", handleMouseEnter);
|
|
5842
|
+
element.addEventListener("mouseleave", handleMouseLeave);
|
|
5843
|
+
return () => {
|
|
5844
|
+
element.removeEventListener("mouseenter", handleMouseEnter);
|
|
5845
|
+
element.removeEventListener("mouseleave", handleMouseLeave);
|
|
5846
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
5847
|
+
};
|
|
5848
|
+
}
|
|
5849
|
+
|
|
5285
5850
|
// src/version.ts
|
|
5286
5851
|
function parseVersion(version) {
|
|
5287
5852
|
const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
|
|
@@ -5652,6 +6217,55 @@ function getSampleValue(def) {
|
|
|
5652
6217
|
// src/index.ts
|
|
5653
6218
|
init_registry();
|
|
5654
6219
|
init_tailwind();
|
|
6220
|
+
|
|
6221
|
+
// src/slotBindings.ts
|
|
6222
|
+
function extractSlotBindings(layout) {
|
|
6223
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
6224
|
+
const elementMap = /* @__PURE__ */ new Map();
|
|
6225
|
+
for (const element of layout) {
|
|
6226
|
+
elementMap.set(element.i, element);
|
|
6227
|
+
}
|
|
6228
|
+
const traceToProps = (element, propPath, visited = /* @__PURE__ */ new Set()) => {
|
|
6229
|
+
if (visited.has(element.i)) return null;
|
|
6230
|
+
visited.add(element.i);
|
|
6231
|
+
const inputs = element.configuration?.bindings?.inputs || {};
|
|
6232
|
+
const binding = inputs[propPath];
|
|
6233
|
+
if (!binding) return null;
|
|
6234
|
+
if (binding.source === "props" && binding.path) {
|
|
6235
|
+
return binding.path;
|
|
6236
|
+
}
|
|
6237
|
+
if (binding.source === "parent" && binding.path && element.parent) {
|
|
6238
|
+
const parentElement = elementMap.get(element.parent);
|
|
6239
|
+
if (parentElement) {
|
|
6240
|
+
return traceToProps(parentElement, binding.path, visited);
|
|
6241
|
+
}
|
|
6242
|
+
}
|
|
6243
|
+
return null;
|
|
6244
|
+
};
|
|
6245
|
+
for (const element of layout) {
|
|
6246
|
+
if (element.componentId !== "slot") continue;
|
|
6247
|
+
const inputs = element.configuration?.bindings?.inputs || {};
|
|
6248
|
+
const slotId = element.configuration?.slotName || element.i;
|
|
6249
|
+
for (const [targetProp, binding] of Object.entries(inputs)) {
|
|
6250
|
+
if (["child", "children", "content"].includes(targetProp)) {
|
|
6251
|
+
const b = binding;
|
|
6252
|
+
if (!b) continue;
|
|
6253
|
+
if (b.source === "props" && b.path) {
|
|
6254
|
+
bindings.set(b.path, slotId);
|
|
6255
|
+
} else if (b.source === "parent" && b.path && element.parent) {
|
|
6256
|
+
const parentElement = elementMap.get(element.parent);
|
|
6257
|
+
if (parentElement) {
|
|
6258
|
+
const originalProp = traceToProps(parentElement, b.path);
|
|
6259
|
+
if (originalProp) {
|
|
6260
|
+
bindings.set(originalProp, slotId);
|
|
6261
|
+
}
|
|
6262
|
+
}
|
|
6263
|
+
}
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
return bindings;
|
|
6268
|
+
}
|
|
5655
6269
|
// Annotate the CommonJS export names for ESM import in node:
|
|
5656
6270
|
0 && (module.exports = {
|
|
5657
6271
|
AnalyticsCollector,
|
|
@@ -5701,6 +6315,7 @@ init_tailwind();
|
|
|
5701
6315
|
extractDependenciesFromCode,
|
|
5702
6316
|
extractOverrideDependencies,
|
|
5703
6317
|
extractReferencedViewIds,
|
|
6318
|
+
extractSlotBindings,
|
|
5704
6319
|
fetchComponent,
|
|
5705
6320
|
fetchComponentWithDependencies,
|
|
5706
6321
|
formatStyleValue,
|
|
@@ -5754,9 +6369,16 @@ init_tailwind();
|
|
|
5754
6369
|
loadFont,
|
|
5755
6370
|
loadFonts,
|
|
5756
6371
|
markElementReady,
|
|
6372
|
+
mount,
|
|
6373
|
+
mountData,
|
|
5757
6374
|
navigateTo,
|
|
5758
6375
|
parseVersion,
|
|
6376
|
+
prefetch,
|
|
6377
|
+
prefetchAll,
|
|
5759
6378
|
prefetchComponents,
|
|
6379
|
+
prefetchOnHover,
|
|
6380
|
+
prefetchOnIdle,
|
|
6381
|
+
prefetchOnVisible,
|
|
5760
6382
|
preloadIcons,
|
|
5761
6383
|
preloadTailwind,
|
|
5762
6384
|
preventFOUC,
|