@servlyadmin/runtime-core 0.1.8 → 0.1.10

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 ADDED
@@ -0,0 +1,308 @@
1
+ # @servlyadmin/runtime-core
2
+
3
+ Framework-agnostic core renderer for Servly components. This package provides the foundation for rendering Servly components in any JavaScript environment.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @servlyadmin/runtime-core
9
+ # or
10
+ yarn add @servlyadmin/runtime-core
11
+ # or
12
+ pnpm add @servlyadmin/runtime-core
13
+ ```
14
+
15
+ ## Quick Start
16
+
17
+ ```typescript
18
+ import { render, fetchComponent } from '@servlyadmin/runtime-core';
19
+
20
+ // Fetch a component from the registry
21
+ const { data } = await fetchComponent('my-component', { version: 'latest' });
22
+
23
+ // Render to a container
24
+ const result = render({
25
+ container: document.getElementById('app'),
26
+ elements: data.layout,
27
+ context: {
28
+ props: { title: 'Hello World' },
29
+ state: {},
30
+ context: {},
31
+ },
32
+ });
33
+
34
+ // Update props
35
+ result.update({
36
+ props: { title: 'Updated Title' },
37
+ state: {},
38
+ context: {},
39
+ });
40
+
41
+ // Cleanup
42
+ result.destroy();
43
+ ```
44
+
45
+ ## Core Concepts
46
+
47
+ ### Layout Elements
48
+
49
+ Components are defined as a tree of layout elements:
50
+
51
+ ```typescript
52
+ interface LayoutElement {
53
+ i: string; // Unique identifier
54
+ type: string; // HTML tag or component type
55
+ configuration?: { // Element configuration
56
+ className?: string;
57
+ style?: Record<string, any>;
58
+ textContent?: string;
59
+ // ... other attributes
60
+ };
61
+ children?: LayoutElement[]; // Nested elements
62
+ }
63
+ ```
64
+
65
+ ### Binding Context
66
+
67
+ Data is passed to components through a binding context:
68
+
69
+ ```typescript
70
+ interface BindingContext {
71
+ props: Record<string, any>; // Component props
72
+ state: Record<string, any>; // Component state
73
+ context: Record<string, any>; // Additional context
74
+ }
75
+ ```
76
+
77
+ ### Template Bindings
78
+
79
+ Use `{{path}}` syntax to bind data:
80
+
81
+ ```typescript
82
+ const elements = [
83
+ {
84
+ i: 'greeting',
85
+ type: 'h1',
86
+ configuration: {
87
+ textContent: 'Hello, {{props.name}}!',
88
+ className: '{{props.className}}',
89
+ },
90
+ },
91
+ ];
92
+ ```
93
+
94
+ ## API Reference
95
+
96
+ ### render(options)
97
+
98
+ Renders elements to a container.
99
+
100
+ ```typescript
101
+ const result = render({
102
+ container: HTMLElement,
103
+ elements: LayoutElement[],
104
+ context: BindingContext,
105
+ eventHandlers?: Record<string, Record<string, (e: Event) => void>>,
106
+ });
107
+
108
+ // Returns
109
+ interface RenderResult {
110
+ update(context: BindingContext): void;
111
+ destroy(): void;
112
+ getElement(id: string): HTMLElement | null;
113
+ }
114
+ ```
115
+
116
+ ### fetchComponent(id, options?)
117
+
118
+ Fetches a component from the registry.
119
+
120
+ ```typescript
121
+ const { data, fromCache } = await fetchComponent('component-id', {
122
+ version: 'latest', // Version specifier
123
+ cacheStrategy: 'memory', // 'memory' | 'localStorage' | 'none'
124
+ forceRefresh: false, // Bypass cache
125
+ timeout: 30000, // Request timeout in ms
126
+ retryConfig: {
127
+ maxRetries: 3,
128
+ retryDelay: 1000,
129
+ },
130
+ });
131
+ ```
132
+
133
+ ### StateManager
134
+
135
+ Manages component state with subscriptions.
136
+
137
+ ```typescript
138
+ import { StateManager } from '@servlyadmin/runtime-core';
139
+
140
+ const stateManager = new StateManager({ count: 0 });
141
+
142
+ // Get/set state
143
+ stateManager.setState({ count: 1 });
144
+ stateManager.getValue('count'); // 1
145
+ stateManager.setValue('user.name', 'John');
146
+
147
+ // Subscribe to changes
148
+ const unsubscribe = stateManager.subscribe((state) => {
149
+ console.log('State changed:', state);
150
+ });
151
+
152
+ // Subscribe to specific path
153
+ stateManager.subscribeToPath('count', (value) => {
154
+ console.log('Count changed:', value);
155
+ });
156
+
157
+ // Batch updates
158
+ stateManager.batch(() => {
159
+ stateManager.setValue('a', 1);
160
+ stateManager.setValue('b', 2);
161
+ }); // Only one notification
162
+ ```
163
+
164
+ ### EventSystem
165
+
166
+ Handles events with plugin-based actions.
167
+
168
+ ```typescript
169
+ import { EventSystem } from '@servlyadmin/runtime-core';
170
+
171
+ const eventSystem = new EventSystem();
172
+
173
+ // Register custom plugin
174
+ eventSystem.registerPlugin('my-action', async (config, context) => {
175
+ console.log('Action executed with:', config);
176
+ });
177
+
178
+ // Create event handler
179
+ const handler = eventSystem.createHandler([
180
+ { key: 'prevent-default', config: {} },
181
+ { key: 'set-state', config: { path: 'clicked', value: true } },
182
+ { key: 'my-action', config: { message: 'Button clicked!' } },
183
+ ]);
184
+
185
+ // Use with element
186
+ button.addEventListener('click', (e) => {
187
+ handler(e, 'button-id', bindingContext);
188
+ });
189
+ ```
190
+
191
+ #### Built-in Plugins
192
+
193
+ - `console-log` - Log messages to console
194
+ - `set-state` - Update state values
195
+ - `delay` - Add delay between actions
196
+ - `prevent-default` - Call event.preventDefault()
197
+ - `stop-propagation` - Call event.stopPropagation()
198
+
199
+ ### Cache
200
+
201
+ Component caching with multiple strategies.
202
+
203
+ ```typescript
204
+ import { ComponentCache } from '@servlyadmin/runtime-core';
205
+
206
+ const cache = new ComponentCache({
207
+ maxSize: 100,
208
+ strategy: 'memory', // 'memory' | 'localStorage' | 'none'
209
+ });
210
+
211
+ // Set with TTL
212
+ cache.set('key', data, { ttl: 60000 }); // 1 minute
213
+
214
+ // Component-specific methods
215
+ cache.setComponent('comp-id', '1.0.0', componentData);
216
+ cache.getComponent('comp-id', 'latest');
217
+ cache.invalidateComponent('comp-id');
218
+
219
+ // Statistics
220
+ const stats = cache.getStats();
221
+ console.log(`Hit rate: ${stats.hitRate * 100}%`);
222
+ ```
223
+
224
+ ### Bindings
225
+
226
+ Template resolution utilities.
227
+
228
+ ```typescript
229
+ import { resolveTemplate, resolveBindings, isTemplate } from '@servlyadmin/runtime-core';
230
+
231
+ const context = {
232
+ props: { name: 'World', count: 42 },
233
+ state: {},
234
+ context: {},
235
+ };
236
+
237
+ // Resolve single template
238
+ resolveTemplate('Hello, {{props.name}}!', context); // "Hello, World!"
239
+
240
+ // Check if string is a template
241
+ isTemplate('{{props.name}}'); // true
242
+ isTemplate('static text'); // false
243
+
244
+ // Resolve all bindings in an object
245
+ resolveBindings({
246
+ title: '{{props.name}}',
247
+ subtitle: 'Count: {{props.count}}',
248
+ }, context);
249
+ // { title: 'World', subtitle: 'Count: 42' }
250
+ ```
251
+
252
+ ## Slots
253
+
254
+ Components can define slots for content injection:
255
+
256
+ ```typescript
257
+ const elements = [
258
+ {
259
+ i: 'card',
260
+ type: 'div',
261
+ configuration: { className: 'card' },
262
+ children: [
263
+ {
264
+ i: 'header-slot',
265
+ type: 'div',
266
+ configuration: {
267
+ 'data-slot': 'header', // Slot placeholder
268
+ },
269
+ },
270
+ {
271
+ i: 'content-slot',
272
+ type: 'div',
273
+ configuration: {
274
+ 'data-slot': 'default',
275
+ },
276
+ },
277
+ ],
278
+ },
279
+ ];
280
+ ```
281
+
282
+ Framework wrappers handle slot content injection automatically.
283
+
284
+ ## TypeScript Support
285
+
286
+ Full TypeScript support with exported types:
287
+
288
+ ```typescript
289
+ import type {
290
+ LayoutElement,
291
+ BindingContext,
292
+ RenderResult,
293
+ ComponentData,
294
+ CacheStrategy,
295
+ RetryConfig,
296
+ } from '@servlyadmin/runtime-core';
297
+ ```
298
+
299
+ ## Browser Support
300
+
301
+ - Chrome 80+
302
+ - Firefox 75+
303
+ - Safari 13+
304
+ - Edge 80+
305
+
306
+ ## License
307
+
308
+ MIT
@@ -0,0 +1,15 @@
1
+ var __getOwnPropNames = Object.getOwnPropertyNames;
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
8
+ var __commonJS = (cb, mod) => function __require2() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+
12
+ export {
13
+ __require,
14
+ __commonJS
15
+ };