@json-render/react-email 0.8.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/LICENSE +201 -0
- package/README.md +147 -0
- package/dist/catalog-types-Dh9gul8V.d.mts +17 -0
- package/dist/catalog-types-Dh9gul8V.d.ts +17 -0
- package/dist/catalog.d.mts +216 -0
- package/dist/catalog.d.ts +216 -0
- package/dist/catalog.js +203 -0
- package/dist/catalog.js.map +1 -0
- package/dist/catalog.mjs +7 -0
- package/dist/catalog.mjs.map +1 -0
- package/dist/chunk-3YN5NZJ7.mjs +44 -0
- package/dist/chunk-3YN5NZJ7.mjs.map +1 -0
- package/dist/chunk-GXJW4OIL.mjs +179 -0
- package/dist/chunk-GXJW4OIL.mjs.map +1 -0
- package/dist/chunk-MPWIHNXF.mjs +253 -0
- package/dist/chunk-MPWIHNXF.mjs.map +1 -0
- package/dist/index.d.mts +114 -0
- package/dist/index.d.ts +114 -0
- package/dist/index.js +1298 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +847 -0
- package/dist/index.mjs.map +1 -0
- package/dist/render-DFHuQRW0.d.ts +80 -0
- package/dist/render-kNHi7tZ2.d.mts +80 -0
- package/dist/render.d.mts +5 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.js +259 -0
- package/dist/render.js.map +1 -0
- package/dist/render.mjs +11 -0
- package/dist/render.mjs.map +1 -0
- package/dist/server.d.mts +43 -0
- package/dist/server.d.ts +43 -0
- package/dist/server.js +247 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +11 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +78 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,847 @@
|
|
|
1
|
+
import {
|
|
2
|
+
renderToHtml,
|
|
3
|
+
renderToPlainText,
|
|
4
|
+
standardComponents
|
|
5
|
+
} from "./chunk-MPWIHNXF.mjs";
|
|
6
|
+
import {
|
|
7
|
+
schema
|
|
8
|
+
} from "./chunk-3YN5NZJ7.mjs";
|
|
9
|
+
import {
|
|
10
|
+
standardComponentDefinitions
|
|
11
|
+
} from "./chunk-GXJW4OIL.mjs";
|
|
12
|
+
|
|
13
|
+
// src/contexts/state.tsx
|
|
14
|
+
import {
|
|
15
|
+
createContext,
|
|
16
|
+
useContext,
|
|
17
|
+
useState,
|
|
18
|
+
useCallback,
|
|
19
|
+
useMemo,
|
|
20
|
+
useEffect,
|
|
21
|
+
useRef
|
|
22
|
+
} from "react";
|
|
23
|
+
import { getByPath, setByPath } from "@json-render/core";
|
|
24
|
+
import { jsx } from "react/jsx-runtime";
|
|
25
|
+
var StateContext = createContext(null);
|
|
26
|
+
function StateProvider({
|
|
27
|
+
initialState = {},
|
|
28
|
+
onStateChange,
|
|
29
|
+
children
|
|
30
|
+
}) {
|
|
31
|
+
const [state, setStateInternal] = useState(initialState);
|
|
32
|
+
const stateRef = useRef(state);
|
|
33
|
+
stateRef.current = state;
|
|
34
|
+
const initialStateJsonRef = useRef(JSON.stringify(initialState));
|
|
35
|
+
useEffect(() => {
|
|
36
|
+
const newJson = JSON.stringify(initialState);
|
|
37
|
+
if (newJson !== initialStateJsonRef.current) {
|
|
38
|
+
initialStateJsonRef.current = newJson;
|
|
39
|
+
if (initialState && Object.keys(initialState).length > 0) {
|
|
40
|
+
setStateInternal((prev) => ({ ...prev, ...initialState }));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}, [initialState]);
|
|
44
|
+
const get = useCallback(
|
|
45
|
+
(path) => getByPath(stateRef.current, path),
|
|
46
|
+
[]
|
|
47
|
+
);
|
|
48
|
+
const set = useCallback(
|
|
49
|
+
(path, value2) => {
|
|
50
|
+
setStateInternal((prev) => {
|
|
51
|
+
const next = { ...prev };
|
|
52
|
+
setByPath(next, path, value2);
|
|
53
|
+
return next;
|
|
54
|
+
});
|
|
55
|
+
onStateChange?.(path, value2);
|
|
56
|
+
},
|
|
57
|
+
[onStateChange]
|
|
58
|
+
);
|
|
59
|
+
const update = useCallback(
|
|
60
|
+
(updates) => {
|
|
61
|
+
const entries = Object.entries(updates);
|
|
62
|
+
setStateInternal((prev) => {
|
|
63
|
+
const next = { ...prev };
|
|
64
|
+
for (const [path, value2] of entries) {
|
|
65
|
+
setByPath(next, path, value2);
|
|
66
|
+
}
|
|
67
|
+
return next;
|
|
68
|
+
});
|
|
69
|
+
for (const [path, value2] of entries) {
|
|
70
|
+
onStateChange?.(path, value2);
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
[onStateChange]
|
|
74
|
+
);
|
|
75
|
+
const value = useMemo(
|
|
76
|
+
() => ({ state, get, set, update }),
|
|
77
|
+
[state, get, set, update]
|
|
78
|
+
);
|
|
79
|
+
return /* @__PURE__ */ jsx(StateContext.Provider, { value, children });
|
|
80
|
+
}
|
|
81
|
+
function useStateStore() {
|
|
82
|
+
const ctx = useContext(StateContext);
|
|
83
|
+
if (!ctx) {
|
|
84
|
+
throw new Error("useStateStore must be used within a StateProvider");
|
|
85
|
+
}
|
|
86
|
+
return ctx;
|
|
87
|
+
}
|
|
88
|
+
function useStateValue(path) {
|
|
89
|
+
const { state } = useStateStore();
|
|
90
|
+
return getByPath(state, path);
|
|
91
|
+
}
|
|
92
|
+
function useStateBinding(path) {
|
|
93
|
+
const { state, set } = useStateStore();
|
|
94
|
+
const value = getByPath(state, path);
|
|
95
|
+
const setValue = useCallback(
|
|
96
|
+
(newValue) => set(path, newValue),
|
|
97
|
+
[path, set]
|
|
98
|
+
);
|
|
99
|
+
return [value, setValue];
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// src/contexts/visibility.tsx
|
|
103
|
+
import {
|
|
104
|
+
createContext as createContext2,
|
|
105
|
+
useContext as useContext2,
|
|
106
|
+
useMemo as useMemo2
|
|
107
|
+
} from "react";
|
|
108
|
+
import {
|
|
109
|
+
evaluateVisibility
|
|
110
|
+
} from "@json-render/core";
|
|
111
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
112
|
+
var VisibilityContext = createContext2(null);
|
|
113
|
+
function VisibilityProvider({ children }) {
|
|
114
|
+
const { state } = useStateStore();
|
|
115
|
+
const ctx = useMemo2(
|
|
116
|
+
() => ({ stateModel: state }),
|
|
117
|
+
[state]
|
|
118
|
+
);
|
|
119
|
+
const isVisible = useMemo2(
|
|
120
|
+
() => (condition) => evaluateVisibility(condition, ctx),
|
|
121
|
+
[ctx]
|
|
122
|
+
);
|
|
123
|
+
const value = useMemo2(
|
|
124
|
+
() => ({ isVisible, ctx }),
|
|
125
|
+
[isVisible, ctx]
|
|
126
|
+
);
|
|
127
|
+
return /* @__PURE__ */ jsx2(VisibilityContext.Provider, { value, children });
|
|
128
|
+
}
|
|
129
|
+
function useVisibility() {
|
|
130
|
+
const ctx = useContext2(VisibilityContext);
|
|
131
|
+
if (!ctx) {
|
|
132
|
+
throw new Error("useVisibility must be used within a VisibilityProvider");
|
|
133
|
+
}
|
|
134
|
+
return ctx;
|
|
135
|
+
}
|
|
136
|
+
function useIsVisible(condition) {
|
|
137
|
+
const { isVisible } = useVisibility();
|
|
138
|
+
return isVisible(condition);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/contexts/actions.tsx
|
|
142
|
+
import {
|
|
143
|
+
createContext as createContext3,
|
|
144
|
+
useContext as useContext3,
|
|
145
|
+
useState as useState2,
|
|
146
|
+
useCallback as useCallback2,
|
|
147
|
+
useMemo as useMemo3
|
|
148
|
+
} from "react";
|
|
149
|
+
import {
|
|
150
|
+
resolveAction,
|
|
151
|
+
executeAction
|
|
152
|
+
} from "@json-render/core";
|
|
153
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
154
|
+
function generateUniqueId() {
|
|
155
|
+
return crypto.randomUUID();
|
|
156
|
+
}
|
|
157
|
+
function deepResolveValue(value, get) {
|
|
158
|
+
if (value === null || value === void 0) return value;
|
|
159
|
+
if (value === "$id") {
|
|
160
|
+
return generateUniqueId();
|
|
161
|
+
}
|
|
162
|
+
if (typeof value === "object" && !Array.isArray(value)) {
|
|
163
|
+
const obj = value;
|
|
164
|
+
const keys = Object.keys(obj);
|
|
165
|
+
if (keys.length === 1 && typeof obj.$state === "string") {
|
|
166
|
+
return get(obj.$state);
|
|
167
|
+
}
|
|
168
|
+
if (keys.length === 1 && "$id" in obj) {
|
|
169
|
+
return generateUniqueId();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (Array.isArray(value)) {
|
|
173
|
+
return value.map((item) => deepResolveValue(item, get));
|
|
174
|
+
}
|
|
175
|
+
if (typeof value === "object") {
|
|
176
|
+
const resolved = {};
|
|
177
|
+
for (const [key, val] of Object.entries(value)) {
|
|
178
|
+
resolved[key] = deepResolveValue(val, get);
|
|
179
|
+
}
|
|
180
|
+
return resolved;
|
|
181
|
+
}
|
|
182
|
+
return value;
|
|
183
|
+
}
|
|
184
|
+
var ActionContext = createContext3(null);
|
|
185
|
+
function ActionProvider({
|
|
186
|
+
handlers: initialHandlers = {},
|
|
187
|
+
navigate,
|
|
188
|
+
children
|
|
189
|
+
}) {
|
|
190
|
+
const { state, get, set } = useStateStore();
|
|
191
|
+
const [handlers, setHandlers] = useState2(initialHandlers);
|
|
192
|
+
const [loadingActions, setLoadingActions] = useState2(/* @__PURE__ */ new Set());
|
|
193
|
+
const [pendingConfirmation, setPendingConfirmation] = useState2(null);
|
|
194
|
+
const registerHandler = useCallback2(
|
|
195
|
+
(name, handler) => {
|
|
196
|
+
setHandlers((prev) => ({ ...prev, [name]: handler }));
|
|
197
|
+
},
|
|
198
|
+
[]
|
|
199
|
+
);
|
|
200
|
+
const execute = useCallback2(
|
|
201
|
+
async (binding) => {
|
|
202
|
+
const resolved = resolveAction(binding, state);
|
|
203
|
+
if (resolved.action === "setState" && resolved.params) {
|
|
204
|
+
const statePath = resolved.params.statePath;
|
|
205
|
+
const value2 = resolved.params.value;
|
|
206
|
+
if (statePath) {
|
|
207
|
+
set(statePath, value2);
|
|
208
|
+
}
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (resolved.action === "pushState" && resolved.params) {
|
|
212
|
+
const statePath = resolved.params.statePath;
|
|
213
|
+
const rawValue = resolved.params.value;
|
|
214
|
+
if (statePath) {
|
|
215
|
+
const resolvedValue = deepResolveValue(rawValue, get);
|
|
216
|
+
const arr = get(statePath) ?? [];
|
|
217
|
+
set(statePath, [...arr, resolvedValue]);
|
|
218
|
+
const clearStatePath = resolved.params.clearStatePath;
|
|
219
|
+
if (clearStatePath) {
|
|
220
|
+
set(clearStatePath, "");
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (resolved.action === "removeState" && resolved.params) {
|
|
226
|
+
const statePath = resolved.params.statePath;
|
|
227
|
+
const index = resolved.params.index;
|
|
228
|
+
if (statePath !== void 0 && index !== void 0) {
|
|
229
|
+
const arr = get(statePath) ?? [];
|
|
230
|
+
set(
|
|
231
|
+
statePath,
|
|
232
|
+
arr.filter((_, i) => i !== index)
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
const handler = handlers[resolved.action];
|
|
238
|
+
if (!handler) {
|
|
239
|
+
console.warn(`No handler registered for action: ${resolved.action}`);
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
if (resolved.confirm) {
|
|
243
|
+
return new Promise((resolve, reject) => {
|
|
244
|
+
setPendingConfirmation({
|
|
245
|
+
action: resolved,
|
|
246
|
+
handler,
|
|
247
|
+
resolve: () => {
|
|
248
|
+
setPendingConfirmation(null);
|
|
249
|
+
resolve();
|
|
250
|
+
},
|
|
251
|
+
reject: () => {
|
|
252
|
+
setPendingConfirmation(null);
|
|
253
|
+
reject(new Error("Action cancelled"));
|
|
254
|
+
}
|
|
255
|
+
});
|
|
256
|
+
}).then(async () => {
|
|
257
|
+
setLoadingActions((prev) => new Set(prev).add(resolved.action));
|
|
258
|
+
try {
|
|
259
|
+
await executeAction({
|
|
260
|
+
action: resolved,
|
|
261
|
+
handler,
|
|
262
|
+
setState: set,
|
|
263
|
+
navigate,
|
|
264
|
+
executeAction: async (name) => {
|
|
265
|
+
const subBinding = { action: name };
|
|
266
|
+
await execute(subBinding);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
} finally {
|
|
270
|
+
setLoadingActions((prev) => {
|
|
271
|
+
const next = new Set(prev);
|
|
272
|
+
next.delete(resolved.action);
|
|
273
|
+
return next;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
setLoadingActions((prev) => new Set(prev).add(resolved.action));
|
|
279
|
+
try {
|
|
280
|
+
await executeAction({
|
|
281
|
+
action: resolved,
|
|
282
|
+
handler,
|
|
283
|
+
setState: set,
|
|
284
|
+
navigate,
|
|
285
|
+
executeAction: async (name) => {
|
|
286
|
+
const subBinding = { action: name };
|
|
287
|
+
await execute(subBinding);
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
} finally {
|
|
291
|
+
setLoadingActions((prev) => {
|
|
292
|
+
const next = new Set(prev);
|
|
293
|
+
next.delete(resolved.action);
|
|
294
|
+
return next;
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
},
|
|
298
|
+
[state, handlers, get, set, navigate]
|
|
299
|
+
);
|
|
300
|
+
const confirm = useCallback2(() => {
|
|
301
|
+
pendingConfirmation?.resolve();
|
|
302
|
+
}, [pendingConfirmation]);
|
|
303
|
+
const cancel = useCallback2(() => {
|
|
304
|
+
pendingConfirmation?.reject();
|
|
305
|
+
}, [pendingConfirmation]);
|
|
306
|
+
const value = useMemo3(
|
|
307
|
+
() => ({
|
|
308
|
+
handlers,
|
|
309
|
+
loadingActions,
|
|
310
|
+
pendingConfirmation,
|
|
311
|
+
execute,
|
|
312
|
+
confirm,
|
|
313
|
+
cancel,
|
|
314
|
+
registerHandler
|
|
315
|
+
}),
|
|
316
|
+
[
|
|
317
|
+
handlers,
|
|
318
|
+
loadingActions,
|
|
319
|
+
pendingConfirmation,
|
|
320
|
+
execute,
|
|
321
|
+
confirm,
|
|
322
|
+
cancel,
|
|
323
|
+
registerHandler
|
|
324
|
+
]
|
|
325
|
+
);
|
|
326
|
+
return /* @__PURE__ */ jsx3(ActionContext.Provider, { value, children });
|
|
327
|
+
}
|
|
328
|
+
function useActions() {
|
|
329
|
+
const ctx = useContext3(ActionContext);
|
|
330
|
+
if (!ctx) {
|
|
331
|
+
throw new Error("useActions must be used within an ActionProvider");
|
|
332
|
+
}
|
|
333
|
+
return ctx;
|
|
334
|
+
}
|
|
335
|
+
function useAction(binding) {
|
|
336
|
+
const { execute, loadingActions } = useActions();
|
|
337
|
+
const isLoading = loadingActions.has(binding.action);
|
|
338
|
+
const executeAction2 = useCallback2(() => execute(binding), [execute, binding]);
|
|
339
|
+
return { execute: executeAction2, isLoading };
|
|
340
|
+
}
|
|
341
|
+
function ConfirmDialog(_props) {
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/contexts/validation.tsx
|
|
346
|
+
import React4, {
|
|
347
|
+
createContext as createContext4,
|
|
348
|
+
useContext as useContext4,
|
|
349
|
+
useState as useState3,
|
|
350
|
+
useCallback as useCallback3,
|
|
351
|
+
useMemo as useMemo4
|
|
352
|
+
} from "react";
|
|
353
|
+
import {
|
|
354
|
+
runValidation
|
|
355
|
+
} from "@json-render/core";
|
|
356
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
357
|
+
var ValidationContext = createContext4(null);
|
|
358
|
+
function dynamicArgsEqual(a, b) {
|
|
359
|
+
if (a === b) return true;
|
|
360
|
+
if (!a || !b) return false;
|
|
361
|
+
const keysA = Object.keys(a);
|
|
362
|
+
const keysB = Object.keys(b);
|
|
363
|
+
if (keysA.length !== keysB.length) return false;
|
|
364
|
+
for (const key of keysA) {
|
|
365
|
+
const va = a[key];
|
|
366
|
+
const vb = b[key];
|
|
367
|
+
if (va === vb) continue;
|
|
368
|
+
if (typeof va === "object" && va !== null && typeof vb === "object" && vb !== null) {
|
|
369
|
+
const sa = va.$state;
|
|
370
|
+
const sb = vb.$state;
|
|
371
|
+
if (typeof sa === "string" && sa === sb) continue;
|
|
372
|
+
}
|
|
373
|
+
return false;
|
|
374
|
+
}
|
|
375
|
+
return true;
|
|
376
|
+
}
|
|
377
|
+
function validationConfigEqual(a, b) {
|
|
378
|
+
if (a === b) return true;
|
|
379
|
+
if (a.validateOn !== b.validateOn) return false;
|
|
380
|
+
const ac = a.checks ?? [];
|
|
381
|
+
const bc = b.checks ?? [];
|
|
382
|
+
if (ac.length !== bc.length) return false;
|
|
383
|
+
for (let i = 0; i < ac.length; i++) {
|
|
384
|
+
const ca = ac[i];
|
|
385
|
+
const cb = bc[i];
|
|
386
|
+
if (ca.type !== cb.type) return false;
|
|
387
|
+
if (ca.message !== cb.message) return false;
|
|
388
|
+
if (!dynamicArgsEqual(ca.args, cb.args)) return false;
|
|
389
|
+
}
|
|
390
|
+
return true;
|
|
391
|
+
}
|
|
392
|
+
function ValidationProvider({
|
|
393
|
+
customFunctions = {},
|
|
394
|
+
children
|
|
395
|
+
}) {
|
|
396
|
+
const { state } = useStateStore();
|
|
397
|
+
const [fieldStates, setFieldStates] = useState3({});
|
|
398
|
+
const [fieldConfigs, setFieldConfigs] = useState3({});
|
|
399
|
+
const registerField = useCallback3(
|
|
400
|
+
(path, config) => {
|
|
401
|
+
setFieldConfigs((prev) => {
|
|
402
|
+
const existing = prev[path];
|
|
403
|
+
if (existing && validationConfigEqual(existing, config)) {
|
|
404
|
+
return prev;
|
|
405
|
+
}
|
|
406
|
+
return { ...prev, [path]: config };
|
|
407
|
+
});
|
|
408
|
+
},
|
|
409
|
+
[]
|
|
410
|
+
);
|
|
411
|
+
const validate = useCallback3(
|
|
412
|
+
(path, config) => {
|
|
413
|
+
const segments = path.split("/").filter(Boolean);
|
|
414
|
+
let value2 = state;
|
|
415
|
+
for (const seg of segments) {
|
|
416
|
+
if (value2 != null && typeof value2 === "object") {
|
|
417
|
+
value2 = value2[seg];
|
|
418
|
+
} else {
|
|
419
|
+
value2 = void 0;
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const result = runValidation(config, {
|
|
424
|
+
value: value2,
|
|
425
|
+
stateModel: state,
|
|
426
|
+
customFunctions
|
|
427
|
+
});
|
|
428
|
+
setFieldStates((prev) => ({
|
|
429
|
+
...prev,
|
|
430
|
+
[path]: {
|
|
431
|
+
touched: prev[path]?.touched ?? true,
|
|
432
|
+
validated: true,
|
|
433
|
+
result
|
|
434
|
+
}
|
|
435
|
+
}));
|
|
436
|
+
return result;
|
|
437
|
+
},
|
|
438
|
+
[state, customFunctions]
|
|
439
|
+
);
|
|
440
|
+
const touch = useCallback3((path) => {
|
|
441
|
+
setFieldStates((prev) => ({
|
|
442
|
+
...prev,
|
|
443
|
+
[path]: {
|
|
444
|
+
...prev[path],
|
|
445
|
+
touched: true,
|
|
446
|
+
validated: prev[path]?.validated ?? false,
|
|
447
|
+
result: prev[path]?.result ?? null
|
|
448
|
+
}
|
|
449
|
+
}));
|
|
450
|
+
}, []);
|
|
451
|
+
const clear = useCallback3((path) => {
|
|
452
|
+
setFieldStates((prev) => {
|
|
453
|
+
const { [path]: _, ...rest } = prev;
|
|
454
|
+
return rest;
|
|
455
|
+
});
|
|
456
|
+
}, []);
|
|
457
|
+
const validateAll = useCallback3(() => {
|
|
458
|
+
let allValid = true;
|
|
459
|
+
for (const [path, config] of Object.entries(fieldConfigs)) {
|
|
460
|
+
const result = validate(path, config);
|
|
461
|
+
if (!result.valid) {
|
|
462
|
+
allValid = false;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return allValid;
|
|
466
|
+
}, [fieldConfigs, validate]);
|
|
467
|
+
const value = useMemo4(
|
|
468
|
+
() => ({
|
|
469
|
+
customFunctions,
|
|
470
|
+
fieldStates,
|
|
471
|
+
validate,
|
|
472
|
+
touch,
|
|
473
|
+
clear,
|
|
474
|
+
validateAll,
|
|
475
|
+
registerField
|
|
476
|
+
}),
|
|
477
|
+
[
|
|
478
|
+
customFunctions,
|
|
479
|
+
fieldStates,
|
|
480
|
+
validate,
|
|
481
|
+
touch,
|
|
482
|
+
clear,
|
|
483
|
+
validateAll,
|
|
484
|
+
registerField
|
|
485
|
+
]
|
|
486
|
+
);
|
|
487
|
+
return /* @__PURE__ */ jsx4(ValidationContext.Provider, { value, children });
|
|
488
|
+
}
|
|
489
|
+
function useValidation() {
|
|
490
|
+
const ctx = useContext4(ValidationContext);
|
|
491
|
+
if (!ctx) {
|
|
492
|
+
throw new Error("useValidation must be used within a ValidationProvider");
|
|
493
|
+
}
|
|
494
|
+
return ctx;
|
|
495
|
+
}
|
|
496
|
+
function useFieldValidation(path, config) {
|
|
497
|
+
const {
|
|
498
|
+
fieldStates,
|
|
499
|
+
validate: validateField,
|
|
500
|
+
touch: touchField,
|
|
501
|
+
clear: clearField,
|
|
502
|
+
registerField
|
|
503
|
+
} = useValidation();
|
|
504
|
+
React4.useEffect(() => {
|
|
505
|
+
if (config) {
|
|
506
|
+
registerField(path, config);
|
|
507
|
+
}
|
|
508
|
+
}, [path, config, registerField]);
|
|
509
|
+
const state = fieldStates[path] ?? {
|
|
510
|
+
touched: false,
|
|
511
|
+
validated: false,
|
|
512
|
+
result: null
|
|
513
|
+
};
|
|
514
|
+
const validate = useCallback3(
|
|
515
|
+
() => validateField(path, config ?? { checks: [] }),
|
|
516
|
+
[path, config, validateField]
|
|
517
|
+
);
|
|
518
|
+
const touch = useCallback3(() => touchField(path), [path, touchField]);
|
|
519
|
+
const clear = useCallback3(() => clearField(path), [path, clearField]);
|
|
520
|
+
return {
|
|
521
|
+
state,
|
|
522
|
+
validate,
|
|
523
|
+
touch,
|
|
524
|
+
clear,
|
|
525
|
+
errors: state.result?.errors ?? [],
|
|
526
|
+
isValid: state.result?.valid ?? true
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// src/contexts/repeat-scope.tsx
|
|
531
|
+
import { createContext as createContext5, useContext as useContext5 } from "react";
|
|
532
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
533
|
+
var RepeatScopeContext = createContext5(null);
|
|
534
|
+
function RepeatScopeProvider({
|
|
535
|
+
item,
|
|
536
|
+
index,
|
|
537
|
+
basePath,
|
|
538
|
+
children
|
|
539
|
+
}) {
|
|
540
|
+
return /* @__PURE__ */ jsx5(RepeatScopeContext.Provider, { value: { item, index, basePath }, children });
|
|
541
|
+
}
|
|
542
|
+
function useRepeatScope() {
|
|
543
|
+
return useContext5(RepeatScopeContext);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
// src/renderer.tsx
|
|
547
|
+
import React6, {
|
|
548
|
+
useCallback as useCallback4,
|
|
549
|
+
useMemo as useMemo5
|
|
550
|
+
} from "react";
|
|
551
|
+
import {
|
|
552
|
+
resolveElementProps,
|
|
553
|
+
resolveBindings,
|
|
554
|
+
resolveActionParam,
|
|
555
|
+
evaluateVisibility as evaluateVisibility2,
|
|
556
|
+
getByPath as getByPath2
|
|
557
|
+
} from "@json-render/core";
|
|
558
|
+
import { Fragment, jsx as jsx6 } from "react/jsx-runtime";
|
|
559
|
+
var ElementErrorBoundary = class extends React6.Component {
|
|
560
|
+
constructor(props) {
|
|
561
|
+
super(props);
|
|
562
|
+
this.state = { hasError: false };
|
|
563
|
+
}
|
|
564
|
+
static getDerivedStateFromError() {
|
|
565
|
+
return { hasError: true };
|
|
566
|
+
}
|
|
567
|
+
componentDidCatch(error, info) {
|
|
568
|
+
console.error(
|
|
569
|
+
`[json-render/react-email] Rendering error in <${this.props.elementType}>:`,
|
|
570
|
+
error,
|
|
571
|
+
info.componentStack
|
|
572
|
+
);
|
|
573
|
+
}
|
|
574
|
+
render() {
|
|
575
|
+
if (this.state.hasError) {
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
return this.props.children;
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
var ElementRenderer = React6.memo(function ElementRenderer2({
|
|
582
|
+
element,
|
|
583
|
+
spec,
|
|
584
|
+
registry,
|
|
585
|
+
loading,
|
|
586
|
+
fallback
|
|
587
|
+
}) {
|
|
588
|
+
const repeatScope = useRepeatScope();
|
|
589
|
+
const { ctx } = useVisibility();
|
|
590
|
+
const { execute } = useActions();
|
|
591
|
+
const fullCtx = useMemo5(
|
|
592
|
+
() => repeatScope ? {
|
|
593
|
+
...ctx,
|
|
594
|
+
repeatItem: repeatScope.item,
|
|
595
|
+
repeatIndex: repeatScope.index,
|
|
596
|
+
repeatBasePath: repeatScope.basePath
|
|
597
|
+
} : ctx,
|
|
598
|
+
[ctx, repeatScope]
|
|
599
|
+
);
|
|
600
|
+
const isVisible = element.visible === void 0 ? true : evaluateVisibility2(element.visible, fullCtx);
|
|
601
|
+
const onBindings = element.on;
|
|
602
|
+
const emit = useCallback4(
|
|
603
|
+
(eventName) => {
|
|
604
|
+
const binding = onBindings?.[eventName];
|
|
605
|
+
if (!binding) return;
|
|
606
|
+
const actionBindings = Array.isArray(binding) ? binding : [binding];
|
|
607
|
+
for (const b of actionBindings) {
|
|
608
|
+
if (!b.params) {
|
|
609
|
+
execute(b);
|
|
610
|
+
continue;
|
|
611
|
+
}
|
|
612
|
+
const resolved = {};
|
|
613
|
+
for (const [key, val] of Object.entries(b.params)) {
|
|
614
|
+
resolved[key] = resolveActionParam(val, fullCtx);
|
|
615
|
+
}
|
|
616
|
+
execute({ ...b, params: resolved });
|
|
617
|
+
}
|
|
618
|
+
},
|
|
619
|
+
[onBindings, execute, fullCtx]
|
|
620
|
+
);
|
|
621
|
+
if (!isVisible) {
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
const rawProps = element.props;
|
|
625
|
+
const elementBindings = resolveBindings(rawProps, fullCtx);
|
|
626
|
+
const resolvedProps = resolveElementProps(rawProps, fullCtx);
|
|
627
|
+
const resolvedElement = resolvedProps !== element.props ? { ...element, props: resolvedProps } : element;
|
|
628
|
+
const Component = registry[resolvedElement.type] ?? fallback;
|
|
629
|
+
if (!Component) {
|
|
630
|
+
console.warn(
|
|
631
|
+
`[json-render/react-email] No renderer for component type: ${resolvedElement.type}`
|
|
632
|
+
);
|
|
633
|
+
return null;
|
|
634
|
+
}
|
|
635
|
+
const children = resolvedElement.repeat ? /* @__PURE__ */ jsx6(
|
|
636
|
+
RepeatChildren,
|
|
637
|
+
{
|
|
638
|
+
element: resolvedElement,
|
|
639
|
+
spec,
|
|
640
|
+
registry,
|
|
641
|
+
loading,
|
|
642
|
+
fallback
|
|
643
|
+
}
|
|
644
|
+
) : resolvedElement.children?.map((childKey) => {
|
|
645
|
+
const childElement = spec.elements[childKey];
|
|
646
|
+
if (!childElement) {
|
|
647
|
+
if (!loading) {
|
|
648
|
+
console.warn(
|
|
649
|
+
`[json-render/react-email] Missing element "${childKey}" referenced as child of "${resolvedElement.type}".`
|
|
650
|
+
);
|
|
651
|
+
}
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
return /* @__PURE__ */ jsx6(
|
|
655
|
+
ElementRenderer2,
|
|
656
|
+
{
|
|
657
|
+
element: childElement,
|
|
658
|
+
spec,
|
|
659
|
+
registry,
|
|
660
|
+
loading,
|
|
661
|
+
fallback
|
|
662
|
+
},
|
|
663
|
+
childKey
|
|
664
|
+
);
|
|
665
|
+
});
|
|
666
|
+
return /* @__PURE__ */ jsx6(ElementErrorBoundary, { elementType: resolvedElement.type, children: /* @__PURE__ */ jsx6(
|
|
667
|
+
Component,
|
|
668
|
+
{
|
|
669
|
+
element: resolvedElement,
|
|
670
|
+
emit,
|
|
671
|
+
bindings: elementBindings,
|
|
672
|
+
loading,
|
|
673
|
+
children
|
|
674
|
+
}
|
|
675
|
+
) });
|
|
676
|
+
});
|
|
677
|
+
function RepeatChildren({
|
|
678
|
+
element,
|
|
679
|
+
spec,
|
|
680
|
+
registry,
|
|
681
|
+
loading,
|
|
682
|
+
fallback
|
|
683
|
+
}) {
|
|
684
|
+
const { state } = useStateStore();
|
|
685
|
+
const repeat = element.repeat;
|
|
686
|
+
const statePath = repeat.statePath;
|
|
687
|
+
const items = getByPath2(state, statePath) ?? [];
|
|
688
|
+
return /* @__PURE__ */ jsx6(Fragment, { children: items.map((itemValue, index) => {
|
|
689
|
+
const key = repeat.key && typeof itemValue === "object" && itemValue !== null ? String(
|
|
690
|
+
itemValue[repeat.key] ?? index
|
|
691
|
+
) : String(index);
|
|
692
|
+
return /* @__PURE__ */ jsx6(
|
|
693
|
+
RepeatScopeProvider,
|
|
694
|
+
{
|
|
695
|
+
item: itemValue,
|
|
696
|
+
index,
|
|
697
|
+
basePath: `${statePath}/${index}`,
|
|
698
|
+
children: element.children?.map((childKey) => {
|
|
699
|
+
const childElement = spec.elements[childKey];
|
|
700
|
+
if (!childElement) {
|
|
701
|
+
if (!loading) {
|
|
702
|
+
console.warn(
|
|
703
|
+
`[json-render/react-email] Missing element "${childKey}" referenced as child of "${element.type}" (repeat).`
|
|
704
|
+
);
|
|
705
|
+
}
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
return /* @__PURE__ */ jsx6(
|
|
709
|
+
ElementRenderer,
|
|
710
|
+
{
|
|
711
|
+
element: childElement,
|
|
712
|
+
spec,
|
|
713
|
+
registry,
|
|
714
|
+
loading,
|
|
715
|
+
fallback
|
|
716
|
+
},
|
|
717
|
+
childKey
|
|
718
|
+
);
|
|
719
|
+
})
|
|
720
|
+
},
|
|
721
|
+
key
|
|
722
|
+
);
|
|
723
|
+
}) });
|
|
724
|
+
}
|
|
725
|
+
function Renderer({
|
|
726
|
+
spec,
|
|
727
|
+
registry: customRegistry,
|
|
728
|
+
includeStandard = true,
|
|
729
|
+
loading,
|
|
730
|
+
fallback
|
|
731
|
+
}) {
|
|
732
|
+
const registry = useMemo5(
|
|
733
|
+
() => ({
|
|
734
|
+
...includeStandard ? standardComponents : {},
|
|
735
|
+
...customRegistry
|
|
736
|
+
}),
|
|
737
|
+
[customRegistry, includeStandard]
|
|
738
|
+
);
|
|
739
|
+
if (!spec || !spec.root) {
|
|
740
|
+
return null;
|
|
741
|
+
}
|
|
742
|
+
const rootElement = spec.elements[spec.root];
|
|
743
|
+
if (!rootElement) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
return /* @__PURE__ */ jsx6(
|
|
747
|
+
ElementRenderer,
|
|
748
|
+
{
|
|
749
|
+
element: rootElement,
|
|
750
|
+
spec,
|
|
751
|
+
registry,
|
|
752
|
+
loading,
|
|
753
|
+
fallback
|
|
754
|
+
}
|
|
755
|
+
);
|
|
756
|
+
}
|
|
757
|
+
function JSONUIProvider({
|
|
758
|
+
initialState,
|
|
759
|
+
handlers,
|
|
760
|
+
navigate,
|
|
761
|
+
validationFunctions,
|
|
762
|
+
onStateChange,
|
|
763
|
+
children
|
|
764
|
+
}) {
|
|
765
|
+
return /* @__PURE__ */ jsx6(StateProvider, { initialState, onStateChange, children: /* @__PURE__ */ jsx6(VisibilityProvider, { children: /* @__PURE__ */ jsx6(ActionProvider, { handlers, navigate, children: /* @__PURE__ */ jsx6(ValidationProvider, { customFunctions: validationFunctions, children }) }) }) });
|
|
766
|
+
}
|
|
767
|
+
function defineRegistry(_catalog, options) {
|
|
768
|
+
const registry = {};
|
|
769
|
+
if (options.components) {
|
|
770
|
+
for (const [name, componentFn] of Object.entries(options.components)) {
|
|
771
|
+
registry[name] = ({
|
|
772
|
+
element,
|
|
773
|
+
children,
|
|
774
|
+
emit,
|
|
775
|
+
bindings,
|
|
776
|
+
loading
|
|
777
|
+
}) => {
|
|
778
|
+
return componentFn({
|
|
779
|
+
props: element.props,
|
|
780
|
+
children,
|
|
781
|
+
emit,
|
|
782
|
+
bindings,
|
|
783
|
+
loading
|
|
784
|
+
});
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
return { registry };
|
|
789
|
+
}
|
|
790
|
+
function createRenderer(catalog, components) {
|
|
791
|
+
const registry = components;
|
|
792
|
+
return function CatalogRenderer({
|
|
793
|
+
spec,
|
|
794
|
+
state,
|
|
795
|
+
onAction,
|
|
796
|
+
onStateChange,
|
|
797
|
+
loading,
|
|
798
|
+
fallback
|
|
799
|
+
}) {
|
|
800
|
+
const actionHandlers = onAction ? new Proxy(
|
|
801
|
+
{},
|
|
802
|
+
{
|
|
803
|
+
get: (_target, prop) => {
|
|
804
|
+
return (params) => onAction(prop, params);
|
|
805
|
+
},
|
|
806
|
+
has: () => true
|
|
807
|
+
}
|
|
808
|
+
) : void 0;
|
|
809
|
+
return /* @__PURE__ */ jsx6(StateProvider, { initialState: state, onStateChange, children: /* @__PURE__ */ jsx6(VisibilityProvider, { children: /* @__PURE__ */ jsx6(ActionProvider, { handlers: actionHandlers, children: /* @__PURE__ */ jsx6(ValidationProvider, { children: /* @__PURE__ */ jsx6(
|
|
810
|
+
Renderer,
|
|
811
|
+
{
|
|
812
|
+
spec,
|
|
813
|
+
registry,
|
|
814
|
+
loading,
|
|
815
|
+
fallback
|
|
816
|
+
}
|
|
817
|
+
) }) }) }) });
|
|
818
|
+
};
|
|
819
|
+
}
|
|
820
|
+
export {
|
|
821
|
+
ActionProvider,
|
|
822
|
+
ConfirmDialog,
|
|
823
|
+
JSONUIProvider,
|
|
824
|
+
Renderer,
|
|
825
|
+
RepeatScopeProvider,
|
|
826
|
+
StateProvider,
|
|
827
|
+
ValidationProvider,
|
|
828
|
+
VisibilityProvider,
|
|
829
|
+
createRenderer,
|
|
830
|
+
defineRegistry,
|
|
831
|
+
renderToHtml,
|
|
832
|
+
renderToPlainText,
|
|
833
|
+
schema,
|
|
834
|
+
standardComponentDefinitions,
|
|
835
|
+
standardComponents,
|
|
836
|
+
useAction,
|
|
837
|
+
useActions,
|
|
838
|
+
useFieldValidation,
|
|
839
|
+
useIsVisible,
|
|
840
|
+
useRepeatScope,
|
|
841
|
+
useStateBinding,
|
|
842
|
+
useStateStore,
|
|
843
|
+
useStateValue,
|
|
844
|
+
useValidation,
|
|
845
|
+
useVisibility
|
|
846
|
+
};
|
|
847
|
+
//# sourceMappingURL=index.mjs.map
|