@servlyadmin/runtime-react 0.1.8 → 0.1.9
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 +292 -0
- package/dist/index.js +84 -56
- package/dist/{index.cjs → index.mjs} +62 -79
- package/package.json +6 -8
- package/dist/index.d.cts +0 -52
- package/dist/index.d.ts +0 -52
package/README.md
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
# @servlyadmin/runtime-react
|
|
2
|
+
|
|
3
|
+
React wrapper for Servly runtime renderer. Render Servly components in your React applications with full support for props, slots, and event handling.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @servlyadmin/runtime-react @servlyadmin/runtime-core
|
|
9
|
+
# or
|
|
10
|
+
yarn add @servlyadmin/runtime-react @servlyadmin/runtime-core
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @servlyadmin/runtime-react @servlyadmin/runtime-core
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { ServlyComponent } from '@servlyadmin/runtime-react';
|
|
19
|
+
|
|
20
|
+
function App() {
|
|
21
|
+
return (
|
|
22
|
+
<ServlyComponent
|
|
23
|
+
id="my-component"
|
|
24
|
+
version="latest"
|
|
25
|
+
props={{ title: 'Hello World' }}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Props
|
|
32
|
+
|
|
33
|
+
| Prop | Type | Default | Description |
|
|
34
|
+
|------|------|---------|-------------|
|
|
35
|
+
| `id` | `string` | required | Component ID from the registry |
|
|
36
|
+
| `version` | `string` | `'latest'` | Version specifier |
|
|
37
|
+
| `props` | `object` | `{}` | Props to pass to the component |
|
|
38
|
+
| `slots` | `Record<string, ReactNode>` | - | Slot content |
|
|
39
|
+
| `fallback` | `ReactNode` | - | Loading/error fallback |
|
|
40
|
+
| `onError` | `(error: Error) => void` | - | Error callback |
|
|
41
|
+
| `onLoad` | `() => void` | - | Load complete callback |
|
|
42
|
+
| `className` | `string` | - | Wrapper class name |
|
|
43
|
+
| `style` | `CSSProperties` | - | Wrapper styles |
|
|
44
|
+
| `showSkeleton` | `boolean` | `true` | Show loading skeleton |
|
|
45
|
+
| `cacheStrategy` | `CacheStrategy` | `'memory'` | Cache strategy |
|
|
46
|
+
| `eventHandlers` | `object` | - | Event handlers by element ID |
|
|
47
|
+
| `children` | `ReactNode` | - | Default slot content |
|
|
48
|
+
|
|
49
|
+
## Usage Examples
|
|
50
|
+
|
|
51
|
+
### Basic Usage
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { ServlyComponent } from '@servlyadmin/runtime-react';
|
|
55
|
+
|
|
56
|
+
function MyPage() {
|
|
57
|
+
return (
|
|
58
|
+
<ServlyComponent
|
|
59
|
+
id="hero-section"
|
|
60
|
+
props={{
|
|
61
|
+
title: 'Welcome',
|
|
62
|
+
subtitle: 'Get started today',
|
|
63
|
+
}}
|
|
64
|
+
/>
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### With Slots
|
|
70
|
+
|
|
71
|
+
```tsx
|
|
72
|
+
function CardExample() {
|
|
73
|
+
return (
|
|
74
|
+
<ServlyComponent
|
|
75
|
+
id="card-component"
|
|
76
|
+
slots={{
|
|
77
|
+
header: <h2>Card Title</h2>,
|
|
78
|
+
footer: <button>Learn More</button>,
|
|
79
|
+
}}
|
|
80
|
+
>
|
|
81
|
+
{/* Children go to default slot */}
|
|
82
|
+
<p>This is the card content.</p>
|
|
83
|
+
</ServlyComponent>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### With Event Handlers
|
|
89
|
+
|
|
90
|
+
```tsx
|
|
91
|
+
function InteractiveExample() {
|
|
92
|
+
const [count, setCount] = useState(0);
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<ServlyComponent
|
|
96
|
+
id="counter-component"
|
|
97
|
+
props={{ count }}
|
|
98
|
+
eventHandlers={{
|
|
99
|
+
'increment-btn': {
|
|
100
|
+
click: () => setCount(c => c + 1),
|
|
101
|
+
},
|
|
102
|
+
'decrement-btn': {
|
|
103
|
+
click: () => setCount(c => c - 1),
|
|
104
|
+
},
|
|
105
|
+
}}
|
|
106
|
+
/>
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### Loading States
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
function WithLoadingState() {
|
|
115
|
+
return (
|
|
116
|
+
<ServlyComponent
|
|
117
|
+
id="data-component"
|
|
118
|
+
fallback={<div>Loading...</div>}
|
|
119
|
+
onLoad={() => console.log('Component loaded!')}
|
|
120
|
+
onError={(error) => console.error('Failed to load:', error)}
|
|
121
|
+
/>
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Custom Loading Skeleton
|
|
127
|
+
|
|
128
|
+
```tsx
|
|
129
|
+
function WithCustomSkeleton() {
|
|
130
|
+
return (
|
|
131
|
+
<ServlyComponent
|
|
132
|
+
id="profile-card"
|
|
133
|
+
showSkeleton={false}
|
|
134
|
+
fallback={
|
|
135
|
+
<div className="animate-pulse">
|
|
136
|
+
<div className="h-32 bg-gray-200 rounded" />
|
|
137
|
+
<div className="h-4 bg-gray-200 rounded mt-4 w-3/4" />
|
|
138
|
+
</div>
|
|
139
|
+
}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Version Pinning
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
function VersionedComponent() {
|
|
149
|
+
return (
|
|
150
|
+
<>
|
|
151
|
+
{/* Exact version */}
|
|
152
|
+
<ServlyComponent id="my-component" version="1.2.3" />
|
|
153
|
+
|
|
154
|
+
{/* Version range */}
|
|
155
|
+
<ServlyComponent id="my-component" version="^1.0.0" />
|
|
156
|
+
|
|
157
|
+
{/* Latest */}
|
|
158
|
+
<ServlyComponent id="my-component" version="latest" />
|
|
159
|
+
</>
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Cache Control
|
|
165
|
+
|
|
166
|
+
```tsx
|
|
167
|
+
function CacheExample() {
|
|
168
|
+
return (
|
|
169
|
+
<>
|
|
170
|
+
{/* Memory cache (default) */}
|
|
171
|
+
<ServlyComponent id="comp1" cacheStrategy="memory" />
|
|
172
|
+
|
|
173
|
+
{/* Persist to localStorage */}
|
|
174
|
+
<ServlyComponent id="comp2" cacheStrategy="localStorage" />
|
|
175
|
+
|
|
176
|
+
{/* No caching */}
|
|
177
|
+
<ServlyComponent id="comp3" cacheStrategy="none" />
|
|
178
|
+
</>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Dynamic Props
|
|
184
|
+
|
|
185
|
+
```tsx
|
|
186
|
+
function DynamicPropsExample() {
|
|
187
|
+
const [theme, setTheme] = useState('light');
|
|
188
|
+
const [user, setUser] = useState({ name: 'Guest' });
|
|
189
|
+
|
|
190
|
+
return (
|
|
191
|
+
<ServlyComponent
|
|
192
|
+
id="themed-component"
|
|
193
|
+
props={{
|
|
194
|
+
theme,
|
|
195
|
+
userName: user.name,
|
|
196
|
+
timestamp: Date.now(),
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
);
|
|
200
|
+
}
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### Error Boundary Integration
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
import { ErrorBoundary } from 'react-error-boundary';
|
|
207
|
+
|
|
208
|
+
function SafeComponent() {
|
|
209
|
+
return (
|
|
210
|
+
<ErrorBoundary fallback={<div>Something went wrong</div>}>
|
|
211
|
+
<ServlyComponent
|
|
212
|
+
id="risky-component"
|
|
213
|
+
onError={(error) => {
|
|
214
|
+
// Log to error tracking service
|
|
215
|
+
logError(error);
|
|
216
|
+
}}
|
|
217
|
+
/>
|
|
218
|
+
</ErrorBoundary>
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
## TypeScript
|
|
224
|
+
|
|
225
|
+
Full TypeScript support:
|
|
226
|
+
|
|
227
|
+
```tsx
|
|
228
|
+
import { ServlyComponent, type ServlyComponentProps } from '@servlyadmin/runtime-react';
|
|
229
|
+
|
|
230
|
+
interface MyComponentProps {
|
|
231
|
+
title: string;
|
|
232
|
+
count: number;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function TypedExample() {
|
|
236
|
+
return (
|
|
237
|
+
<ServlyComponent<MyComponentProps>
|
|
238
|
+
id="typed-component"
|
|
239
|
+
props={{
|
|
240
|
+
title: 'Hello',
|
|
241
|
+
count: 42,
|
|
242
|
+
}}
|
|
243
|
+
/>
|
|
244
|
+
);
|
|
245
|
+
}
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Server-Side Rendering
|
|
249
|
+
|
|
250
|
+
The component handles SSR gracefully by rendering the fallback on the server and hydrating on the client.
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
// Works with Next.js, Remix, etc.
|
|
254
|
+
function SSRPage() {
|
|
255
|
+
return (
|
|
256
|
+
<ServlyComponent
|
|
257
|
+
id="ssr-component"
|
|
258
|
+
fallback={<div>Loading component...</div>}
|
|
259
|
+
/>
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Performance Tips
|
|
265
|
+
|
|
266
|
+
1. **Use version pinning** in production to leverage caching
|
|
267
|
+
2. **Prefetch components** that will be needed soon
|
|
268
|
+
3. **Use `cacheStrategy="localStorage"`** for components that rarely change
|
|
269
|
+
4. **Memoize event handlers** to prevent unnecessary re-renders
|
|
270
|
+
|
|
271
|
+
```tsx
|
|
272
|
+
import { useMemo, useCallback } from 'react';
|
|
273
|
+
|
|
274
|
+
function OptimizedExample() {
|
|
275
|
+
const eventHandlers = useMemo(() => ({
|
|
276
|
+
'btn': {
|
|
277
|
+
click: () => console.log('clicked'),
|
|
278
|
+
},
|
|
279
|
+
}), []);
|
|
280
|
+
|
|
281
|
+
return (
|
|
282
|
+
<ServlyComponent
|
|
283
|
+
id="optimized"
|
|
284
|
+
eventHandlers={eventHandlers}
|
|
285
|
+
/>
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,46 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
var
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
|
+
var __export = (target, all) => {
|
|
6
|
+
for (var name in all)
|
|
7
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
|
+
};
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
|
+
|
|
19
|
+
// packages/runtime-react/src/index.ts
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
|
+
ServlyComponent: () => ServlyComponent,
|
|
23
|
+
clearAllCaches: () => import_runtime_core2.clearAllCaches,
|
|
24
|
+
compareVersions: () => import_runtime_core2.compareVersions,
|
|
25
|
+
default: () => ServlyComponent_default,
|
|
26
|
+
fetchComponent: () => import_runtime_core2.fetchComponent,
|
|
27
|
+
getRegistryUrl: () => import_runtime_core2.getRegistryUrl,
|
|
28
|
+
invalidateCache: () => import_runtime_core2.invalidateCache,
|
|
29
|
+
isComponentAvailable: () => import_runtime_core2.isComponentAvailable,
|
|
30
|
+
parseVersion: () => import_runtime_core2.parseVersion,
|
|
31
|
+
prefetchComponents: () => import_runtime_core2.prefetchComponents,
|
|
32
|
+
resolveVersion: () => import_runtime_core2.resolveVersion,
|
|
33
|
+
satisfiesVersion: () => import_runtime_core2.satisfiesVersion,
|
|
34
|
+
setRegistryUrl: () => import_runtime_core2.setRegistryUrl
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(index_exports);
|
|
37
|
+
|
|
38
|
+
// packages/runtime-react/src/ServlyComponent.tsx
|
|
39
|
+
var import_react = require("react");
|
|
40
|
+
var import_react_dom = require("react-dom");
|
|
41
|
+
var import_runtime_core = require("@servlyadmin/runtime-core");
|
|
42
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
43
|
+
var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
10
44
|
"div",
|
|
11
45
|
{
|
|
12
46
|
className: `servly-skeleton ${className || ""}`,
|
|
@@ -16,7 +50,7 @@ var LoadingSkeleton = ({ className }) => /* @__PURE__ */ jsx(
|
|
|
16
50
|
minHeight: "100px",
|
|
17
51
|
animation: "servly-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
|
|
18
52
|
},
|
|
19
|
-
children: /* @__PURE__ */ jsx("style", { children: `
|
|
53
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
|
|
20
54
|
@keyframes servly-pulse {
|
|
21
55
|
0%, 100% { opacity: 1; }
|
|
22
56
|
50% { opacity: 0.5; }
|
|
@@ -24,7 +58,7 @@ var LoadingSkeleton = ({ className }) => /* @__PURE__ */ jsx(
|
|
|
24
58
|
` })
|
|
25
59
|
}
|
|
26
60
|
);
|
|
27
|
-
var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsxs(
|
|
61
|
+
var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
28
62
|
"div",
|
|
29
63
|
{
|
|
30
64
|
className: `servly-error ${className || ""}`,
|
|
@@ -36,9 +70,9 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsx
|
|
|
36
70
|
...style
|
|
37
71
|
},
|
|
38
72
|
children: [
|
|
39
|
-
/* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 500 }, children: "Failed to load component" }),
|
|
40
|
-
/* @__PURE__ */ jsx("p", { style: { margin: "8px 0 0", fontSize: "14px", color: "#991b1b" }, children: error.message }),
|
|
41
|
-
onRetry && /* @__PURE__ */ jsx(
|
|
73
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontWeight: 500 }, children: "Failed to load component" }),
|
|
74
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: "8px 0 0", fontSize: "14px", color: "#991b1b" }, children: error.message }),
|
|
75
|
+
onRetry && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
42
76
|
"button",
|
|
43
77
|
{
|
|
44
78
|
onClick: onRetry,
|
|
@@ -59,8 +93,8 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsx
|
|
|
59
93
|
}
|
|
60
94
|
);
|
|
61
95
|
function useSlotElements(containerRef, isRendered) {
|
|
62
|
-
const [slotElements, setSlotElements] = useState({});
|
|
63
|
-
useEffect(() => {
|
|
96
|
+
const [slotElements, setSlotElements] = (0, import_react.useState)({});
|
|
97
|
+
(0, import_react.useEffect)(() => {
|
|
64
98
|
if (!isRendered || !containerRef.current) {
|
|
65
99
|
setSlotElements({});
|
|
66
100
|
return;
|
|
@@ -93,24 +127,24 @@ function ServlyComponent({
|
|
|
93
127
|
eventHandlers,
|
|
94
128
|
children
|
|
95
129
|
}) {
|
|
96
|
-
const containerRef = useRef(null);
|
|
97
|
-
const renderResultRef = useRef(null);
|
|
98
|
-
const abortControllerRef = useRef(null);
|
|
99
|
-
const [isRendered, setIsRendered] = useState(false);
|
|
100
|
-
const [state, setState] = useState({
|
|
130
|
+
const containerRef = (0, import_react.useRef)(null);
|
|
131
|
+
const renderResultRef = (0, import_react.useRef)(null);
|
|
132
|
+
const abortControllerRef = (0, import_react.useRef)(null);
|
|
133
|
+
const [isRendered, setIsRendered] = (0, import_react.useState)(false);
|
|
134
|
+
const [state, setState] = (0, import_react.useState)({
|
|
101
135
|
loading: true,
|
|
102
136
|
error: null,
|
|
103
137
|
data: null
|
|
104
138
|
});
|
|
105
139
|
const slotElements = useSlotElements(containerRef, isRendered);
|
|
106
|
-
const effectiveSlots = useMemo(() => {
|
|
140
|
+
const effectiveSlots = (0, import_react.useMemo)(() => {
|
|
107
141
|
const result = { ...slots };
|
|
108
142
|
if (children && !result.default) {
|
|
109
143
|
result.default = children;
|
|
110
144
|
}
|
|
111
145
|
return result;
|
|
112
146
|
}, [slots, children]);
|
|
113
|
-
const loadComponent = useCallback(async () => {
|
|
147
|
+
const loadComponent = (0, import_react.useCallback)(async () => {
|
|
114
148
|
if (abortControllerRef.current) {
|
|
115
149
|
abortControllerRef.current.abort();
|
|
116
150
|
}
|
|
@@ -124,11 +158,13 @@ function ServlyComponent({
|
|
|
124
158
|
signal: abortControllerRef.current.signal
|
|
125
159
|
};
|
|
126
160
|
try {
|
|
127
|
-
const result = await fetchComponent(id, fetchOptions);
|
|
161
|
+
const result = await (0, import_runtime_core.fetchComponent)(id, fetchOptions);
|
|
128
162
|
setState({
|
|
129
163
|
loading: false,
|
|
130
164
|
error: null,
|
|
131
|
-
data: result.data
|
|
165
|
+
data: result.data,
|
|
166
|
+
views: result.views,
|
|
167
|
+
registry: result.registry
|
|
132
168
|
});
|
|
133
169
|
onLoad?.();
|
|
134
170
|
} catch (error) {
|
|
@@ -137,12 +173,14 @@ function ServlyComponent({
|
|
|
137
173
|
setState({
|
|
138
174
|
loading: false,
|
|
139
175
|
error: err,
|
|
140
|
-
data: null
|
|
176
|
+
data: null,
|
|
177
|
+
views: void 0,
|
|
178
|
+
registry: void 0
|
|
141
179
|
});
|
|
142
180
|
onError?.(err);
|
|
143
181
|
}
|
|
144
182
|
}, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
|
|
145
|
-
useEffect(() => {
|
|
183
|
+
(0, import_react.useEffect)(() => {
|
|
146
184
|
loadComponent();
|
|
147
185
|
return () => {
|
|
148
186
|
if (abortControllerRef.current) {
|
|
@@ -150,7 +188,7 @@ function ServlyComponent({
|
|
|
150
188
|
}
|
|
151
189
|
};
|
|
152
190
|
}, [loadComponent]);
|
|
153
|
-
useEffect(() => {
|
|
191
|
+
(0, import_react.useEffect)(() => {
|
|
154
192
|
if (!state.data || !containerRef.current) return;
|
|
155
193
|
const context = {
|
|
156
194
|
props,
|
|
@@ -161,11 +199,13 @@ function ServlyComponent({
|
|
|
161
199
|
renderResultRef.current.update(context);
|
|
162
200
|
return;
|
|
163
201
|
}
|
|
164
|
-
renderResultRef.current = render({
|
|
202
|
+
renderResultRef.current = (0, import_runtime_core.render)({
|
|
165
203
|
container: containerRef.current,
|
|
166
204
|
elements: state.data.layout,
|
|
167
205
|
context,
|
|
168
|
-
eventHandlers
|
|
206
|
+
eventHandlers,
|
|
207
|
+
views: state.views,
|
|
208
|
+
componentRegistry: state.registry
|
|
169
209
|
});
|
|
170
210
|
setIsRendered(true);
|
|
171
211
|
return () => {
|
|
@@ -176,7 +216,7 @@ function ServlyComponent({
|
|
|
176
216
|
}
|
|
177
217
|
};
|
|
178
218
|
}, [state.data, eventHandlers]);
|
|
179
|
-
useEffect(() => {
|
|
219
|
+
(0, import_react.useEffect)(() => {
|
|
180
220
|
if (!renderResultRef.current || !state.data) return;
|
|
181
221
|
const context = {
|
|
182
222
|
props,
|
|
@@ -186,13 +226,13 @@ function ServlyComponent({
|
|
|
186
226
|
renderResultRef.current.update(context);
|
|
187
227
|
}, [props, state.data]);
|
|
188
228
|
if (state.loading) {
|
|
189
|
-
if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
190
|
-
if (showSkeleton) return /* @__PURE__ */ jsx(LoadingSkeleton, { className });
|
|
229
|
+
if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
|
|
230
|
+
if (showSkeleton) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSkeleton, { className });
|
|
191
231
|
return null;
|
|
192
232
|
}
|
|
193
233
|
if (state.error) {
|
|
194
|
-
if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
195
|
-
return /* @__PURE__ */ jsx(
|
|
234
|
+
if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
|
|
235
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
196
236
|
ErrorDisplay,
|
|
197
237
|
{
|
|
198
238
|
error: state.error,
|
|
@@ -202,8 +242,8 @@ function ServlyComponent({
|
|
|
202
242
|
}
|
|
203
243
|
);
|
|
204
244
|
}
|
|
205
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
206
|
-
/* @__PURE__ */ jsx(
|
|
245
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
246
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
207
247
|
"div",
|
|
208
248
|
{
|
|
209
249
|
ref: containerRef,
|
|
@@ -216,32 +256,20 @@ function ServlyComponent({
|
|
|
216
256
|
Object.entries(effectiveSlots).map(([slotName, content]) => {
|
|
217
257
|
const slotEl = slotElements[slotName];
|
|
218
258
|
if (!slotEl || !content) return null;
|
|
219
|
-
return createPortal(content, slotEl, `slot-${slotName}`);
|
|
259
|
+
return (0, import_react_dom.createPortal)(content, slotEl, `slot-${slotName}`);
|
|
220
260
|
})
|
|
221
261
|
] });
|
|
222
262
|
}
|
|
223
263
|
var ServlyComponent_default = ServlyComponent;
|
|
224
264
|
|
|
225
|
-
// src/index.ts
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
isComponentAvailable,
|
|
230
|
-
setRegistryUrl,
|
|
231
|
-
getRegistryUrl,
|
|
232
|
-
invalidateCache,
|
|
233
|
-
clearAllCaches,
|
|
234
|
-
parseVersion,
|
|
235
|
-
compareVersions,
|
|
236
|
-
satisfiesVersion,
|
|
237
|
-
resolveVersion
|
|
238
|
-
} from "@servlyadmin/runtime-core";
|
|
239
|
-
export {
|
|
265
|
+
// packages/runtime-react/src/index.ts
|
|
266
|
+
var import_runtime_core2 = require("@servlyadmin/runtime-core");
|
|
267
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
268
|
+
0 && (module.exports = {
|
|
240
269
|
ServlyComponent,
|
|
241
270
|
clearAllCaches,
|
|
242
271
|
compareVersions,
|
|
243
|
-
|
|
244
|
-
fetchComponent2 as fetchComponent,
|
|
272
|
+
fetchComponent,
|
|
245
273
|
getRegistryUrl,
|
|
246
274
|
invalidateCache,
|
|
247
275
|
isComponentAvailable,
|
|
@@ -250,4 +278,4 @@ export {
|
|
|
250
278
|
resolveVersion,
|
|
251
279
|
satisfiesVersion,
|
|
252
280
|
setRegistryUrl
|
|
253
|
-
};
|
|
281
|
+
});
|
|
@@ -1,47 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
ServlyComponent: () => ServlyComponent,
|
|
24
|
-
clearAllCaches: () => import_runtime_core2.clearAllCaches,
|
|
25
|
-
compareVersions: () => import_runtime_core2.compareVersions,
|
|
26
|
-
default: () => ServlyComponent_default,
|
|
27
|
-
fetchComponent: () => import_runtime_core2.fetchComponent,
|
|
28
|
-
getRegistryUrl: () => import_runtime_core2.getRegistryUrl,
|
|
29
|
-
invalidateCache: () => import_runtime_core2.invalidateCache,
|
|
30
|
-
isComponentAvailable: () => import_runtime_core2.isComponentAvailable,
|
|
31
|
-
parseVersion: () => import_runtime_core2.parseVersion,
|
|
32
|
-
prefetchComponents: () => import_runtime_core2.prefetchComponents,
|
|
33
|
-
resolveVersion: () => import_runtime_core2.resolveVersion,
|
|
34
|
-
satisfiesVersion: () => import_runtime_core2.satisfiesVersion,
|
|
35
|
-
setRegistryUrl: () => import_runtime_core2.setRegistryUrl
|
|
36
|
-
});
|
|
37
|
-
module.exports = __toCommonJS(index_exports);
|
|
38
|
-
|
|
39
|
-
// src/ServlyComponent.tsx
|
|
40
|
-
var import_react = require("react");
|
|
41
|
-
var import_react_dom = require("react-dom");
|
|
42
|
-
var import_runtime_core = require("@servlyadmin/runtime-core");
|
|
43
|
-
var import_jsx_runtime = require("react/jsx-runtime");
|
|
44
|
-
var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1
|
+
// packages/runtime-react/src/ServlyComponent.tsx
|
|
2
|
+
import { useRef, useEffect, useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
4
|
+
import {
|
|
5
|
+
render,
|
|
6
|
+
fetchComponent
|
|
7
|
+
} from "@servlyadmin/runtime-core";
|
|
8
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
+
var LoadingSkeleton = ({ className }) => /* @__PURE__ */ jsx(
|
|
45
10
|
"div",
|
|
46
11
|
{
|
|
47
12
|
className: `servly-skeleton ${className || ""}`,
|
|
@@ -51,7 +16,7 @@ var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.
|
|
|
51
16
|
minHeight: "100px",
|
|
52
17
|
animation: "servly-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
|
|
53
18
|
},
|
|
54
|
-
children: /* @__PURE__ */
|
|
19
|
+
children: /* @__PURE__ */ jsx("style", { children: `
|
|
55
20
|
@keyframes servly-pulse {
|
|
56
21
|
0%, 100% { opacity: 1; }
|
|
57
22
|
50% { opacity: 0.5; }
|
|
@@ -59,7 +24,7 @@ var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.
|
|
|
59
24
|
` })
|
|
60
25
|
}
|
|
61
26
|
);
|
|
62
|
-
var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */
|
|
27
|
+
var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsxs(
|
|
63
28
|
"div",
|
|
64
29
|
{
|
|
65
30
|
className: `servly-error ${className || ""}`,
|
|
@@ -71,9 +36,9 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ (0,
|
|
|
71
36
|
...style
|
|
72
37
|
},
|
|
73
38
|
children: [
|
|
74
|
-
/* @__PURE__ */
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
onRetry && /* @__PURE__ */
|
|
39
|
+
/* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 500 }, children: "Failed to load component" }),
|
|
40
|
+
/* @__PURE__ */ jsx("p", { style: { margin: "8px 0 0", fontSize: "14px", color: "#991b1b" }, children: error.message }),
|
|
41
|
+
onRetry && /* @__PURE__ */ jsx(
|
|
77
42
|
"button",
|
|
78
43
|
{
|
|
79
44
|
onClick: onRetry,
|
|
@@ -94,8 +59,8 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ (0,
|
|
|
94
59
|
}
|
|
95
60
|
);
|
|
96
61
|
function useSlotElements(containerRef, isRendered) {
|
|
97
|
-
const [slotElements, setSlotElements] =
|
|
98
|
-
|
|
62
|
+
const [slotElements, setSlotElements] = useState({});
|
|
63
|
+
useEffect(() => {
|
|
99
64
|
if (!isRendered || !containerRef.current) {
|
|
100
65
|
setSlotElements({});
|
|
101
66
|
return;
|
|
@@ -128,24 +93,24 @@ function ServlyComponent({
|
|
|
128
93
|
eventHandlers,
|
|
129
94
|
children
|
|
130
95
|
}) {
|
|
131
|
-
const containerRef =
|
|
132
|
-
const renderResultRef =
|
|
133
|
-
const abortControllerRef =
|
|
134
|
-
const [isRendered, setIsRendered] =
|
|
135
|
-
const [state, setState] =
|
|
96
|
+
const containerRef = useRef(null);
|
|
97
|
+
const renderResultRef = useRef(null);
|
|
98
|
+
const abortControllerRef = useRef(null);
|
|
99
|
+
const [isRendered, setIsRendered] = useState(false);
|
|
100
|
+
const [state, setState] = useState({
|
|
136
101
|
loading: true,
|
|
137
102
|
error: null,
|
|
138
103
|
data: null
|
|
139
104
|
});
|
|
140
105
|
const slotElements = useSlotElements(containerRef, isRendered);
|
|
141
|
-
const effectiveSlots =
|
|
106
|
+
const effectiveSlots = useMemo(() => {
|
|
142
107
|
const result = { ...slots };
|
|
143
108
|
if (children && !result.default) {
|
|
144
109
|
result.default = children;
|
|
145
110
|
}
|
|
146
111
|
return result;
|
|
147
112
|
}, [slots, children]);
|
|
148
|
-
const loadComponent =
|
|
113
|
+
const loadComponent = useCallback(async () => {
|
|
149
114
|
if (abortControllerRef.current) {
|
|
150
115
|
abortControllerRef.current.abort();
|
|
151
116
|
}
|
|
@@ -159,11 +124,13 @@ function ServlyComponent({
|
|
|
159
124
|
signal: abortControllerRef.current.signal
|
|
160
125
|
};
|
|
161
126
|
try {
|
|
162
|
-
const result = await
|
|
127
|
+
const result = await fetchComponent(id, fetchOptions);
|
|
163
128
|
setState({
|
|
164
129
|
loading: false,
|
|
165
130
|
error: null,
|
|
166
|
-
data: result.data
|
|
131
|
+
data: result.data,
|
|
132
|
+
views: result.views,
|
|
133
|
+
registry: result.registry
|
|
167
134
|
});
|
|
168
135
|
onLoad?.();
|
|
169
136
|
} catch (error) {
|
|
@@ -172,12 +139,14 @@ function ServlyComponent({
|
|
|
172
139
|
setState({
|
|
173
140
|
loading: false,
|
|
174
141
|
error: err,
|
|
175
|
-
data: null
|
|
142
|
+
data: null,
|
|
143
|
+
views: void 0,
|
|
144
|
+
registry: void 0
|
|
176
145
|
});
|
|
177
146
|
onError?.(err);
|
|
178
147
|
}
|
|
179
148
|
}, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
|
|
180
|
-
|
|
149
|
+
useEffect(() => {
|
|
181
150
|
loadComponent();
|
|
182
151
|
return () => {
|
|
183
152
|
if (abortControllerRef.current) {
|
|
@@ -185,7 +154,7 @@ function ServlyComponent({
|
|
|
185
154
|
}
|
|
186
155
|
};
|
|
187
156
|
}, [loadComponent]);
|
|
188
|
-
|
|
157
|
+
useEffect(() => {
|
|
189
158
|
if (!state.data || !containerRef.current) return;
|
|
190
159
|
const context = {
|
|
191
160
|
props,
|
|
@@ -196,11 +165,13 @@ function ServlyComponent({
|
|
|
196
165
|
renderResultRef.current.update(context);
|
|
197
166
|
return;
|
|
198
167
|
}
|
|
199
|
-
renderResultRef.current =
|
|
168
|
+
renderResultRef.current = render({
|
|
200
169
|
container: containerRef.current,
|
|
201
170
|
elements: state.data.layout,
|
|
202
171
|
context,
|
|
203
|
-
eventHandlers
|
|
172
|
+
eventHandlers,
|
|
173
|
+
views: state.views,
|
|
174
|
+
componentRegistry: state.registry
|
|
204
175
|
});
|
|
205
176
|
setIsRendered(true);
|
|
206
177
|
return () => {
|
|
@@ -211,7 +182,7 @@ function ServlyComponent({
|
|
|
211
182
|
}
|
|
212
183
|
};
|
|
213
184
|
}, [state.data, eventHandlers]);
|
|
214
|
-
|
|
185
|
+
useEffect(() => {
|
|
215
186
|
if (!renderResultRef.current || !state.data) return;
|
|
216
187
|
const context = {
|
|
217
188
|
props,
|
|
@@ -221,13 +192,13 @@ function ServlyComponent({
|
|
|
221
192
|
renderResultRef.current.update(context);
|
|
222
193
|
}, [props, state.data]);
|
|
223
194
|
if (state.loading) {
|
|
224
|
-
if (fallback) return /* @__PURE__ */
|
|
225
|
-
if (showSkeleton) return /* @__PURE__ */
|
|
195
|
+
if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
196
|
+
if (showSkeleton) return /* @__PURE__ */ jsx(LoadingSkeleton, { className });
|
|
226
197
|
return null;
|
|
227
198
|
}
|
|
228
199
|
if (state.error) {
|
|
229
|
-
if (fallback) return /* @__PURE__ */
|
|
230
|
-
return /* @__PURE__ */
|
|
200
|
+
if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
|
|
201
|
+
return /* @__PURE__ */ jsx(
|
|
231
202
|
ErrorDisplay,
|
|
232
203
|
{
|
|
233
204
|
error: state.error,
|
|
@@ -237,8 +208,8 @@ function ServlyComponent({
|
|
|
237
208
|
}
|
|
238
209
|
);
|
|
239
210
|
}
|
|
240
|
-
return /* @__PURE__ */
|
|
241
|
-
/* @__PURE__ */
|
|
211
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
212
|
+
/* @__PURE__ */ jsx(
|
|
242
213
|
"div",
|
|
243
214
|
{
|
|
244
215
|
ref: containerRef,
|
|
@@ -251,20 +222,32 @@ function ServlyComponent({
|
|
|
251
222
|
Object.entries(effectiveSlots).map(([slotName, content]) => {
|
|
252
223
|
const slotEl = slotElements[slotName];
|
|
253
224
|
if (!slotEl || !content) return null;
|
|
254
|
-
return
|
|
225
|
+
return createPortal(content, slotEl, `slot-${slotName}`);
|
|
255
226
|
})
|
|
256
227
|
] });
|
|
257
228
|
}
|
|
258
229
|
var ServlyComponent_default = ServlyComponent;
|
|
259
230
|
|
|
260
|
-
// src/index.ts
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
231
|
+
// packages/runtime-react/src/index.ts
|
|
232
|
+
import {
|
|
233
|
+
fetchComponent as fetchComponent2,
|
|
234
|
+
prefetchComponents,
|
|
235
|
+
isComponentAvailable,
|
|
236
|
+
setRegistryUrl,
|
|
237
|
+
getRegistryUrl,
|
|
238
|
+
invalidateCache,
|
|
239
|
+
clearAllCaches,
|
|
240
|
+
parseVersion,
|
|
241
|
+
compareVersions,
|
|
242
|
+
satisfiesVersion,
|
|
243
|
+
resolveVersion
|
|
244
|
+
} from "@servlyadmin/runtime-core";
|
|
245
|
+
export {
|
|
264
246
|
ServlyComponent,
|
|
265
247
|
clearAllCaches,
|
|
266
248
|
compareVersions,
|
|
267
|
-
|
|
249
|
+
ServlyComponent_default as default,
|
|
250
|
+
fetchComponent2 as fetchComponent,
|
|
268
251
|
getRegistryUrl,
|
|
269
252
|
invalidateCache,
|
|
270
253
|
isComponentAvailable,
|
|
@@ -273,4 +256,4 @@ var import_runtime_core2 = require("@servlyadmin/runtime-core");
|
|
|
273
256
|
resolveVersion,
|
|
274
257
|
satisfiesVersion,
|
|
275
258
|
setRegistryUrl
|
|
276
|
-
}
|
|
259
|
+
};
|
package/package.json
CHANGED
|
@@ -1,16 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servlyadmin/runtime-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "React wrapper for Servly runtime renderer",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.
|
|
7
|
-
"module": "./dist/index.
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"module": "./dist/index.mjs",
|
|
9
8
|
"exports": {
|
|
10
9
|
".": {
|
|
11
|
-
"import": "./dist/index.
|
|
12
|
-
"require": "./dist/index.
|
|
13
|
-
"types": "./dist/index.d.ts"
|
|
10
|
+
"import": "./dist/index.mjs",
|
|
11
|
+
"require": "./dist/index.js"
|
|
14
12
|
}
|
|
15
13
|
},
|
|
16
14
|
"files": [
|
|
@@ -34,7 +32,7 @@
|
|
|
34
32
|
"react-dom": ">=17.0.0"
|
|
35
33
|
},
|
|
36
34
|
"dependencies": {
|
|
37
|
-
"@servlyadmin/runtime-core": "^0.1.
|
|
35
|
+
"@servlyadmin/runtime-core": "^0.1.9"
|
|
38
36
|
},
|
|
39
37
|
"devDependencies": {
|
|
40
38
|
"@types/react": "^18.2.0",
|
package/dist/index.d.cts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { CacheStrategy, RetryConfig } from '@servlyadmin/runtime-core';
|
|
3
|
-
export { BindingContext, CacheStrategy, ComponentData, FetchOptions, LayoutElement, PropDefinition, RetryConfig, clearAllCaches, compareVersions, fetchComponent, getRegistryUrl, invalidateCache, isComponentAvailable, parseVersion, prefetchComponents, resolveVersion, satisfiesVersion, setRegistryUrl } from '@servlyadmin/runtime-core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ServlyComponent
|
|
7
|
-
* React wrapper for Servly runtime renderer with slot support
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Slot content type - React nodes keyed by slot name
|
|
12
|
-
*/
|
|
13
|
-
type SlotContent = Record<string, React.ReactNode>;
|
|
14
|
-
/**
|
|
15
|
-
* Props for ServlyComponent
|
|
16
|
-
*/
|
|
17
|
-
interface ServlyComponentProps<P = Record<string, any>> {
|
|
18
|
-
/** Component ID from the registry */
|
|
19
|
-
id: string;
|
|
20
|
-
/** Version specifier (exact, range, or "latest") */
|
|
21
|
-
version?: string;
|
|
22
|
-
/** Props to pass to the component */
|
|
23
|
-
props?: P;
|
|
24
|
-
/** Slot content - React nodes to portal into named slots */
|
|
25
|
-
slots?: SlotContent;
|
|
26
|
-
/** Fallback UI while loading or on error */
|
|
27
|
-
fallback?: React.ReactNode;
|
|
28
|
-
/** Error callback */
|
|
29
|
-
onError?: (error: Error) => void;
|
|
30
|
-
/** Load complete callback */
|
|
31
|
-
onLoad?: () => void;
|
|
32
|
-
/** Custom className for wrapper */
|
|
33
|
-
className?: string;
|
|
34
|
-
/** Custom styles for wrapper */
|
|
35
|
-
style?: React.CSSProperties;
|
|
36
|
-
/** Show loading skeleton */
|
|
37
|
-
showSkeleton?: boolean;
|
|
38
|
-
/** Cache strategy */
|
|
39
|
-
cacheStrategy?: CacheStrategy;
|
|
40
|
-
/** Retry configuration */
|
|
41
|
-
retryConfig?: Partial<RetryConfig>;
|
|
42
|
-
/** Event handlers keyed by element ID then event name */
|
|
43
|
-
eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
|
|
44
|
-
/** Children - rendered into default slot if no slots prop */
|
|
45
|
-
children?: React.ReactNode;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* ServlyComponent - React wrapper for Servly runtime with slot support
|
|
49
|
-
*/
|
|
50
|
-
declare function ServlyComponent<P = Record<string, any>>({ id, version, props, slots, fallback, onError, onLoad, className, style, showSkeleton, cacheStrategy, retryConfig, eventHandlers, children, }: ServlyComponentProps<P>): React.ReactElement | null;
|
|
51
|
-
|
|
52
|
-
export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
|
package/dist/index.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { CacheStrategy, RetryConfig } from '@servlyadmin/runtime-core';
|
|
3
|
-
export { BindingContext, CacheStrategy, ComponentData, FetchOptions, LayoutElement, PropDefinition, RetryConfig, clearAllCaches, compareVersions, fetchComponent, getRegistryUrl, invalidateCache, isComponentAvailable, parseVersion, prefetchComponents, resolveVersion, satisfiesVersion, setRegistryUrl } from '@servlyadmin/runtime-core';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* ServlyComponent
|
|
7
|
-
* React wrapper for Servly runtime renderer with slot support
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* Slot content type - React nodes keyed by slot name
|
|
12
|
-
*/
|
|
13
|
-
type SlotContent = Record<string, React.ReactNode>;
|
|
14
|
-
/**
|
|
15
|
-
* Props for ServlyComponent
|
|
16
|
-
*/
|
|
17
|
-
interface ServlyComponentProps<P = Record<string, any>> {
|
|
18
|
-
/** Component ID from the registry */
|
|
19
|
-
id: string;
|
|
20
|
-
/** Version specifier (exact, range, or "latest") */
|
|
21
|
-
version?: string;
|
|
22
|
-
/** Props to pass to the component */
|
|
23
|
-
props?: P;
|
|
24
|
-
/** Slot content - React nodes to portal into named slots */
|
|
25
|
-
slots?: SlotContent;
|
|
26
|
-
/** Fallback UI while loading or on error */
|
|
27
|
-
fallback?: React.ReactNode;
|
|
28
|
-
/** Error callback */
|
|
29
|
-
onError?: (error: Error) => void;
|
|
30
|
-
/** Load complete callback */
|
|
31
|
-
onLoad?: () => void;
|
|
32
|
-
/** Custom className for wrapper */
|
|
33
|
-
className?: string;
|
|
34
|
-
/** Custom styles for wrapper */
|
|
35
|
-
style?: React.CSSProperties;
|
|
36
|
-
/** Show loading skeleton */
|
|
37
|
-
showSkeleton?: boolean;
|
|
38
|
-
/** Cache strategy */
|
|
39
|
-
cacheStrategy?: CacheStrategy;
|
|
40
|
-
/** Retry configuration */
|
|
41
|
-
retryConfig?: Partial<RetryConfig>;
|
|
42
|
-
/** Event handlers keyed by element ID then event name */
|
|
43
|
-
eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
|
|
44
|
-
/** Children - rendered into default slot if no slots prop */
|
|
45
|
-
children?: React.ReactNode;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* ServlyComponent - React wrapper for Servly runtime with slot support
|
|
49
|
-
*/
|
|
50
|
-
declare function ServlyComponent<P = Record<string, any>>({ id, version, props, slots, fallback, onError, onLoad, className, style, showSkeleton, cacheStrategy, retryConfig, eventHandlers, children, }: ServlyComponentProps<P>): React.ReactElement | null;
|
|
51
|
-
|
|
52
|
-
export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
|