@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 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
- // 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(
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
- import {
227
- fetchComponent as fetchComponent2,
228
- prefetchComponents,
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
- ServlyComponent_default as default,
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
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __export = (target, all) => {
7
- for (var name in all)
8
- __defProp(target, name, { get: all[name], enumerable: true });
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__ */ (0, import_jsx_runtime.jsx)("style", { children: `
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__ */ (0, import_jsx_runtime.jsxs)(
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__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: 0, fontWeight: 500 }, children: "Failed to load component" }),
75
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { margin: "8px 0 0", fontSize: "14px", color: "#991b1b" }, children: error.message }),
76
- onRetry && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
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] = (0, import_react.useState)({});
98
- (0, import_react.useEffect)(() => {
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 = (0, import_react.useRef)(null);
132
- const renderResultRef = (0, import_react.useRef)(null);
133
- const abortControllerRef = (0, import_react.useRef)(null);
134
- const [isRendered, setIsRendered] = (0, import_react.useState)(false);
135
- const [state, setState] = (0, import_react.useState)({
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 = (0, import_react.useMemo)(() => {
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 = (0, import_react.useCallback)(async () => {
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 (0, import_runtime_core.fetchComponent)(id, fetchOptions);
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
- (0, import_react.useEffect)(() => {
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
- (0, import_react.useEffect)(() => {
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 = (0, import_runtime_core.render)({
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
- (0, import_react.useEffect)(() => {
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__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
225
- if (showSkeleton) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSkeleton, { className });
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__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
230
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
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__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
241
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
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 (0, import_react_dom.createPortal)(content, slotEl, `slot-${slotName}`);
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
- var import_runtime_core2 = require("@servlyadmin/runtime-core");
262
- // Annotate the CommonJS export names for ESM import in node:
263
- 0 && (module.exports = {
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
- fetchComponent,
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.8",
3
+ "version": "0.1.9",
4
4
  "description": "React wrapper for Servly runtime renderer",
5
5
  "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
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.js",
12
- "require": "./dist/index.cjs",
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.8"
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 };