@servlyadmin/runtime-react 0.1.31 → 0.1.34

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 CHANGED
@@ -41,6 +41,11 @@ var import_react = require("react");
41
41
  var import_react_dom = require("react-dom");
42
42
  var import_runtime_core = require("@servlyadmin/runtime-core");
43
43
  var import_jsx_runtime = require("react/jsx-runtime");
44
+ if (typeof document !== "undefined") {
45
+ (0, import_runtime_core.injectTailwind)({ usePlayCdn: true }).catch((err) => {
46
+ console.warn("[ServlyComponent React] Failed to inject Tailwind:", err);
47
+ });
48
+ }
44
49
  var LoadingSkeleton = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
45
50
  "div",
46
51
  {
@@ -126,7 +131,8 @@ function ServlyComponent({
126
131
  cacheStrategy = "memory",
127
132
  retryConfig,
128
133
  eventHandlers,
129
- children
134
+ children,
135
+ waitForStyles = true
130
136
  }) {
131
137
  const containerRef = (0, import_react.useRef)(null);
132
138
  const renderResultRef = (0, import_react.useRef)(null);
@@ -135,7 +141,9 @@ function ServlyComponent({
135
141
  const [state, setState] = (0, import_react.useState)({
136
142
  loading: true,
137
143
  error: null,
138
- data: null
144
+ data: null,
145
+ stylesReady: !waitForStyles
146
+ // If not waiting, styles are "ready"
139
147
  });
140
148
  const slotElements = useSlotElements(containerRef, isRendered);
141
149
  const effectiveSlots = (0, import_react.useMemo)(() => {
@@ -160,24 +168,26 @@ function ServlyComponent({
160
168
  };
161
169
  try {
162
170
  const result = await (0, import_runtime_core.fetchComponent)(id, fetchOptions);
163
- setState({
171
+ setState((prev) => ({
172
+ ...prev,
164
173
  loading: false,
165
174
  error: null,
166
175
  data: result.data,
167
176
  views: result.views,
168
177
  registry: result.registry
169
- });
178
+ }));
170
179
  onLoad?.();
171
180
  } catch (error) {
172
181
  const err = error instanceof Error ? error : new Error(String(error));
173
182
  if (err.message === "Fetch aborted") return;
174
- setState({
183
+ setState((prev) => ({
184
+ ...prev,
175
185
  loading: false,
176
186
  error: err,
177
187
  data: null,
178
188
  views: void 0,
179
189
  registry: void 0
180
- });
190
+ }));
181
191
  onError?.(err);
182
192
  }
183
193
  }, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
@@ -191,24 +201,34 @@ function ServlyComponent({
191
201
  }, [loadComponent]);
192
202
  (0, import_react.useEffect)(() => {
193
203
  if (!state.data || !containerRef.current) return;
194
- const context = {
195
- props,
196
- state: {},
197
- context: {}
204
+ const doRender = async () => {
205
+ if (waitForStyles) {
206
+ await (0, import_runtime_core.waitForTailwind)();
207
+ setState((prev) => ({ ...prev, stylesReady: true }));
208
+ }
209
+ const context = {
210
+ props,
211
+ state: {},
212
+ context: {}
213
+ };
214
+ if (renderResultRef.current) {
215
+ renderResultRef.current.update(context);
216
+ return;
217
+ }
218
+ renderResultRef.current = (0, import_runtime_core.render)({
219
+ container: containerRef.current,
220
+ elements: state.data.layout,
221
+ context,
222
+ eventHandlers,
223
+ views: state.views,
224
+ componentRegistry: state.registry
225
+ });
226
+ if (containerRef.current) {
227
+ (0, import_runtime_core.markElementReady)(containerRef.current);
228
+ }
229
+ setIsRendered(true);
198
230
  };
199
- if (renderResultRef.current) {
200
- renderResultRef.current.update(context);
201
- return;
202
- }
203
- renderResultRef.current = (0, import_runtime_core.render)({
204
- container: containerRef.current,
205
- elements: state.data.layout,
206
- context,
207
- eventHandlers,
208
- views: state.views,
209
- componentRegistry: state.registry
210
- });
211
- setIsRendered(true);
231
+ doRender();
212
232
  return () => {
213
233
  if (renderResultRef.current) {
214
234
  renderResultRef.current.destroy();
@@ -216,7 +236,7 @@ function ServlyComponent({
216
236
  setIsRendered(false);
217
237
  }
218
238
  };
219
- }, [state.data, eventHandlers]);
239
+ }, [state.data, eventHandlers, waitForStyles]);
220
240
  (0, import_react.useEffect)(() => {
221
241
  if (!renderResultRef.current || !state.data) return;
222
242
  const context = {
@@ -226,7 +246,7 @@ function ServlyComponent({
226
246
  };
227
247
  renderResultRef.current.update(context);
228
248
  }, [props, state.data]);
229
- if (state.loading) {
249
+ if (state.loading || waitForStyles && !state.stylesReady) {
230
250
  if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
231
251
  if (showSkeleton) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(LoadingSkeleton, { className });
232
252
  return null;
@@ -248,7 +268,7 @@ function ServlyComponent({
248
268
  "div",
249
269
  {
250
270
  ref: containerRef,
251
- className: `servly-component ${className || ""}`,
271
+ className: `servly-component servly-ready ${className || ""}`,
252
272
  style,
253
273
  "data-servly-id": id,
254
274
  "data-servly-version": state.data?.version
package/dist/index.js CHANGED
@@ -3,9 +3,17 @@ import { useRef, useEffect, useState, useCallback, useMemo } from "react";
3
3
  import { createPortal } from "react-dom";
4
4
  import {
5
5
  render,
6
- fetchComponent
6
+ fetchComponent,
7
+ waitForTailwind,
8
+ markElementReady,
9
+ injectTailwind
7
10
  } from "@servlyadmin/runtime-core";
8
11
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ if (typeof document !== "undefined") {
13
+ injectTailwind({ usePlayCdn: true }).catch((err) => {
14
+ console.warn("[ServlyComponent React] Failed to inject Tailwind:", err);
15
+ });
16
+ }
9
17
  var LoadingSkeleton = ({ className }) => /* @__PURE__ */ jsx(
10
18
  "div",
11
19
  {
@@ -91,7 +99,8 @@ function ServlyComponent({
91
99
  cacheStrategy = "memory",
92
100
  retryConfig,
93
101
  eventHandlers,
94
- children
102
+ children,
103
+ waitForStyles = true
95
104
  }) {
96
105
  const containerRef = useRef(null);
97
106
  const renderResultRef = useRef(null);
@@ -100,7 +109,9 @@ function ServlyComponent({
100
109
  const [state, setState] = useState({
101
110
  loading: true,
102
111
  error: null,
103
- data: null
112
+ data: null,
113
+ stylesReady: !waitForStyles
114
+ // If not waiting, styles are "ready"
104
115
  });
105
116
  const slotElements = useSlotElements(containerRef, isRendered);
106
117
  const effectiveSlots = useMemo(() => {
@@ -125,24 +136,26 @@ function ServlyComponent({
125
136
  };
126
137
  try {
127
138
  const result = await fetchComponent(id, fetchOptions);
128
- setState({
139
+ setState((prev) => ({
140
+ ...prev,
129
141
  loading: false,
130
142
  error: null,
131
143
  data: result.data,
132
144
  views: result.views,
133
145
  registry: result.registry
134
- });
146
+ }));
135
147
  onLoad?.();
136
148
  } catch (error) {
137
149
  const err = error instanceof Error ? error : new Error(String(error));
138
150
  if (err.message === "Fetch aborted") return;
139
- setState({
151
+ setState((prev) => ({
152
+ ...prev,
140
153
  loading: false,
141
154
  error: err,
142
155
  data: null,
143
156
  views: void 0,
144
157
  registry: void 0
145
- });
158
+ }));
146
159
  onError?.(err);
147
160
  }
148
161
  }, [id, version, cacheStrategy, retryConfig, onLoad, onError]);
@@ -156,24 +169,34 @@ function ServlyComponent({
156
169
  }, [loadComponent]);
157
170
  useEffect(() => {
158
171
  if (!state.data || !containerRef.current) return;
159
- const context = {
160
- props,
161
- state: {},
162
- context: {}
172
+ const doRender = async () => {
173
+ if (waitForStyles) {
174
+ await waitForTailwind();
175
+ setState((prev) => ({ ...prev, stylesReady: true }));
176
+ }
177
+ const context = {
178
+ props,
179
+ state: {},
180
+ context: {}
181
+ };
182
+ if (renderResultRef.current) {
183
+ renderResultRef.current.update(context);
184
+ return;
185
+ }
186
+ renderResultRef.current = render({
187
+ container: containerRef.current,
188
+ elements: state.data.layout,
189
+ context,
190
+ eventHandlers,
191
+ views: state.views,
192
+ componentRegistry: state.registry
193
+ });
194
+ if (containerRef.current) {
195
+ markElementReady(containerRef.current);
196
+ }
197
+ setIsRendered(true);
163
198
  };
164
- if (renderResultRef.current) {
165
- renderResultRef.current.update(context);
166
- return;
167
- }
168
- renderResultRef.current = render({
169
- container: containerRef.current,
170
- elements: state.data.layout,
171
- context,
172
- eventHandlers,
173
- views: state.views,
174
- componentRegistry: state.registry
175
- });
176
- setIsRendered(true);
199
+ doRender();
177
200
  return () => {
178
201
  if (renderResultRef.current) {
179
202
  renderResultRef.current.destroy();
@@ -181,7 +204,7 @@ function ServlyComponent({
181
204
  setIsRendered(false);
182
205
  }
183
206
  };
184
- }, [state.data, eventHandlers]);
207
+ }, [state.data, eventHandlers, waitForStyles]);
185
208
  useEffect(() => {
186
209
  if (!renderResultRef.current || !state.data) return;
187
210
  const context = {
@@ -191,7 +214,7 @@ function ServlyComponent({
191
214
  };
192
215
  renderResultRef.current.update(context);
193
216
  }, [props, state.data]);
194
- if (state.loading) {
217
+ if (state.loading || waitForStyles && !state.stylesReady) {
195
218
  if (fallback) return /* @__PURE__ */ jsx(Fragment, { children: fallback });
196
219
  if (showSkeleton) return /* @__PURE__ */ jsx(LoadingSkeleton, { className });
197
220
  return null;
@@ -213,7 +236,7 @@ function ServlyComponent({
213
236
  "div",
214
237
  {
215
238
  ref: containerRef,
216
- className: `servly-component ${className || ""}`,
239
+ className: `servly-component servly-ready ${className || ""}`,
217
240
  style,
218
241
  "data-servly-id": id,
219
242
  "data-servly-version": state.data?.version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servlyadmin/runtime-react",
3
- "version": "0.1.31",
3
+ "version": "0.1.34",
4
4
  "description": "React wrapper for Servly runtime renderer",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -36,7 +36,7 @@
36
36
  "react-dom": ">=17.0.0"
37
37
  },
38
38
  "dependencies": {
39
- "@servlyadmin/runtime-core": "^0.1.31"
39
+ "@servlyadmin/runtime-core": "^0.1.44"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/react": "^18.2.0",