@servlyadmin/runtime-react 0.1.0

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 ADDED
@@ -0,0 +1,235 @@
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_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)(
44
+ "div",
45
+ {
46
+ className: `servly-skeleton ${className || ""}`,
47
+ style: {
48
+ backgroundColor: "#f3f4f6",
49
+ borderRadius: "8px",
50
+ minHeight: "100px",
51
+ animation: "servly-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
52
+ },
53
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { children: `
54
+ @keyframes servly-pulse {
55
+ 0%, 100% { opacity: 1; }
56
+ 50% { opacity: 0.5; }
57
+ }
58
+ ` })
59
+ }
60
+ );
61
+ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
62
+ "div",
63
+ {
64
+ className: `servly-error ${className || ""}`,
65
+ style: {
66
+ padding: "16px",
67
+ color: "#ef4444",
68
+ backgroundColor: "#fef2f2",
69
+ borderRadius: "8px",
70
+ ...style
71
+ },
72
+ children: [
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)(
76
+ "button",
77
+ {
78
+ onClick: onRetry,
79
+ style: {
80
+ marginTop: "12px",
81
+ padding: "8px 16px",
82
+ backgroundColor: "#ef4444",
83
+ color: "white",
84
+ border: "none",
85
+ borderRadius: "4px",
86
+ cursor: "pointer",
87
+ fontSize: "14px"
88
+ },
89
+ children: "Retry"
90
+ }
91
+ )
92
+ ]
93
+ }
94
+ );
95
+ function ServlyComponent({
96
+ id,
97
+ version = "latest",
98
+ props = {},
99
+ fallback,
100
+ onError,
101
+ onLoad,
102
+ className,
103
+ style,
104
+ showSkeleton = true,
105
+ cacheStrategy = "memory",
106
+ retryConfig,
107
+ eventHandlers
108
+ }) {
109
+ const containerRef = (0, import_react.useRef)(null);
110
+ const renderResultRef = (0, import_react.useRef)(null);
111
+ const abortControllerRef = (0, import_react.useRef)(null);
112
+ const [state, setState] = (0, import_react.useState)({
113
+ loading: true,
114
+ error: null,
115
+ data: null
116
+ });
117
+ const loadComponent = (0, import_react.useCallback)(async () => {
118
+ if (abortControllerRef.current) {
119
+ abortControllerRef.current.abort();
120
+ }
121
+ abortControllerRef.current = new AbortController();
122
+ setState((prev) => ({ ...prev, loading: true, error: null }));
123
+ const fetchOptions = {
124
+ version,
125
+ cacheStrategy,
126
+ retryConfig,
127
+ signal: abortControllerRef.current.signal
128
+ };
129
+ try {
130
+ const result = await (0, import_runtime_core.fetchComponent)(id, fetchOptions);
131
+ setState({
132
+ loading: false,
133
+ error: null,
134
+ data: result.data
135
+ });
136
+ onLoad?.();
137
+ } catch (error) {
138
+ const err = error instanceof Error ? error : new Error(String(error));
139
+ if (err.message === "Fetch aborted") return;
140
+ setState({
141
+ loading: false,
142
+ error: err,
143
+ data: null
144
+ });
145
+ onError?.(err);
146
+ }
147
+ }, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
148
+ (0, import_react.useEffect)(() => {
149
+ loadComponent();
150
+ return () => {
151
+ if (abortControllerRef.current) {
152
+ abortControllerRef.current.abort();
153
+ }
154
+ };
155
+ }, [loadComponent]);
156
+ (0, import_react.useEffect)(() => {
157
+ if (!state.data || !containerRef.current) return;
158
+ const context = {
159
+ props,
160
+ state: {},
161
+ context: {}
162
+ };
163
+ if (renderResultRef.current) {
164
+ renderResultRef.current.update(context);
165
+ return;
166
+ }
167
+ renderResultRef.current = (0, import_runtime_core.render)({
168
+ container: containerRef.current,
169
+ elements: state.data.layout,
170
+ context,
171
+ eventHandlers
172
+ });
173
+ return () => {
174
+ if (renderResultRef.current) {
175
+ renderResultRef.current.destroy();
176
+ renderResultRef.current = null;
177
+ }
178
+ };
179
+ }, [state.data, props, eventHandlers]);
180
+ (0, import_react.useEffect)(() => {
181
+ if (!renderResultRef.current || !state.data) return;
182
+ const context = {
183
+ props,
184
+ state: {},
185
+ context: {}
186
+ };
187
+ renderResultRef.current.update(context);
188
+ }, [props, state.data]);
189
+ if (state.loading) {
190
+ if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
191
+ if (showSkeleton) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSkeleton, { className });
192
+ return null;
193
+ }
194
+ if (state.error) {
195
+ if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
196
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
197
+ ErrorDisplay,
198
+ {
199
+ error: state.error,
200
+ onRetry: loadComponent,
201
+ className,
202
+ style
203
+ }
204
+ );
205
+ }
206
+ return /* @__PURE__ */ (0, import_jsx_runtime.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
+ }
217
+ var ServlyComponent_default = ServlyComponent;
218
+
219
+ // src/index.ts
220
+ var import_runtime_core2 = require("@servlyadmin/runtime-core");
221
+ // Annotate the CommonJS export names for ESM import in node:
222
+ 0 && (module.exports = {
223
+ ServlyComponent,
224
+ clearAllCaches,
225
+ compareVersions,
226
+ fetchComponent,
227
+ getRegistryUrl,
228
+ invalidateCache,
229
+ isComponentAvailable,
230
+ parseVersion,
231
+ prefetchComponents,
232
+ resolveVersion,
233
+ satisfiesVersion,
234
+ setRegistryUrl
235
+ });
@@ -0,0 +1,44 @@
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
8
+ */
9
+
10
+ /**
11
+ * Props for ServlyComponent
12
+ */
13
+ interface ServlyComponentProps<P = Record<string, any>> {
14
+ /** Component ID from the registry */
15
+ id: string;
16
+ /** Version specifier (exact, range, or "latest") */
17
+ version?: string;
18
+ /** Props to pass to the component */
19
+ props?: P;
20
+ /** Fallback UI while loading or on error */
21
+ fallback?: React.ReactNode;
22
+ /** Error callback */
23
+ onError?: (error: Error) => void;
24
+ /** Load complete callback */
25
+ onLoad?: () => void;
26
+ /** Custom className for wrapper */
27
+ className?: string;
28
+ /** Custom styles for wrapper */
29
+ style?: React.CSSProperties;
30
+ /** Show loading skeleton */
31
+ showSkeleton?: boolean;
32
+ /** Cache strategy */
33
+ cacheStrategy?: CacheStrategy;
34
+ /** Retry configuration */
35
+ retryConfig?: Partial<RetryConfig>;
36
+ /** Event handlers keyed by element ID then event name */
37
+ eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
38
+ }
39
+ /**
40
+ * ServlyComponent - React wrapper for Servly runtime
41
+ */
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;
43
+
44
+ export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
@@ -0,0 +1,44 @@
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
8
+ */
9
+
10
+ /**
11
+ * Props for ServlyComponent
12
+ */
13
+ interface ServlyComponentProps<P = Record<string, any>> {
14
+ /** Component ID from the registry */
15
+ id: string;
16
+ /** Version specifier (exact, range, or "latest") */
17
+ version?: string;
18
+ /** Props to pass to the component */
19
+ props?: P;
20
+ /** Fallback UI while loading or on error */
21
+ fallback?: React.ReactNode;
22
+ /** Error callback */
23
+ onError?: (error: Error) => void;
24
+ /** Load complete callback */
25
+ onLoad?: () => void;
26
+ /** Custom className for wrapper */
27
+ className?: string;
28
+ /** Custom styles for wrapper */
29
+ style?: React.CSSProperties;
30
+ /** Show loading skeleton */
31
+ showSkeleton?: boolean;
32
+ /** Cache strategy */
33
+ cacheStrategy?: CacheStrategy;
34
+ /** Retry configuration */
35
+ retryConfig?: Partial<RetryConfig>;
36
+ /** Event handlers keyed by element ID then event name */
37
+ eventHandlers?: Record<string, Record<string, (e: Event) => void>>;
38
+ }
39
+ /**
40
+ * ServlyComponent - React wrapper for Servly runtime
41
+ */
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;
43
+
44
+ export { ServlyComponent, type ServlyComponentProps, ServlyComponent as default };
package/dist/index.js ADDED
@@ -0,0 +1,212 @@
1
+ // src/ServlyComponent.tsx
2
+ import { useRef, useEffect, useState, useCallback } from "react";
3
+ import {
4
+ render,
5
+ fetchComponent
6
+ } from "@servlyadmin/runtime-core";
7
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
+ var LoadingSkeleton = ({ className }) => /* @__PURE__ */ jsx(
9
+ "div",
10
+ {
11
+ className: `servly-skeleton ${className || ""}`,
12
+ style: {
13
+ backgroundColor: "#f3f4f6",
14
+ borderRadius: "8px",
15
+ minHeight: "100px",
16
+ animation: "servly-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite"
17
+ },
18
+ children: /* @__PURE__ */ jsx("style", { children: `
19
+ @keyframes servly-pulse {
20
+ 0%, 100% { opacity: 1; }
21
+ 50% { opacity: 0.5; }
22
+ }
23
+ ` })
24
+ }
25
+ );
26
+ var ErrorDisplay = ({ error, onRetry, className, style }) => /* @__PURE__ */ jsxs(
27
+ "div",
28
+ {
29
+ className: `servly-error ${className || ""}`,
30
+ style: {
31
+ padding: "16px",
32
+ color: "#ef4444",
33
+ backgroundColor: "#fef2f2",
34
+ borderRadius: "8px",
35
+ ...style
36
+ },
37
+ children: [
38
+ /* @__PURE__ */ jsx("p", { style: { margin: 0, fontWeight: 500 }, children: "Failed to load component" }),
39
+ /* @__PURE__ */ jsx("p", { style: { margin: "8px 0 0", fontSize: "14px", color: "#991b1b" }, children: error.message }),
40
+ onRetry && /* @__PURE__ */ jsx(
41
+ "button",
42
+ {
43
+ onClick: onRetry,
44
+ style: {
45
+ marginTop: "12px",
46
+ padding: "8px 16px",
47
+ backgroundColor: "#ef4444",
48
+ color: "white",
49
+ border: "none",
50
+ borderRadius: "4px",
51
+ cursor: "pointer",
52
+ fontSize: "14px"
53
+ },
54
+ children: "Retry"
55
+ }
56
+ )
57
+ ]
58
+ }
59
+ );
60
+ function ServlyComponent({
61
+ id,
62
+ version = "latest",
63
+ props = {},
64
+ fallback,
65
+ onError,
66
+ onLoad,
67
+ className,
68
+ style,
69
+ showSkeleton = true,
70
+ cacheStrategy = "memory",
71
+ retryConfig,
72
+ eventHandlers
73
+ }) {
74
+ const containerRef = useRef(null);
75
+ const renderResultRef = useRef(null);
76
+ const abortControllerRef = useRef(null);
77
+ const [state, setState] = useState({
78
+ loading: true,
79
+ error: null,
80
+ data: null
81
+ });
82
+ const loadComponent = useCallback(async () => {
83
+ if (abortControllerRef.current) {
84
+ abortControllerRef.current.abort();
85
+ }
86
+ abortControllerRef.current = new AbortController();
87
+ setState((prev) => ({ ...prev, loading: true, error: null }));
88
+ const fetchOptions = {
89
+ version,
90
+ cacheStrategy,
91
+ retryConfig,
92
+ signal: abortControllerRef.current.signal
93
+ };
94
+ try {
95
+ const result = await fetchComponent(id, fetchOptions);
96
+ setState({
97
+ loading: false,
98
+ error: null,
99
+ data: result.data
100
+ });
101
+ onLoad?.();
102
+ } catch (error) {
103
+ const err = error instanceof Error ? error : new Error(String(error));
104
+ if (err.message === "Fetch aborted") return;
105
+ setState({
106
+ loading: false,
107
+ error: err,
108
+ data: null
109
+ });
110
+ onError?.(err);
111
+ }
112
+ }, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
113
+ useEffect(() => {
114
+ loadComponent();
115
+ return () => {
116
+ if (abortControllerRef.current) {
117
+ abortControllerRef.current.abort();
118
+ }
119
+ };
120
+ }, [loadComponent]);
121
+ useEffect(() => {
122
+ if (!state.data || !containerRef.current) return;
123
+ const context = {
124
+ props,
125
+ state: {},
126
+ context: {}
127
+ };
128
+ if (renderResultRef.current) {
129
+ renderResultRef.current.update(context);
130
+ return;
131
+ }
132
+ renderResultRef.current = render({
133
+ container: containerRef.current,
134
+ elements: state.data.layout,
135
+ context,
136
+ eventHandlers
137
+ });
138
+ return () => {
139
+ if (renderResultRef.current) {
140
+ renderResultRef.current.destroy();
141
+ renderResultRef.current = null;
142
+ }
143
+ };
144
+ }, [state.data, props, eventHandlers]);
145
+ useEffect(() => {
146
+ if (!renderResultRef.current || !state.data) return;
147
+ const context = {
148
+ props,
149
+ state: {},
150
+ context: {}
151
+ };
152
+ renderResultRef.current.update(context);
153
+ }, [props, state.data]);
154
+ if (state.loading) {
155
+ if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
156
+ if (showSkeleton) return /* @__PURE__ */ jsx(LoadingSkeleton, { className });
157
+ return null;
158
+ }
159
+ if (state.error) {
160
+ if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
161
+ return /* @__PURE__ */ jsx(
162
+ ErrorDisplay,
163
+ {
164
+ error: state.error,
165
+ onRetry: loadComponent,
166
+ className,
167
+ style
168
+ }
169
+ );
170
+ }
171
+ return /* @__PURE__ */ jsx(
172
+ "div",
173
+ {
174
+ ref: containerRef,
175
+ className: `servly-component ${className || ""}`,
176
+ style,
177
+ "data-servly-id": id,
178
+ "data-servly-version": state.data?.version
179
+ }
180
+ );
181
+ }
182
+ var ServlyComponent_default = ServlyComponent;
183
+
184
+ // src/index.ts
185
+ import {
186
+ fetchComponent as fetchComponent2,
187
+ prefetchComponents,
188
+ isComponentAvailable,
189
+ setRegistryUrl,
190
+ getRegistryUrl,
191
+ invalidateCache,
192
+ clearAllCaches,
193
+ parseVersion,
194
+ compareVersions,
195
+ satisfiesVersion,
196
+ resolveVersion
197
+ } from "@servlyadmin/runtime-core";
198
+ export {
199
+ ServlyComponent,
200
+ clearAllCaches,
201
+ compareVersions,
202
+ ServlyComponent_default as default,
203
+ fetchComponent2 as fetchComponent,
204
+ getRegistryUrl,
205
+ invalidateCache,
206
+ isComponentAvailable,
207
+ parseVersion,
208
+ prefetchComponents,
209
+ resolveVersion,
210
+ satisfiesVersion,
211
+ setRegistryUrl
212
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@servlyadmin/runtime-react",
3
+ "version": "0.1.0",
4
+ "description": "React wrapper for Servly runtime renderer",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "sideEffects": false,
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format esm,cjs --dts --clean --external react",
22
+ "dev": "tsup src/index.ts --format esm,cjs --dts --watch --external react",
23
+ "test": "vitest run",
24
+ "test:watch": "vitest"
25
+ },
26
+ "keywords": [
27
+ "servly",
28
+ "runtime",
29
+ "react",
30
+ "component"
31
+ ],
32
+ "author": "Servly",
33
+ "license": "MIT",
34
+ "peerDependencies": {
35
+ "react": ">=17.0.0",
36
+ "react-dom": ">=17.0.0"
37
+ },
38
+ "dependencies": {
39
+ "@servlyadmin/runtime-core": "^0.1.0"
40
+ },
41
+ "devDependencies": {
42
+ "@types/react": "^18.2.0",
43
+ "@types/react-dom": "^18.2.0",
44
+ "react": "^18.2.0",
45
+ "react-dom": "^18.2.0",
46
+ "tsup": "^8.0.0",
47
+ "typescript": "^5.3.0",
48
+ "vitest": "^1.0.0"
49
+ }
50
+ }