@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/README.md
CHANGED
|
@@ -14,10 +14,88 @@ pnpm add @servlyadmin/runtime-core
|
|
|
14
14
|
|
|
15
15
|
## Quick Start
|
|
16
16
|
|
|
17
|
+
The simplest way to render a component:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { mount } from '@servlyadmin/runtime-core';
|
|
21
|
+
|
|
22
|
+
// Mount a component - that's it!
|
|
23
|
+
const app = await mount({
|
|
24
|
+
componentId: 'my-component-id',
|
|
25
|
+
target: '#app',
|
|
26
|
+
props: { title: 'Hello World' }
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
// Update props
|
|
30
|
+
app.update({ props: { title: 'Updated!' } });
|
|
31
|
+
|
|
32
|
+
// Cleanup
|
|
33
|
+
app.destroy();
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### With Callbacks
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
const app = await mount({
|
|
40
|
+
componentId: 'my-component-id',
|
|
41
|
+
target: '#app',
|
|
42
|
+
props: { title: 'Hello' },
|
|
43
|
+
onReady: (result) => console.log('Mounted!', result.version),
|
|
44
|
+
onError: (err) => console.error('Failed:', err)
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### With Loading & Error States
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const app = await mount({
|
|
52
|
+
componentId: 'my-component-id',
|
|
53
|
+
target: '#app',
|
|
54
|
+
props: { title: 'Hello' },
|
|
55
|
+
|
|
56
|
+
// Show loading indicator
|
|
57
|
+
loadingComponent: '<div class="skeleton animate-pulse h-32 bg-gray-200 rounded"></div>',
|
|
58
|
+
|
|
59
|
+
// Show error message on failure
|
|
60
|
+
errorComponent: (err) => `<div class="text-red-500">Failed to load: ${err.message}</div>`,
|
|
61
|
+
|
|
62
|
+
// Optional: delay before showing loading (avoids flash for fast loads)
|
|
63
|
+
loadingDelay: 200,
|
|
64
|
+
|
|
65
|
+
// Optional: minimum time to show loading (avoids flash)
|
|
66
|
+
minLoadingTime: 500,
|
|
67
|
+
|
|
68
|
+
// Lifecycle callbacks
|
|
69
|
+
onLoadStart: () => console.log('Loading...'),
|
|
70
|
+
onLoadEnd: () => console.log('Done!'),
|
|
71
|
+
onReady: (result) => console.log('Mounted!'),
|
|
72
|
+
onError: (err) => console.error('Failed:', err)
|
|
73
|
+
});
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### With Version & Cache Control
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const app = await mount({
|
|
80
|
+
componentId: 'my-component-id',
|
|
81
|
+
target: document.getElementById('app'),
|
|
82
|
+
props: { title: 'Hello' },
|
|
83
|
+
version: '^1.0.0',
|
|
84
|
+
fetchOptions: {
|
|
85
|
+
cacheStrategy: 'memory',
|
|
86
|
+
forceRefresh: true
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Low-Level API
|
|
92
|
+
|
|
93
|
+
For more control, use `fetchComponent` and `render` directly:
|
|
94
|
+
|
|
17
95
|
```typescript
|
|
18
96
|
import { render, fetchComponent } from '@servlyadmin/runtime-core';
|
|
19
97
|
|
|
20
|
-
// Fetch a component from the registry
|
|
98
|
+
// Fetch a component from the registry
|
|
21
99
|
const { data } = await fetchComponent('my-component-id');
|
|
22
100
|
|
|
23
101
|
// Render to a container
|
|
@@ -83,6 +161,36 @@ const { data } = await fetchComponent('my-component', {
|
|
|
83
161
|
});
|
|
84
162
|
```
|
|
85
163
|
|
|
164
|
+
## Prefetching
|
|
165
|
+
|
|
166
|
+
Preload components for faster subsequent rendering:
|
|
167
|
+
|
|
168
|
+
```typescript
|
|
169
|
+
import { prefetch, prefetchAll, prefetchOnHover, prefetchOnVisible, prefetchOnIdle } from '@servlyadmin/runtime-core';
|
|
170
|
+
|
|
171
|
+
// Prefetch a single component
|
|
172
|
+
await prefetch('pricing-card');
|
|
173
|
+
|
|
174
|
+
// Prefetch multiple components
|
|
175
|
+
await prefetchAll(['pricing-card', 'contact-form', 'navbar']);
|
|
176
|
+
|
|
177
|
+
// Prefetch with versions
|
|
178
|
+
await prefetchAll([
|
|
179
|
+
{ id: 'pricing-card', version: '^1.0.0' },
|
|
180
|
+
{ id: 'contact-form', version: 'latest' }
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
// Prefetch on hover (great for modals/dialogs)
|
|
184
|
+
const cleanup = prefetchOnHover('#open-modal-btn', 'modal-component');
|
|
185
|
+
// Later: cleanup() to remove listener
|
|
186
|
+
|
|
187
|
+
// Prefetch when element becomes visible (Intersection Observer)
|
|
188
|
+
const cleanup = prefetchOnVisible('#pricing-section', ['pricing-card', 'feature-list']);
|
|
189
|
+
|
|
190
|
+
// Prefetch when browser is idle (non-critical components)
|
|
191
|
+
prefetchOnIdle(['footer', 'sidebar', 'help-modal']);
|
|
192
|
+
```
|
|
193
|
+
|
|
86
194
|
## Core Concepts
|
|
87
195
|
|
|
88
196
|
### Layout Elements
|
|
@@ -135,6 +243,65 @@ const elements = [
|
|
|
135
243
|
|
|
136
244
|
## API Reference
|
|
137
245
|
|
|
246
|
+
### mount(options) - Recommended
|
|
247
|
+
|
|
248
|
+
The simplest way to render a component. Handles fetching, container resolution, and rendering.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
const app = await mount({
|
|
252
|
+
componentId: string, // Required: Component ID to fetch
|
|
253
|
+
target: string | HTMLElement, // Required: CSS selector or element
|
|
254
|
+
props?: Record<string, any>, // Props to pass (default: {})
|
|
255
|
+
state?: Record<string, any>, // Initial state (default: {})
|
|
256
|
+
context?: Record<string, any>, // Additional context (default: {})
|
|
257
|
+
version?: string, // Version specifier (default: 'latest')
|
|
258
|
+
eventHandlers?: Record<string, Record<string, (e: Event) => void>>,
|
|
259
|
+
fetchOptions?: {
|
|
260
|
+
cacheStrategy?: 'localStorage' | 'memory' | 'none',
|
|
261
|
+
forceRefresh?: boolean,
|
|
262
|
+
apiKey?: string,
|
|
263
|
+
retryConfig?: RetryConfig,
|
|
264
|
+
},
|
|
265
|
+
|
|
266
|
+
// Loading & Error States
|
|
267
|
+
loadingComponent?: string | HTMLElement, // HTML to show while loading
|
|
268
|
+
errorComponent?: (err: Error) => string | HTMLElement, // Error display
|
|
269
|
+
loadingDelay?: number, // Delay before showing loading (ms)
|
|
270
|
+
minLoadingTime?: number, // Minimum loading display time (ms)
|
|
271
|
+
|
|
272
|
+
// Lifecycle Callbacks
|
|
273
|
+
onLoadStart?: () => void, // Called when loading starts
|
|
274
|
+
onLoadEnd?: () => void, // Called when loading ends
|
|
275
|
+
onReady?: (result: MountResult) => void,
|
|
276
|
+
onError?: (error: Error) => void,
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
// Returns MountResult
|
|
280
|
+
interface MountResult {
|
|
281
|
+
update(context: Partial<BindingContext>): void;
|
|
282
|
+
destroy(): void;
|
|
283
|
+
rootElement: HTMLElement | null;
|
|
284
|
+
container: HTMLElement;
|
|
285
|
+
data: ComponentData;
|
|
286
|
+
fromCache: boolean;
|
|
287
|
+
version: string;
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### mountData(options)
|
|
292
|
+
|
|
293
|
+
Mount with pre-fetched data (useful for SSR or custom data sources):
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
import { mountData } from '@servlyadmin/runtime-core';
|
|
297
|
+
|
|
298
|
+
const app = mountData({
|
|
299
|
+
data: myComponentData, // Pre-fetched ComponentData
|
|
300
|
+
target: '#app',
|
|
301
|
+
props: { title: 'Hello' }
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
138
305
|
### render(options)
|
|
139
306
|
|
|
140
307
|
Renders elements to a container.
|
|
@@ -284,6 +451,53 @@ hasTemplateSyntax('{{props.name}}'); // true
|
|
|
284
451
|
hasTemplateSyntax('static text'); // false
|
|
285
452
|
```
|
|
286
453
|
|
|
454
|
+
### Prefetch API
|
|
455
|
+
|
|
456
|
+
Preload components for faster subsequent rendering.
|
|
457
|
+
|
|
458
|
+
```typescript
|
|
459
|
+
import {
|
|
460
|
+
prefetch,
|
|
461
|
+
prefetchAll,
|
|
462
|
+
prefetchOnHover,
|
|
463
|
+
prefetchOnVisible,
|
|
464
|
+
prefetchOnIdle
|
|
465
|
+
} from '@servlyadmin/runtime-core';
|
|
466
|
+
|
|
467
|
+
// Prefetch single component
|
|
468
|
+
await prefetch('pricing-card');
|
|
469
|
+
await prefetch('pricing-card', '^1.0.0'); // With version
|
|
470
|
+
|
|
471
|
+
// Prefetch multiple components
|
|
472
|
+
const { success, failed } = await prefetchAll([
|
|
473
|
+
'pricing-card',
|
|
474
|
+
'contact-form',
|
|
475
|
+
{ id: 'navbar', version: '^2.0.0' }
|
|
476
|
+
]);
|
|
477
|
+
|
|
478
|
+
// Prefetch on hover (returns cleanup function)
|
|
479
|
+
const cleanup = prefetchOnHover(
|
|
480
|
+
'#open-modal-btn', // Target element
|
|
481
|
+
'modal-component', // Component ID
|
|
482
|
+
'latest', // Version
|
|
483
|
+
{ delay: 100 } // Options: delay before prefetch
|
|
484
|
+
);
|
|
485
|
+
// Later: cleanup()
|
|
486
|
+
|
|
487
|
+
// Prefetch when element becomes visible
|
|
488
|
+
const cleanup = prefetchOnVisible(
|
|
489
|
+
'#pricing-section', // Target element
|
|
490
|
+
['pricing-card', 'feature-list'], // Components to prefetch
|
|
491
|
+
{ rootMargin: '100px', threshold: 0 } // IntersectionObserver options
|
|
492
|
+
);
|
|
493
|
+
|
|
494
|
+
// Prefetch during browser idle time
|
|
495
|
+
prefetchOnIdle(
|
|
496
|
+
['footer', 'sidebar', 'help-modal'],
|
|
497
|
+
{ timeout: 5000 } // Max wait time before forcing prefetch
|
|
498
|
+
);
|
|
499
|
+
```
|
|
500
|
+
|
|
287
501
|
## Slots
|
|
288
502
|
|
|
289
503
|
Components can define slots for content injection:
|