@servlyadmin/runtime-react 0.1.7 → 0.1.8
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/dist/index.cjs +53 -12
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +54 -13
- package/package.json +2 -3
package/dist/index.cjs
CHANGED
|
@@ -38,6 +38,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
38
38
|
|
|
39
39
|
// src/ServlyComponent.tsx
|
|
40
40
|
var import_react = require("react");
|
|
41
|
+
var import_react_dom = require("react-dom");
|
|
41
42
|
var import_runtime_core = require("@servlyadmin/runtime-core");
|
|
42
43
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
43
44
|
var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
@@ -92,10 +93,30 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ (0,
|
|
|
92
93
|
]
|
|
93
94
|
}
|
|
94
95
|
);
|
|
96
|
+
function useSlotElements(containerRef, isRendered) {
|
|
97
|
+
const [slotElements, setSlotElements] = (0, import_react.useState)({});
|
|
98
|
+
(0, import_react.useEffect)(() => {
|
|
99
|
+
if (!isRendered || !containerRef.current) {
|
|
100
|
+
setSlotElements({});
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const found = {};
|
|
104
|
+
const slots = containerRef.current.querySelectorAll("[data-slot]");
|
|
105
|
+
slots.forEach((el) => {
|
|
106
|
+
const slotName = el.getAttribute("data-slot");
|
|
107
|
+
if (slotName) {
|
|
108
|
+
found[slotName] = el;
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
setSlotElements(found);
|
|
112
|
+
}, [isRendered, containerRef]);
|
|
113
|
+
return slotElements;
|
|
114
|
+
}
|
|
95
115
|
function ServlyComponent({
|
|
96
116
|
id,
|
|
97
117
|
version = "latest",
|
|
98
118
|
props = {},
|
|
119
|
+
slots,
|
|
99
120
|
fallback,
|
|
100
121
|
onError,
|
|
101
122
|
onLoad,
|
|
@@ -104,22 +125,33 @@ function ServlyComponent({
|
|
|
104
125
|
showSkeleton = true,
|
|
105
126
|
cacheStrategy = "memory",
|
|
106
127
|
retryConfig,
|
|
107
|
-
eventHandlers
|
|
128
|
+
eventHandlers,
|
|
129
|
+
children
|
|
108
130
|
}) {
|
|
109
131
|
const containerRef = (0, import_react.useRef)(null);
|
|
110
132
|
const renderResultRef = (0, import_react.useRef)(null);
|
|
111
133
|
const abortControllerRef = (0, import_react.useRef)(null);
|
|
134
|
+
const [isRendered, setIsRendered] = (0, import_react.useState)(false);
|
|
112
135
|
const [state, setState] = (0, import_react.useState)({
|
|
113
136
|
loading: true,
|
|
114
137
|
error: null,
|
|
115
138
|
data: null
|
|
116
139
|
});
|
|
140
|
+
const slotElements = useSlotElements(containerRef, isRendered);
|
|
141
|
+
const effectiveSlots = (0, import_react.useMemo)(() => {
|
|
142
|
+
const result = { ...slots };
|
|
143
|
+
if (children && !result.default) {
|
|
144
|
+
result.default = children;
|
|
145
|
+
}
|
|
146
|
+
return result;
|
|
147
|
+
}, [slots, children]);
|
|
117
148
|
const loadComponent = (0, import_react.useCallback)(async () => {
|
|
118
149
|
if (abortControllerRef.current) {
|
|
119
150
|
abortControllerRef.current.abort();
|
|
120
151
|
}
|
|
121
152
|
abortControllerRef.current = new AbortController();
|
|
122
153
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
154
|
+
setIsRendered(false);
|
|
123
155
|
const fetchOptions = {
|
|
124
156
|
version,
|
|
125
157
|
cacheStrategy,
|
|
@@ -170,13 +202,15 @@ function ServlyComponent({
|
|
|
170
202
|
context,
|
|
171
203
|
eventHandlers
|
|
172
204
|
});
|
|
205
|
+
setIsRendered(true);
|
|
173
206
|
return () => {
|
|
174
207
|
if (renderResultRef.current) {
|
|
175
208
|
renderResultRef.current.destroy();
|
|
176
209
|
renderResultRef.current = null;
|
|
210
|
+
setIsRendered(false);
|
|
177
211
|
}
|
|
178
212
|
};
|
|
179
|
-
}, [state.data,
|
|
213
|
+
}, [state.data, eventHandlers]);
|
|
180
214
|
(0, import_react.useEffect)(() => {
|
|
181
215
|
if (!renderResultRef.current || !state.data) return;
|
|
182
216
|
const context = {
|
|
@@ -203,16 +237,23 @@ function ServlyComponent({
|
|
|
203
237
|
}
|
|
204
238
|
);
|
|
205
239
|
}
|
|
206
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
240
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
241
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
242
|
+
"div",
|
|
243
|
+
{
|
|
244
|
+
ref: containerRef,
|
|
245
|
+
className: `servly-component ${className || ""}`,
|
|
246
|
+
style,
|
|
247
|
+
"data-servly-id": id,
|
|
248
|
+
"data-servly-version": state.data?.version
|
|
249
|
+
}
|
|
250
|
+
),
|
|
251
|
+
Object.entries(effectiveSlots).map(([slotName, content]) => {
|
|
252
|
+
const slotEl = slotElements[slotName];
|
|
253
|
+
if (!slotEl || !content) return null;
|
|
254
|
+
return (0, import_react_dom.createPortal)(content, slotEl, `slot-${slotName}`);
|
|
255
|
+
})
|
|
256
|
+
] });
|
|
216
257
|
}
|
|
217
258
|
var ServlyComponent_default = ServlyComponent;
|
|
218
259
|
|
package/dist/index.d.cts
CHANGED
|
@@ -4,9 +4,13 @@ export { BindingContext, CacheStrategy, ComponentData, FetchOptions, LayoutEleme
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* ServlyComponent
|
|
7
|
-
* React wrapper for Servly runtime renderer
|
|
7
|
+
* React wrapper for Servly runtime renderer with slot support
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Slot content type - React nodes keyed by slot name
|
|
12
|
+
*/
|
|
13
|
+
type SlotContent = Record<string, React.ReactNode>;
|
|
10
14
|
/**
|
|
11
15
|
* Props for ServlyComponent
|
|
12
16
|
*/
|
|
@@ -17,6 +21,8 @@ interface ServlyComponentProps<P = Record<string, any>> {
|
|
|
17
21
|
version?: string;
|
|
18
22
|
/** Props to pass to the component */
|
|
19
23
|
props?: P;
|
|
24
|
+
/** Slot content - React nodes to portal into named slots */
|
|
25
|
+
slots?: SlotContent;
|
|
20
26
|
/** Fallback UI while loading or on error */
|
|
21
27
|
fallback?: React.ReactNode;
|
|
22
28
|
/** Error callback */
|
|
@@ -35,10 +41,12 @@ interface ServlyComponentProps<P = Record<string, any>> {
|
|
|
35
41
|
retryConfig?: Partial<RetryConfig>;
|
|
36
42
|
/** Event handlers keyed by element ID then event name */
|
|
37
43
|
eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
|
|
44
|
+
/** Children - rendered into default slot if no slots prop */
|
|
45
|
+
children?: React.ReactNode;
|
|
38
46
|
}
|
|
39
47
|
/**
|
|
40
|
-
* ServlyComponent - React wrapper for Servly runtime
|
|
48
|
+
* ServlyComponent - React wrapper for Servly runtime with slot support
|
|
41
49
|
*/
|
|
42
|
-
declare function ServlyComponent<P = Record<string, any>>({ id, version, props, fallback, onError, onLoad, className, style, showSkeleton, cacheStrategy, retryConfig, eventHandlers, }: ServlyComponentProps<P>): React.ReactElement | null;
|
|
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;
|
|
43
51
|
|
|
44
52
|
export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,13 @@ export { BindingContext, CacheStrategy, ComponentData, FetchOptions, LayoutEleme
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* ServlyComponent
|
|
7
|
-
* React wrapper for Servly runtime renderer
|
|
7
|
+
* React wrapper for Servly runtime renderer with slot support
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Slot content type - React nodes keyed by slot name
|
|
12
|
+
*/
|
|
13
|
+
type SlotContent = Record<string, React.ReactNode>;
|
|
10
14
|
/**
|
|
11
15
|
* Props for ServlyComponent
|
|
12
16
|
*/
|
|
@@ -17,6 +21,8 @@ interface ServlyComponentProps<P = Record<string, any>> {
|
|
|
17
21
|
version?: string;
|
|
18
22
|
/** Props to pass to the component */
|
|
19
23
|
props?: P;
|
|
24
|
+
/** Slot content - React nodes to portal into named slots */
|
|
25
|
+
slots?: SlotContent;
|
|
20
26
|
/** Fallback UI while loading or on error */
|
|
21
27
|
fallback?: React.ReactNode;
|
|
22
28
|
/** Error callback */
|
|
@@ -35,10 +41,12 @@ interface ServlyComponentProps<P = Record<string, any>> {
|
|
|
35
41
|
retryConfig?: Partial<RetryConfig>;
|
|
36
42
|
/** Event handlers keyed by element ID then event name */
|
|
37
43
|
eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
|
|
44
|
+
/** Children - rendered into default slot if no slots prop */
|
|
45
|
+
children?: React.ReactNode;
|
|
38
46
|
}
|
|
39
47
|
/**
|
|
40
|
-
* ServlyComponent - React wrapper for Servly runtime
|
|
48
|
+
* ServlyComponent - React wrapper for Servly runtime with slot support
|
|
41
49
|
*/
|
|
42
|
-
declare function ServlyComponent<P = Record<string, any>>({ id, version, props, fallback, onError, onLoad, className, style, showSkeleton, cacheStrategy, retryConfig, eventHandlers, }: ServlyComponentProps<P>): React.ReactElement | null;
|
|
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;
|
|
43
51
|
|
|
44
52
|
export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/ServlyComponent.tsx
|
|
2
|
-
import { useRef, useEffect, useState, useCallback } from "react";
|
|
2
|
+
import { useRef, useEffect, useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { createPortal } from "react-dom";
|
|
3
4
|
import {
|
|
4
5
|
render,
|
|
5
6
|
fetchComponent
|
|
@@ -57,10 +58,30 @@ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsx
|
|
|
57
58
|
]
|
|
58
59
|
}
|
|
59
60
|
);
|
|
61
|
+
function useSlotElements(containerRef, isRendered) {
|
|
62
|
+
const [slotElements, setSlotElements] = useState({});
|
|
63
|
+
useEffect(() => {
|
|
64
|
+
if (!isRendered || !containerRef.current) {
|
|
65
|
+
setSlotElements({});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const found = {};
|
|
69
|
+
const slots = containerRef.current.querySelectorAll("[data-slot]");
|
|
70
|
+
slots.forEach((el) => {
|
|
71
|
+
const slotName = el.getAttribute("data-slot");
|
|
72
|
+
if (slotName) {
|
|
73
|
+
found[slotName] = el;
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
setSlotElements(found);
|
|
77
|
+
}, [isRendered, containerRef]);
|
|
78
|
+
return slotElements;
|
|
79
|
+
}
|
|
60
80
|
function ServlyComponent({
|
|
61
81
|
id,
|
|
62
82
|
version = "latest",
|
|
63
83
|
props = {},
|
|
84
|
+
slots,
|
|
64
85
|
fallback,
|
|
65
86
|
onError,
|
|
66
87
|
onLoad,
|
|
@@ -69,22 +90,33 @@ function ServlyComponent({
|
|
|
69
90
|
showSkeleton = true,
|
|
70
91
|
cacheStrategy = "memory",
|
|
71
92
|
retryConfig,
|
|
72
|
-
eventHandlers
|
|
93
|
+
eventHandlers,
|
|
94
|
+
children
|
|
73
95
|
}) {
|
|
74
96
|
const containerRef = useRef(null);
|
|
75
97
|
const renderResultRef = useRef(null);
|
|
76
98
|
const abortControllerRef = useRef(null);
|
|
99
|
+
const [isRendered, setIsRendered] = useState(false);
|
|
77
100
|
const [state, setState] = useState({
|
|
78
101
|
loading: true,
|
|
79
102
|
error: null,
|
|
80
103
|
data: null
|
|
81
104
|
});
|
|
105
|
+
const slotElements = useSlotElements(containerRef, isRendered);
|
|
106
|
+
const effectiveSlots = useMemo(() => {
|
|
107
|
+
const result = { ...slots };
|
|
108
|
+
if (children && !result.default) {
|
|
109
|
+
result.default = children;
|
|
110
|
+
}
|
|
111
|
+
return result;
|
|
112
|
+
}, [slots, children]);
|
|
82
113
|
const loadComponent = useCallback(async () => {
|
|
83
114
|
if (abortControllerRef.current) {
|
|
84
115
|
abortControllerRef.current.abort();
|
|
85
116
|
}
|
|
86
117
|
abortControllerRef.current = new AbortController();
|
|
87
118
|
setState((prev) => ({ ...prev, loading: true, error: null }));
|
|
119
|
+
setIsRendered(false);
|
|
88
120
|
const fetchOptions = {
|
|
89
121
|
version,
|
|
90
122
|
cacheStrategy,
|
|
@@ -135,13 +167,15 @@ function ServlyComponent({
|
|
|
135
167
|
context,
|
|
136
168
|
eventHandlers
|
|
137
169
|
});
|
|
170
|
+
setIsRendered(true);
|
|
138
171
|
return () => {
|
|
139
172
|
if (renderResultRef.current) {
|
|
140
173
|
renderResultRef.current.destroy();
|
|
141
174
|
renderResultRef.current = null;
|
|
175
|
+
setIsRendered(false);
|
|
142
176
|
}
|
|
143
177
|
};
|
|
144
|
-
}, [state.data,
|
|
178
|
+
}, [state.data, eventHandlers]);
|
|
145
179
|
useEffect(() => {
|
|
146
180
|
if (!renderResultRef.current || !state.data) return;
|
|
147
181
|
const context = {
|
|
@@ -168,16 +202,23 @@ function ServlyComponent({
|
|
|
168
202
|
}
|
|
169
203
|
);
|
|
170
204
|
}
|
|
171
|
-
return /* @__PURE__ */
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
205
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
206
|
+
/* @__PURE__ */ jsx(
|
|
207
|
+
"div",
|
|
208
|
+
{
|
|
209
|
+
ref: containerRef,
|
|
210
|
+
className: `servly-component ${className || ""}`,
|
|
211
|
+
style,
|
|
212
|
+
"data-servly-id": id,
|
|
213
|
+
"data-servly-version": state.data?.version
|
|
214
|
+
}
|
|
215
|
+
),
|
|
216
|
+
Object.entries(effectiveSlots).map(([slotName, content]) => {
|
|
217
|
+
const slotEl = slotElements[slotName];
|
|
218
|
+
if (!slotEl || !content) return null;
|
|
219
|
+
return createPortal(content, slotEl, `slot-${slotName}`);
|
|
220
|
+
})
|
|
221
|
+
] });
|
|
181
222
|
}
|
|
182
223
|
var ServlyComponent_default = ServlyComponent;
|
|
183
224
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@servlyadmin/runtime-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.8",
|
|
4
4
|
"description": "React wrapper for Servly runtime renderer",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -34,8 +34,7 @@
|
|
|
34
34
|
"react-dom": ">=17.0.0"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@servlyadmin/runtime-core": "^0.1.
|
|
38
|
-
"@servlyadmin/runtime-react": "^0.1.6"
|
|
37
|
+
"@servlyadmin/runtime-core": "^0.1.8"
|
|
39
38
|
},
|
|
40
39
|
"devDependencies": {
|
|
41
40
|
"@types/react": "^18.2.0",
|