@mmapp/react 0.1.0-alpha.18 → 0.1.0-alpha.20

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.
Files changed (55) hide show
  1. package/dist/actions-HOXZPBTT.mjs +116 -0
  2. package/dist/actions-MFI2V4DX.mjs +116 -0
  3. package/dist/atoms/index.d.mts +2 -2
  4. package/dist/atoms/index.d.ts +2 -2
  5. package/dist/atoms/index.js +1 -1
  6. package/dist/atoms/index.mjs +1 -1
  7. package/dist/builtin-atoms-C-sNyYJl.d.mts +647 -0
  8. package/dist/builtin-atoms-C-sNyYJl.d.ts +647 -0
  9. package/dist/builtin-atoms-DCKrjG7i.d.mts +96 -0
  10. package/dist/builtin-atoms-DCKrjG7i.d.ts +96 -0
  11. package/dist/builtin-atoms-DRD3EwG6.d.mts +648 -0
  12. package/dist/builtin-atoms-DRD3EwG6.d.ts +648 -0
  13. package/dist/builtin-atoms-jt04b7Rw.d.mts +643 -0
  14. package/dist/builtin-atoms-jt04b7Rw.d.ts +643 -0
  15. package/dist/chunk-247T4GDJ.mjs +677 -0
  16. package/dist/chunk-3H6CR7E7.mjs +1924 -0
  17. package/dist/chunk-3PL6FL6I.mjs +96 -0
  18. package/dist/chunk-3SJSW3C4.mjs +2039 -0
  19. package/dist/chunk-5OI2VI57.mjs +1964 -0
  20. package/dist/chunk-CL6FYZ43.mjs +105 -0
  21. package/dist/chunk-ENQOCZI5.mjs +1938 -0
  22. package/dist/chunk-FB3WCZAU.mjs +512 -0
  23. package/dist/chunk-FBKUGKQI.mjs +1938 -0
  24. package/dist/chunk-GLJ7VC7Z.mjs +684 -0
  25. package/dist/chunk-HHMWR6NA.mjs +504 -0
  26. package/dist/chunk-HULEMSN2.mjs +120 -0
  27. package/dist/chunk-J5MW6CRU.mjs +1938 -0
  28. package/dist/chunk-PNTTKNYU.mjs +677 -0
  29. package/dist/chunk-TY5OTJP4.mjs +684 -0
  30. package/dist/chunk-WV7DVCP6.mjs +513 -0
  31. package/dist/chunk-YFMPTGUF.mjs +677 -0
  32. package/dist/chunk-ZAHMWAER.mjs +1960 -0
  33. package/dist/{chunk-2VJQJM7S.mjs → chunk-ZDWACXZN.mjs} +1 -1
  34. package/dist/composition-BJ6QQTWT.mjs +12 -0
  35. package/dist/composition-XBGKKCI7.mjs +57 -0
  36. package/dist/content-QVPFUG4P.mjs +246 -0
  37. package/dist/control-flow-CBREHWJW.mjs +35 -0
  38. package/dist/control-flow-FWBOI6SM.mjs +35 -0
  39. package/dist/control-flow-ZWUGCDSP.mjs +35 -0
  40. package/dist/data-WCMIZYKD.mjs +97 -0
  41. package/dist/grouping-E6F377VZ.mjs +204 -0
  42. package/dist/grouping-FRPOEXO3.mjs +233 -0
  43. package/dist/index.d.mts +4 -433
  44. package/dist/index.d.ts +4 -433
  45. package/dist/index.js +3671 -582
  46. package/dist/index.mjs +335 -1040
  47. package/dist/input-PUOZDNSI.mjs +222 -0
  48. package/dist/layout-RATDMCLP.mjs +106 -0
  49. package/dist/navigation-VCT7ZBMA.mjs +15 -0
  50. package/dist/navigation-WFV7YWOU.mjs +14 -0
  51. package/dist/player/index.d.mts +37 -11
  52. package/dist/player/index.d.ts +37 -11
  53. package/dist/player/index.js +3321 -193
  54. package/dist/player/index.mjs +55 -5
  55. package/package.json +4 -4
@@ -0,0 +1,1960 @@
1
+ import {
2
+ ScopeContext,
3
+ buildScope,
4
+ builtinFunctions,
5
+ classifyExpression,
6
+ evaluateExpression,
7
+ resolvePath,
8
+ useScope
9
+ } from "./chunk-WV7DVCP6.mjs";
10
+
11
+ // src/hooks/useQuery.ts
12
+ import { useState, useEffect, useCallback, useRef } from "react";
13
+ var _globalResolver = null;
14
+ function setQueryResolver(resolver) {
15
+ _globalResolver = resolver;
16
+ }
17
+ function useQuery(slugOrDef, params = {}) {
18
+ const slug = typeof slugOrDef === "string" ? slugOrDef : slugOrDef.slug;
19
+ const [data, setData] = useState([]);
20
+ const [loading, setLoading] = useState(true);
21
+ const [error, setError] = useState(null);
22
+ const [total, setTotal] = useState(void 0);
23
+ const paramsRef = useRef(params);
24
+ paramsRef.current = params;
25
+ const fetchData = useCallback(async () => {
26
+ if (paramsRef.current.enabled === false) {
27
+ setLoading(false);
28
+ return;
29
+ }
30
+ const resolver = _globalResolver;
31
+ if (!resolver) {
32
+ setError(new Error(`useQuery: No query resolver configured. Wrap your app in a WorkflowProvider.`));
33
+ setLoading(false);
34
+ return;
35
+ }
36
+ try {
37
+ setLoading(true);
38
+ setError(null);
39
+ const result2 = await resolver.query(slug, paramsRef.current);
40
+ setData(result2.data);
41
+ setTotal(result2.total);
42
+ } catch (err) {
43
+ setError(err instanceof Error ? err : new Error(String(err)));
44
+ } finally {
45
+ setLoading(false);
46
+ }
47
+ }, [slug]);
48
+ useEffect(() => {
49
+ fetchData();
50
+ }, [fetchData]);
51
+ useEffect(() => {
52
+ if (!params.refetchInterval || params.refetchInterval <= 0) return;
53
+ const interval = setInterval(fetchData, params.refetchInterval);
54
+ return () => clearInterval(interval);
55
+ }, [fetchData, params.refetchInterval]);
56
+ const hasMore = total !== void 0 && data.length < total;
57
+ const result = {
58
+ data,
59
+ loading,
60
+ error,
61
+ refetch: fetchData,
62
+ total,
63
+ hasMore
64
+ };
65
+ return result;
66
+ }
67
+
68
+ // src/hooks/useMutation.ts
69
+ import { useState as useState2, useCallback as useCallback2, useRef as useRef2 } from "react";
70
+ var _globalMutationResolver = null;
71
+ function setMutationResolver(resolver) {
72
+ _globalMutationResolver = resolver;
73
+ }
74
+ function useMutation(slugOrDef) {
75
+ const slug = typeof slugOrDef === "string" ? slugOrDef : slugOrDef.slug;
76
+ const [isPending, setIsPending] = useState2(false);
77
+ const [error, setError] = useState2(null);
78
+ const slugRef = useRef2(slug);
79
+ slugRef.current = slug;
80
+ const getResolver = useCallback2(() => {
81
+ const resolver = _globalMutationResolver;
82
+ if (!resolver) {
83
+ throw new Error(`useMutation: No mutation resolver configured. Wrap your app in a WorkflowProvider.`);
84
+ }
85
+ return resolver;
86
+ }, []);
87
+ const create = useCallback2(async (input) => {
88
+ try {
89
+ setIsPending(true);
90
+ setError(null);
91
+ const resolver = getResolver();
92
+ return await resolver.create(slugRef.current, input);
93
+ } catch (err) {
94
+ const e = err instanceof Error ? err : new Error(String(err));
95
+ setError(e);
96
+ throw e;
97
+ } finally {
98
+ setIsPending(false);
99
+ }
100
+ }, [getResolver]);
101
+ const update = useCallback2(async (instanceId, fields) => {
102
+ try {
103
+ setIsPending(true);
104
+ setError(null);
105
+ const resolver = getResolver();
106
+ await resolver.update(slugRef.current, instanceId, fields);
107
+ } catch (err) {
108
+ const e = err instanceof Error ? err : new Error(String(err));
109
+ setError(e);
110
+ throw e;
111
+ } finally {
112
+ setIsPending(false);
113
+ }
114
+ }, [getResolver]);
115
+ const transitionFn = useCallback2(async (instanceId, transitionName, input) => {
116
+ try {
117
+ setIsPending(true);
118
+ setError(null);
119
+ const resolver = getResolver();
120
+ await resolver.transition(slugRef.current, instanceId, transitionName, input);
121
+ } catch (err) {
122
+ const e = err instanceof Error ? err : new Error(String(err));
123
+ setError(e);
124
+ throw e;
125
+ } finally {
126
+ setIsPending(false);
127
+ }
128
+ }, [getResolver]);
129
+ const next = useCallback2(async (instanceId, input) => {
130
+ try {
131
+ setIsPending(true);
132
+ setError(null);
133
+ const resolver = getResolver();
134
+ if (resolver.next) {
135
+ await resolver.next(slugRef.current, instanceId, input);
136
+ } else {
137
+ await resolver.transition(slugRef.current, instanceId, "__next__", input);
138
+ }
139
+ } catch (err) {
140
+ const e = err instanceof Error ? err : new Error(String(err));
141
+ setError(e);
142
+ throw e;
143
+ } finally {
144
+ setIsPending(false);
145
+ }
146
+ }, [getResolver]);
147
+ const remove = useCallback2(async (instanceId) => {
148
+ try {
149
+ setIsPending(true);
150
+ setError(null);
151
+ const resolver = getResolver();
152
+ await resolver.remove(slugRef.current, instanceId);
153
+ } catch (err) {
154
+ const e = err instanceof Error ? err : new Error(String(err));
155
+ setError(e);
156
+ throw e;
157
+ } finally {
158
+ setIsPending(false);
159
+ }
160
+ }, [getResolver]);
161
+ const reset = useCallback2(() => setError(null), []);
162
+ const handle = {
163
+ create,
164
+ update,
165
+ transition: transitionFn,
166
+ trigger: transitionFn,
167
+ next,
168
+ remove,
169
+ isPending,
170
+ error,
171
+ reset
172
+ };
173
+ return handle;
174
+ }
175
+
176
+ // src/player/binding-resolver.ts
177
+ function classifyBinding(expr) {
178
+ const t = expr.trim();
179
+ const type = classifyExpression(t);
180
+ switch (type) {
181
+ case "literal":
182
+ return { type, value: parseLiteralValue(t) };
183
+ case "path": {
184
+ const dotIdx = t.indexOf(".");
185
+ if (dotIdx === -1) return { type, root: t, rest: "" };
186
+ return { type, root: t.slice(0, dotIdx), rest: t.slice(dotIdx + 1) };
187
+ }
188
+ case "function": {
189
+ const fnCall = parseFunctionCall(t);
190
+ if (fnCall) return { type, name: fnCall.name, rawArgs: fnCall.args };
191
+ return { type, expression: t };
192
+ }
193
+ case "action": {
194
+ const fnCall = parseFunctionCall(t);
195
+ if (fnCall) return { type, name: fnCall.name, rawArgs: fnCall.args };
196
+ if (t.startsWith("$action.")) return { type, name: t.slice("$action.".length), rawArgs: [] };
197
+ return { type, expression: t };
198
+ }
199
+ case "condition":
200
+ if (t.startsWith("$expr(") && t.endsWith(")")) return { type, expression: t.slice(6, -1) };
201
+ return { type, expression: t };
202
+ }
203
+ }
204
+ function parseLiteralValue(t) {
205
+ if (t === "[Expression]" || t.includes("[Expression]")) return void 0;
206
+ if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) return t.slice(1, -1);
207
+ if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t);
208
+ if (t === "true") return true;
209
+ if (t === "false") return false;
210
+ if (t === "null") return null;
211
+ return void 0;
212
+ }
213
+ function parseFunctionCall(expr) {
214
+ const match = expr.match(/^\$(fn|action)\.(\w+)\((.*)\)$/s);
215
+ if (!match) return null;
216
+ const [, namespace, name, argsStr] = match;
217
+ const args = argsStr.trim() ? splitArgs(argsStr.trim()) : [];
218
+ return { namespace, name, args };
219
+ }
220
+ function splitArgs(argsStr) {
221
+ const args = [];
222
+ let current = "";
223
+ let depth = 0;
224
+ let inString = null;
225
+ for (let i = 0; i < argsStr.length; i++) {
226
+ const ch = argsStr[i];
227
+ if (inString) {
228
+ current += ch;
229
+ if (ch === inString && argsStr[i - 1] !== "\\") inString = null;
230
+ } else if (ch === '"' || ch === "'") {
231
+ current += ch;
232
+ inString = ch;
233
+ } else if (ch === "(" || ch === "[") {
234
+ current += ch;
235
+ depth++;
236
+ } else if (ch === ")" || ch === "]") {
237
+ current += ch;
238
+ depth--;
239
+ } else if (ch === "," && depth === 0) {
240
+ args.push(current.trim());
241
+ current = "";
242
+ } else {
243
+ current += ch;
244
+ }
245
+ }
246
+ if (current.trim()) args.push(current.trim());
247
+ return args;
248
+ }
249
+ function resolveBinding(expr, scope) {
250
+ const binding = classifyBinding(expr);
251
+ switch (binding.type) {
252
+ case "literal":
253
+ return binding.value;
254
+ case "path":
255
+ return resolveScopedPath(binding.root, binding.rest, scope);
256
+ case "function":
257
+ return resolveFunction(binding.name, binding.rawArgs, scope);
258
+ case "action":
259
+ return resolveAction(binding.name, binding.rawArgs, scope);
260
+ case "condition":
261
+ return resolveCondition(binding.expression ?? expr, scope);
262
+ default:
263
+ return void 0;
264
+ }
265
+ }
266
+ function resolveAllBindings(bindings, scope) {
267
+ const resolved = {};
268
+ for (const [propName, expr] of Object.entries(bindings)) {
269
+ try {
270
+ resolved[propName] = resolveBinding(expr, scope);
271
+ } catch {
272
+ resolved[propName] = void 0;
273
+ }
274
+ }
275
+ return resolved;
276
+ }
277
+ function resolveScopedPath(root, rest, scope) {
278
+ let rootValue;
279
+ switch (root) {
280
+ case "$instance":
281
+ rootValue = scope.$instance;
282
+ break;
283
+ case "$instances":
284
+ rootValue = scope.$instances;
285
+ break;
286
+ case "$definition":
287
+ rootValue = scope.$definition;
288
+ break;
289
+ case "$pagination":
290
+ rootValue = scope.$pagination;
291
+ break;
292
+ case "$entity":
293
+ rootValue = scope.$entity;
294
+ break;
295
+ case "$local":
296
+ rootValue = scope.$local;
297
+ break;
298
+ case "$user":
299
+ rootValue = scope.$user;
300
+ break;
301
+ case "$action":
302
+ rootValue = scope.$action;
303
+ break;
304
+ case "$fn":
305
+ rootValue = scope.$fn;
306
+ break;
307
+ case "$item":
308
+ rootValue = scope.$item;
309
+ break;
310
+ case "$index":
311
+ rootValue = scope.$index;
312
+ break;
313
+ default:
314
+ rootValue = scope[root];
315
+ if (rootValue === void 0) {
316
+ rootValue = scope.$item;
317
+ if (rootValue != null && rest) {
318
+ return resolvePath(`${root}.${rest}`, { [root]: scope.$item });
319
+ }
320
+ }
321
+ }
322
+ if (!rest) return rootValue;
323
+ if (rootValue == null) return void 0;
324
+ return resolvePath(rest, rootValue);
325
+ }
326
+ function resolveFunction(name, rawArgs, scope) {
327
+ const fn = scope.$fn?.[name] ?? builtinFunctions[name];
328
+ if (typeof fn !== "function") {
329
+ console.warn(`[binding-resolver] Unknown function: $fn.${name}`);
330
+ return void 0;
331
+ }
332
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
333
+ try {
334
+ return fn(...resolvedArgs);
335
+ } catch (err) {
336
+ console.warn(`[binding-resolver] Error calling $fn.${name}:`, err);
337
+ return void 0;
338
+ }
339
+ }
340
+ function resolveAction(name, rawArgs, scope) {
341
+ const actions = scope.$action;
342
+ if (!actions) return void 0;
343
+ if (rawArgs.length === 0) {
344
+ const actionFn2 = actions[name];
345
+ if (typeof actionFn2 === "function") return actionFn2;
346
+ return void 0;
347
+ }
348
+ const actionFn = actions[name];
349
+ if (typeof actionFn !== "function") return void 0;
350
+ return (...callArgs) => {
351
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
352
+ return actionFn(...resolvedArgs, ...callArgs);
353
+ };
354
+ }
355
+ function resolveCondition(expression, scope) {
356
+ const context = buildEvalContext(scope);
357
+ return evaluateExpression(expression, context);
358
+ }
359
+ function buildEvalContext(scope) {
360
+ const ctx = {};
361
+ ctx.$instance = scope.$instance;
362
+ ctx.$instances = scope.$instances;
363
+ ctx.$definition = scope.$definition;
364
+ ctx.$pagination = scope.$pagination;
365
+ ctx.$entity = scope.$entity;
366
+ ctx.$local = scope.$local;
367
+ ctx.$user = scope.$user;
368
+ ctx.$action = scope.$action;
369
+ ctx.$fn = scope.$fn;
370
+ ctx.$item = scope.$item;
371
+ ctx.$index = scope.$index;
372
+ if (scope.$instances) ctx.items = scope.$instances;
373
+ if (scope.$instance) {
374
+ ctx.instance = scope.$instance;
375
+ ctx.loading = false;
376
+ }
377
+ if (scope.$item) ctx.item = scope.$item;
378
+ if (scope.$index != null) ctx.index = scope.$index;
379
+ if (scope.state_data) ctx.state_data = scope.state_data;
380
+ if (scope.memory) ctx.memory = scope.memory;
381
+ if (scope.context) ctx.context = scope.context;
382
+ return ctx;
383
+ }
384
+ function buildActionScope(opts) {
385
+ const { resolver, instanceId, slug, setLocal, router, toast, refreshQuery, onEvent } = opts;
386
+ return {
387
+ transition: async (name, id, data) => {
388
+ const targetId = id ?? instanceId;
389
+ if (!targetId) {
390
+ console.warn("[action] transition called without instanceId");
391
+ return;
392
+ }
393
+ await resolver.transition(targetId, name, data);
394
+ refreshQuery?.();
395
+ },
396
+ create: async (targetSlug, data) => {
397
+ const id = await resolver.create(targetSlug || slug || "", data);
398
+ refreshQuery?.();
399
+ return id;
400
+ },
401
+ update: async (id, fields) => {
402
+ await resolver.update(id, fields);
403
+ refreshQuery?.();
404
+ },
405
+ remove: async (id) => {
406
+ await resolver.remove(id);
407
+ refreshQuery?.();
408
+ },
409
+ setLocal: (key, value) => {
410
+ setLocal(key, value);
411
+ },
412
+ navigate: (path) => {
413
+ router?.push(path);
414
+ },
415
+ toast: (message, variant) => {
416
+ toast?.(message, variant);
417
+ },
418
+ refreshQuery: (dataSourceName) => {
419
+ refreshQuery?.(dataSourceName);
420
+ },
421
+ scrollTo: (elementId) => {
422
+ if (typeof document !== "undefined") {
423
+ const el = document.getElementById(elementId);
424
+ el?.scrollIntoView({ behavior: "smooth" });
425
+ }
426
+ },
427
+ openModal: (modalId) => {
428
+ if (typeof window !== "undefined") {
429
+ window.dispatchEvent(new CustomEvent("player:open_modal", { detail: { id: modalId } }));
430
+ }
431
+ },
432
+ closeModal: (modalId) => {
433
+ if (typeof window !== "undefined") {
434
+ window.dispatchEvent(new CustomEvent("player:close_modal", { detail: { id: modalId } }));
435
+ }
436
+ },
437
+ emit: (event, payload) => {
438
+ onEvent?.(event, payload);
439
+ }
440
+ };
441
+ }
442
+
443
+ // src/player/atom-registry.ts
444
+ import React from "react";
445
+ function namedExport(loader, exportName) {
446
+ return () => loader().then((mod) => ({ default: mod[exportName] }));
447
+ }
448
+ var AtomRegistryImpl = class _AtomRegistryImpl {
449
+ loaders = /* @__PURE__ */ new Map();
450
+ lazyCache = /* @__PURE__ */ new Map();
451
+ eagerCache = /* @__PURE__ */ new Map();
452
+ register(name, loader) {
453
+ this.loaders.set(name, loader);
454
+ this.lazyCache.delete(name);
455
+ }
456
+ registerEager(name, component) {
457
+ this.eagerCache.set(name, component);
458
+ }
459
+ resolve(name) {
460
+ const eager = this.eagerCache.get(name);
461
+ if (eager) {
462
+ const cached2 = this.lazyCache.get(name);
463
+ if (cached2) return cached2;
464
+ const lazy2 = React.lazy(() => Promise.resolve({ default: eager }));
465
+ this.lazyCache.set(name, lazy2);
466
+ return lazy2;
467
+ }
468
+ const cached = this.lazyCache.get(name);
469
+ if (cached) return cached;
470
+ const loader = this.loaders.get(name);
471
+ if (!loader) return null;
472
+ const lazy = React.lazy(loader);
473
+ this.lazyCache.set(name, lazy);
474
+ return lazy;
475
+ }
476
+ resolveSync(name) {
477
+ return this.eagerCache.get(name) ?? null;
478
+ }
479
+ has(name) {
480
+ return this.loaders.has(name) || this.eagerCache.has(name);
481
+ }
482
+ list() {
483
+ const names = /* @__PURE__ */ new Set();
484
+ for (const k of this.loaders.keys()) names.add(k);
485
+ for (const k of this.eagerCache.keys()) names.add(k);
486
+ return Array.from(names).sort();
487
+ }
488
+ merge(other) {
489
+ const merged = new _AtomRegistryImpl();
490
+ for (const [name, loader] of this.loaders) merged.loaders.set(name, loader);
491
+ for (const [name, comp] of this.eagerCache) merged.eagerCache.set(name, comp);
492
+ for (const name of other.list()) {
493
+ const otherImpl = other;
494
+ if (otherImpl.loaders?.has(name)) {
495
+ merged.loaders.set(name, otherImpl.loaders.get(name));
496
+ }
497
+ if (otherImpl.eagerCache?.has(name)) {
498
+ merged.eagerCache.set(name, otherImpl.eagerCache.get(name));
499
+ }
500
+ }
501
+ return merged;
502
+ }
503
+ toRecord() {
504
+ const record = {};
505
+ for (const name of this.eagerCache.keys()) {
506
+ record[name] = this.eagerCache.get(name);
507
+ }
508
+ return record;
509
+ }
510
+ };
511
+ function createCoreAtomRegistry() {
512
+ const registry = new AtomRegistryImpl();
513
+ registry.register("Stack", namedExport(() => import("./layout-RATDMCLP.mjs"), "Stack"));
514
+ registry.register("Row", namedExport(() => import("./layout-RATDMCLP.mjs"), "Row"));
515
+ registry.register("Grid", namedExport(() => import("./layout-RATDMCLP.mjs"), "Grid"));
516
+ registry.register("Column", namedExport(() => import("./layout-RATDMCLP.mjs"), "Column"));
517
+ registry.register("Divider", namedExport(() => import("./layout-RATDMCLP.mjs"), "Divider"));
518
+ registry.register("Spacer", namedExport(() => import("./layout-RATDMCLP.mjs"), "Spacer"));
519
+ registry.register("Text", namedExport(() => import("./content-QVPFUG4P.mjs"), "Text"));
520
+ registry.register("Heading", namedExport(() => import("./content-QVPFUG4P.mjs"), "Heading"));
521
+ registry.register("Field", namedExport(() => import("./content-QVPFUG4P.mjs"), "Field"));
522
+ registry.register("Image", namedExport(() => import("./content-QVPFUG4P.mjs"), "Image"));
523
+ registry.register("Badge", namedExport(() => import("./content-QVPFUG4P.mjs"), "Badge"));
524
+ registry.register("Icon", namedExport(() => import("./content-QVPFUG4P.mjs"), "Icon"));
525
+ registry.register("Button", namedExport(() => import("./actions-HOXZPBTT.mjs"), "Button"));
526
+ registry.register("Link", namedExport(() => import("./actions-HOXZPBTT.mjs"), "Link"));
527
+ registry.register("Show", namedExport(() => import("./control-flow-ZWUGCDSP.mjs"), "Show"));
528
+ registry.register("Each", namedExport(() => import("./control-flow-ZWUGCDSP.mjs"), "Each"));
529
+ registry.register("TextInput", namedExport(() => import("./input-PUOZDNSI.mjs"), "TextInput"));
530
+ registry.register("Input", namedExport(() => import("./input-PUOZDNSI.mjs"), "TextInput"));
531
+ registry.register("Select", namedExport(() => import("./input-PUOZDNSI.mjs"), "Select"));
532
+ registry.register("Toggle", namedExport(() => import("./input-PUOZDNSI.mjs"), "Toggle"));
533
+ registry.register("Slider", namedExport(() => import("./input-PUOZDNSI.mjs"), "Slider"));
534
+ registry.register("Card", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "Card"));
535
+ registry.register("Section", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "Section"));
536
+ registry.register("Tabs", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "Tabs"));
537
+ registry.register("Accordion", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "Accordion"));
538
+ registry.register("Modal", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "Modal"));
539
+ registry.register("Router", namedExport(() => import("./navigation-VCT7ZBMA.mjs"), "Router"));
540
+ registry.register("Route", namedExport(() => import("./navigation-VCT7ZBMA.mjs"), "Route"));
541
+ registry.register("NavLink", namedExport(() => import("./navigation-VCT7ZBMA.mjs"), "NavLink"));
542
+ registry.register("RoleGuard", namedExport(() => import("./navigation-VCT7ZBMA.mjs"), "RoleGuard"));
543
+ registry.register("Slot", namedExport(() => import("./composition-BJ6QQTWT.mjs"), "Slot"));
544
+ registry.register("ModuleOutlet", namedExport(() => import("./composition-BJ6QQTWT.mjs"), "ModuleOutlet"));
545
+ registry.register("Markdown", namedExport(() => import("./content-QVPFUG4P.mjs"), "Markdown"));
546
+ registry.register("ScrollArea", namedExport(() => import("./grouping-FRPOEXO3.mjs"), "ScrollArea"));
547
+ registry.register("Table", namedExport(() => import("./data-WCMIZYKD.mjs"), "Table"));
548
+ registry.register("DataGrid", namedExport(() => import("./data-WCMIZYKD.mjs"), "DataGrid"));
549
+ registry.register("Alert", namedExport(() => import("./content-QVPFUG4P.mjs"), "Alert"));
550
+ registry.register("EmptyState", namedExport(() => import("./content-QVPFUG4P.mjs"), "EmptyState"));
551
+ registry.register("Progress", namedExport(() => import("./content-QVPFUG4P.mjs"), "Progress"));
552
+ registry.register("Separator", namedExport(() => import("./content-QVPFUG4P.mjs"), "Separator"));
553
+ return registry;
554
+ }
555
+ function mergeRegistries(...registries) {
556
+ let merged = new AtomRegistryImpl();
557
+ for (const r of registries) {
558
+ merged = merged.merge(r);
559
+ }
560
+ return merged;
561
+ }
562
+
563
+ // src/player/theme.ts
564
+ var DEFAULT_DESIGN_TOKENS = {
565
+ // Colors
566
+ "token:primary": "#3182ce",
567
+ "token:primary-hover": "#2b6cb0",
568
+ "token:primary-light": "#ebf8ff",
569
+ "token:secondary": "#718096",
570
+ "token:secondary-hover": "#4a5568",
571
+ "token:accent": "#805ad5",
572
+ "token:success": "#38a169",
573
+ "token:warning": "#dd6b20",
574
+ "token:error": "#e53e3e",
575
+ "token:info": "#3182ce",
576
+ // Surfaces
577
+ "token:surface": "#ffffff",
578
+ "token:surface-hover": "#f7fafc",
579
+ "token:surface-secondary": "#edf2f7",
580
+ "token:background": "#f7fafc",
581
+ "token:card": "#ffffff",
582
+ "token:overlay": "rgba(0, 0, 0, 0.4)",
583
+ // Borders
584
+ "token:border": "#e2e8f0",
585
+ "token:border-light": "#edf2f7",
586
+ "token:border-focus": "#3182ce",
587
+ // Text
588
+ "token:text": "#1a202c",
589
+ "token:text-secondary": "#718096",
590
+ "token:text-muted": "#a0aec0",
591
+ "token:text-inverse": "#ffffff",
592
+ "token:text-link": "#3182ce",
593
+ // Shadows
594
+ "token:shadow-sm": "0 1px 2px rgba(0, 0, 0, 0.05)",
595
+ "token:shadow": "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06)",
596
+ "token:shadow-md": "0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)",
597
+ "token:shadow-lg": "0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05)",
598
+ // Spacing
599
+ "token:spacing-xs": "4px",
600
+ "token:spacing-sm": "8px",
601
+ "token:spacing-md": "16px",
602
+ "token:spacing-lg": "24px",
603
+ "token:spacing-xl": "32px",
604
+ // Radius
605
+ "token:radius-sm": "4px",
606
+ "token:radius": "6px",
607
+ "token:radius-md": "8px",
608
+ "token:radius-lg": "12px",
609
+ "token:radius-full": "9999px"
610
+ };
611
+
612
+ // src/player/PlayerProvider.tsx
613
+ import { createContext, useContext, useEffect as useEffect2, useMemo, useRef as useRef3 } from "react";
614
+ import { jsx } from "react/jsx-runtime";
615
+ var PlayerContext = createContext(null);
616
+ function usePlayerContext() {
617
+ return useContext(PlayerContext);
618
+ }
619
+ var ThemeContext = createContext(DEFAULT_DESIGN_TOKENS);
620
+ function useTheme() {
621
+ return useContext(ThemeContext);
622
+ }
623
+ var PlayerProvider = ({
624
+ resolver,
625
+ atomRegistry: userAtomRegistry,
626
+ auth,
627
+ router,
628
+ toast,
629
+ onEvent,
630
+ theme: userTheme,
631
+ children
632
+ }) => {
633
+ const atomRegistry = useMemo(
634
+ () => userAtomRegistry ?? createCoreAtomRegistry(),
635
+ [userAtomRegistry]
636
+ );
637
+ const mergedTheme = useMemo(
638
+ () => userTheme ? { ...DEFAULT_DESIGN_TOKENS, ...userTheme } : DEFAULT_DESIGN_TOKENS,
639
+ [userTheme]
640
+ );
641
+ const resolverRef = useRef3(resolver);
642
+ resolverRef.current = resolver;
643
+ useEffect2(() => {
644
+ if (!resolver) return;
645
+ setQueryResolver({
646
+ query: async (_slug, params) => {
647
+ const r = resolverRef.current;
648
+ if (!r) return { data: [] };
649
+ const result = await r.query(_slug, {
650
+ state: params.state,
651
+ filter: params.filter,
652
+ limit: params.limit,
653
+ offset: params.offset,
654
+ search: params.search,
655
+ searchFields: params.searchFields,
656
+ sort: params.sort
657
+ });
658
+ return { data: result.data, total: result.total };
659
+ }
660
+ });
661
+ setMutationResolver({
662
+ create: async (_slug, input) => {
663
+ const r = resolverRef.current;
664
+ if (!r) throw new Error("No resolver");
665
+ return r.create(_slug, input);
666
+ },
667
+ update: async (_slug, instanceId, fields) => {
668
+ const r = resolverRef.current;
669
+ if (!r) throw new Error("No resolver");
670
+ await r.update(instanceId, fields);
671
+ },
672
+ transition: async (_slug, instanceId, transitionName, input) => {
673
+ const r = resolverRef.current;
674
+ if (!r) throw new Error("No resolver");
675
+ await r.transition(instanceId, transitionName, input);
676
+ },
677
+ remove: async (_slug, instanceId) => {
678
+ const r = resolverRef.current;
679
+ if (!r) throw new Error("No resolver");
680
+ await r.remove(instanceId);
681
+ }
682
+ });
683
+ return () => {
684
+ setQueryResolver(null);
685
+ setMutationResolver(null);
686
+ };
687
+ }, [resolver]);
688
+ const value = useMemo(() => ({
689
+ resolver: resolver ?? null,
690
+ atomRegistry,
691
+ auth,
692
+ router,
693
+ toast,
694
+ onEvent
695
+ }), [resolver, atomRegistry, auth, router, toast, onEvent]);
696
+ return /* @__PURE__ */ jsx(PlayerContext.Provider, { value, children: /* @__PURE__ */ jsx(ThemeContext.Provider, { value: mergedTheme, children }) });
697
+ };
698
+
699
+ // src/player/ExperienceRenderer.tsx
700
+ import React3, {
701
+ useState as useState3,
702
+ useEffect as useEffect3,
703
+ useCallback as useCallback3,
704
+ useMemo as useMemo2,
705
+ useRef as useRef4,
706
+ Suspense
707
+ } from "react";
708
+ import { jsx as jsx2, jsxs } from "react/jsx-runtime";
709
+ var SharedLocalContext = React3.createContext({
710
+ state: {},
711
+ setLocal: () => {
712
+ }
713
+ });
714
+ function useSharedLocal() {
715
+ return React3.useContext(SharedLocalContext);
716
+ }
717
+ var NodeErrorBoundary = class extends React3.Component {
718
+ constructor(props) {
719
+ super(props);
720
+ this.state = { hasError: false };
721
+ }
722
+ static getDerivedStateFromError(error) {
723
+ return { hasError: true, error };
724
+ }
725
+ componentDidCatch(error, info) {
726
+ console.error(`[ExperienceRenderer] Error in node ${this.props.nodeId}:`, error, info);
727
+ }
728
+ render() {
729
+ if (this.state.hasError) {
730
+ return this.props.fallback ?? /* @__PURE__ */ jsxs("div", { style: { padding: 8, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 6, fontSize: 12, color: "#c53030" }, children: [
731
+ "Error: ",
732
+ this.state.error?.message ?? "Render failed"
733
+ ] });
734
+ }
735
+ return this.props.children;
736
+ }
737
+ };
738
+ function useDataSources(dataSources, resolver, scope) {
739
+ const [results, setResults] = useState3({});
740
+ const mountedRef = useRef4(true);
741
+ useEffect3(() => {
742
+ mountedRef.current = true;
743
+ return () => {
744
+ mountedRef.current = false;
745
+ };
746
+ }, []);
747
+ useEffect3(() => {
748
+ if (!dataSources?.length || !resolver) return;
749
+ const loading = {};
750
+ for (const ds of dataSources) {
751
+ loading[ds.name] = { loading: true, error: null };
752
+ }
753
+ setResults(loading);
754
+ const fetchAll = async () => {
755
+ const entries = await Promise.all(
756
+ dataSources.map(async (ds) => {
757
+ try {
758
+ const result = await fetchDataSource(ds, resolver, scope);
759
+ return [ds.name, result];
760
+ } catch (err) {
761
+ return [ds.name, { loading: false, error: err instanceof Error ? err : new Error(String(err)) }];
762
+ }
763
+ })
764
+ );
765
+ if (mountedRef.current) {
766
+ setResults(Object.fromEntries(entries));
767
+ }
768
+ };
769
+ fetchAll();
770
+ }, [dataSources, resolver]);
771
+ return results;
772
+ }
773
+ async function fetchDataSource(ds, resolver, scope) {
774
+ switch (ds.type) {
775
+ case "workflow": {
776
+ const slug = ds.slug ?? "";
777
+ if (!slug) return { loading: false, error: new Error("workflow dataSource missing slug") };
778
+ const queryResult = await resolver.query(slug, {
779
+ state: ds.filter?.current_state,
780
+ filter: ds.filter,
781
+ limit: ds.pageSize ?? 20,
782
+ page: scope.$local?.[ds.pageKey ?? "page"] ?? 1,
783
+ search: ds.search ? interpolateTemplate(ds.search, scope) : void 0,
784
+ searchFields: ds.searchFields,
785
+ sort: ds.sort,
786
+ facets: ds.facets,
787
+ entity: ds.entity,
788
+ includeDefinition: ds.includeDefinition,
789
+ parentInstanceId: ds.parentInstanceId ? interpolateTemplate(ds.parentInstanceId, scope) : void 0
790
+ });
791
+ const result = {
792
+ instances: queryResult.data,
793
+ loading: false,
794
+ error: null
795
+ };
796
+ if (queryResult.data.length === 1 && ds.query !== "list") {
797
+ result.instance = queryResult.data[0];
798
+ }
799
+ if (queryResult.definition) result.definition = queryResult.definition;
800
+ if (queryResult.total != null) {
801
+ result.pagination = {
802
+ total: queryResult.total,
803
+ page: queryResult.page,
804
+ pageSize: queryResult.pageSize
805
+ };
806
+ }
807
+ if (queryResult.facets) result.facets = queryResult.facets;
808
+ if (queryResult.aggregates) result.aggregates = queryResult.aggregates;
809
+ if (ds.autoStart && queryResult.data.length === 0) {
810
+ try {
811
+ const id = await resolver.create(slug, ds.initialData);
812
+ const instance = await resolver.getInstance(id);
813
+ result.instance = instance;
814
+ result.instances = [instance];
815
+ } catch {
816
+ }
817
+ }
818
+ return result;
819
+ }
820
+ case "api": {
821
+ if (!resolver.fetch) return { loading: false, error: new Error("API datasource: resolver.fetch not implemented") };
822
+ const endpoint = interpolateTemplate(ds.endpoint, scope);
823
+ const raw = await resolver.fetch(endpoint, {
824
+ method: ds.method,
825
+ body: ds.body,
826
+ headers: ds.headers
827
+ });
828
+ const mapped = mapApiResponse(raw, ds.mapping);
829
+ return { instances: mapped.items, loading: false, error: null, pagination: mapped.pagination };
830
+ }
831
+ case "static": {
832
+ const data = ds.data;
833
+ if (Array.isArray(data)) {
834
+ return {
835
+ instances: data.map((d, i) => ({
836
+ id: String(d.id ?? i),
837
+ state: "static",
838
+ fields: d
839
+ })),
840
+ loading: false,
841
+ error: null
842
+ };
843
+ }
844
+ return {
845
+ instance: { id: "static", state: "static", fields: data },
846
+ loading: false,
847
+ error: null
848
+ };
849
+ }
850
+ case "ref": {
851
+ const ctx = buildEvalContext(scope);
852
+ const resolved = evaluateExpression(ds.expression, ctx);
853
+ if (Array.isArray(resolved)) {
854
+ return {
855
+ instances: resolved.map((item, i) => ({
856
+ id: String(item?.id ?? i),
857
+ state: String(item?.state ?? "ref"),
858
+ fields: item && typeof item === "object" ? item : { value: item }
859
+ })),
860
+ loading: false,
861
+ error: null
862
+ };
863
+ }
864
+ if (resolved != null && typeof resolved === "object") {
865
+ const obj = resolved;
866
+ return {
867
+ instance: {
868
+ id: String(obj.id ?? "ref"),
869
+ state: String(obj.state ?? "ref"),
870
+ fields: obj
871
+ },
872
+ loading: false,
873
+ error: null
874
+ };
875
+ }
876
+ return { loading: false, error: null };
877
+ }
878
+ default:
879
+ return { loading: false, error: new Error(`Unknown dataSource type: ${ds.type}`) };
880
+ }
881
+ }
882
+ function interpolateTemplate(template, scope) {
883
+ return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
884
+ const val = resolveBinding(`$${path}`, scope) ?? resolveBinding(path, scope);
885
+ return val != null ? String(val) : "";
886
+ });
887
+ }
888
+ function mapApiResponse(raw, mapping) {
889
+ if (!raw || typeof raw !== "object") return { items: [] };
890
+ const obj = raw;
891
+ let items;
892
+ if (mapping?.items || mapping?.data) {
893
+ items = obj[mapping.items ?? mapping.data ?? "data"] ?? [];
894
+ } else if (Array.isArray(raw)) {
895
+ items = raw;
896
+ } else if (Array.isArray(obj.data)) {
897
+ items = obj.data;
898
+ } else if (Array.isArray(obj.items)) {
899
+ items = obj.items;
900
+ } else {
901
+ items = [raw];
902
+ }
903
+ const result = items.map((item, i) => ({
904
+ id: String(item?.id ?? i),
905
+ state: String(item?.state ?? "unknown"),
906
+ fields: item ?? {}
907
+ }));
908
+ let pagination;
909
+ const total = mapping?.total ? obj[mapping.total] : obj.total;
910
+ if (total != null) {
911
+ pagination = { total: Number(total), page: Number(obj.page ?? 1), pageSize: Number(obj.pageSize ?? items.length) };
912
+ }
913
+ return { items: result, pagination };
914
+ }
915
+ function resolveTokens(value, tokens) {
916
+ if (typeof value === "string" && value.startsWith("token:")) {
917
+ return tokens[value] ?? value;
918
+ }
919
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
920
+ const resolved = {};
921
+ for (const [k, v] of Object.entries(value)) {
922
+ resolved[k] = resolveTokens(v, tokens);
923
+ }
924
+ return resolved;
925
+ }
926
+ return value;
927
+ }
928
+ var NodeRenderer = ({ node, fallback }) => {
929
+ const parentScope = useScope();
930
+ const playerCtx = usePlayerContext();
931
+ const resolver = playerCtx?.resolver ?? null;
932
+ const atomRegistry = playerCtx?.atomRegistry;
933
+ const themeTokens = useTheme();
934
+ const sharedLocal = useSharedLocal();
935
+ const localDefaults = node.config?.localDefaults ?? {};
936
+ useEffect3(() => {
937
+ if (Object.keys(localDefaults).length > 0) {
938
+ for (const [key, value] of Object.entries(localDefaults)) {
939
+ if (sharedLocal.state[key] === void 0) {
940
+ sharedLocal.setLocal(key, value);
941
+ }
942
+ }
943
+ }
944
+ }, []);
945
+ const localState = sharedLocal.state;
946
+ const handleSetLocal = sharedLocal.setLocal;
947
+ const [, setFetchVersion] = useState3(0);
948
+ const handleRefreshQuery = useCallback3(() => {
949
+ setFetchVersion((v) => v + 1);
950
+ }, []);
951
+ const dsResults = useDataSources(node.dataSources, resolver, parentScope);
952
+ const primaryInstance = Object.values(dsResults).find((r) => r.instance)?.instance;
953
+ const primarySlug = node.dataSources?.find((ds) => ds.type === "workflow")?.slug;
954
+ const actionScope = useMemo2(() => {
955
+ if (!resolver) {
956
+ return {
957
+ transition: async () => {
958
+ },
959
+ create: async () => "",
960
+ update: async () => {
961
+ },
962
+ remove: async () => {
963
+ },
964
+ setLocal: handleSetLocal,
965
+ navigate: () => {
966
+ },
967
+ toast: () => {
968
+ },
969
+ refreshQuery: handleRefreshQuery,
970
+ scrollTo: () => {
971
+ },
972
+ openModal: () => {
973
+ },
974
+ closeModal: () => {
975
+ },
976
+ emit: () => {
977
+ }
978
+ };
979
+ }
980
+ return buildActionScope({
981
+ resolver,
982
+ instanceId: primaryInstance?.id,
983
+ slug: primarySlug,
984
+ setLocal: handleSetLocal,
985
+ router: playerCtx?.router,
986
+ toast: playerCtx?.toast,
987
+ refreshQuery: handleRefreshQuery,
988
+ onEvent: playerCtx?.onEvent
989
+ });
990
+ }, [resolver, primaryInstance?.id, primarySlug, handleSetLocal, handleRefreshQuery, playerCtx]);
991
+ const scope = useMemo2(() => buildScope({
992
+ dataSources: dsResults,
993
+ localState,
994
+ auth: playerCtx?.auth,
995
+ entity: node.dataSources?.find((ds) => ds.type === "workflow")?.entity,
996
+ parentScope,
997
+ actionScope
998
+ }), [dsResults, localState, parentScope, actionScope, playerCtx?.auth]);
999
+ const enrichedScope = useMemo2(() => {
1000
+ const handleCreate = () => {
1001
+ if (primarySlug && resolver) {
1002
+ resolver.create(primarySlug).then(() => handleRefreshQuery());
1003
+ }
1004
+ };
1005
+ const setSearch = (e) => {
1006
+ const val = typeof e === "object" && e !== null && "target" in e ? e.target.value : String(e ?? "");
1007
+ handleSetLocal("search", val);
1008
+ };
1009
+ const enrichedAction = {
1010
+ ...scope.$action,
1011
+ handleCreate,
1012
+ setSearch
1013
+ };
1014
+ const enrichedInstance = scope.$instance ? { ...scope.$instance, handleCreate, setSearch } : void 0;
1015
+ return {
1016
+ ...scope,
1017
+ $action: enrichedAction,
1018
+ $instance: enrichedInstance,
1019
+ // Also add at top-level for direct access
1020
+ handleCreate,
1021
+ setSearch
1022
+ };
1023
+ }, [scope, primarySlug, resolver, handleRefreshQuery, handleSetLocal]);
1024
+ if (node.visible_when) {
1025
+ const ctx = buildEvalContext(enrichedScope);
1026
+ const visible = evaluateExpression(node.visible_when, ctx);
1027
+ if (!visible) return null;
1028
+ }
1029
+ if (node.$if) {
1030
+ const ctx = buildEvalContext(enrichedScope);
1031
+ const visible = evaluateExpression(node.$if, ctx);
1032
+ if (!visible) return null;
1033
+ }
1034
+ const resolvedBindings = node.bindings ? resolveAllBindings(node.bindings, enrichedScope) : {};
1035
+ const config = node.config ?? node.props ?? {};
1036
+ const rawMerged = { ...config, ...resolvedBindings };
1037
+ const mergedProps = {};
1038
+ for (const [k, v] of Object.entries(rawMerged)) {
1039
+ mergedProps[k] = resolveTokens(v, themeTokens);
1040
+ }
1041
+ if (node.className) mergedProps.className = node.className;
1042
+ if (node.id) mergedProps["data-node-id"] = node.id;
1043
+ const loadingAny = Object.values(dsResults).some((r) => r.loading);
1044
+ if (Object.keys(dsResults).length > 0) {
1045
+ mergedProps.loading = loadingAny;
1046
+ const firstResult = Object.values(dsResults)[0];
1047
+ if (firstResult?.instances) mergedProps.data = firstResult.instances;
1048
+ if (firstResult?.instance) mergedProps.instance = firstResult.instance;
1049
+ if (firstResult?.pagination) mergedProps.pagination = firstResult.pagination;
1050
+ if (firstResult?.definition) mergedProps.definition = firstResult.definition;
1051
+ }
1052
+ const componentName = node.component ?? node.type ?? "";
1053
+ let AtomComponent = null;
1054
+ if (atomRegistry) {
1055
+ const lazy = atomRegistry.resolve(componentName);
1056
+ if (lazy) AtomComponent = lazy;
1057
+ }
1058
+ if (!AtomComponent) {
1059
+ if (!componentName && node.children?.length) {
1060
+ return /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ jsx2("div", { className: node.className, style: node.style, children: node.children.map((child, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node: child, fallback }) }, child.id ?? i)) }) });
1061
+ }
1062
+ if (componentName) {
1063
+ return /* @__PURE__ */ jsxs("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
1064
+ "Unknown: ",
1065
+ componentName
1066
+ ] });
1067
+ }
1068
+ return null;
1069
+ }
1070
+ let children = null;
1071
+ if (node.children?.length) {
1072
+ children = node.children.map((child, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node: child, fallback }) }, child.id ?? i));
1073
+ }
1074
+ if (!children && mergedProps.children != null) {
1075
+ children = mergedProps.children;
1076
+ delete mergedProps.children;
1077
+ }
1078
+ delete mergedProps.localDefaults;
1079
+ delete mergedProps.dataSources;
1080
+ delete mergedProps.bindings;
1081
+ delete mergedProps.visible_when;
1082
+ return /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: node.id, fallback, children: /* @__PURE__ */ jsx2(Suspense, { fallback: /* @__PURE__ */ jsxs("div", { style: { padding: 8, color: "#a0aec0", fontSize: 13 }, children: [
1083
+ "Loading ",
1084
+ componentName,
1085
+ "..."
1086
+ ] }), children: /* @__PURE__ */ jsx2(AtomComponent, { ...mergedProps, children }) }) }) });
1087
+ };
1088
+ var ExperienceRenderer = ({
1089
+ tree,
1090
+ initialScope,
1091
+ entity,
1092
+ fallback,
1093
+ className
1094
+ }) => {
1095
+ const playerCtx = usePlayerContext();
1096
+ const nodes = Array.isArray(tree) ? tree : [tree];
1097
+ const [sharedLocalState, setSharedLocalState] = useState3({});
1098
+ const handleSharedSetLocal = useCallback3((key, value) => {
1099
+ setSharedLocalState((prev) => ({ ...prev, [key]: value }));
1100
+ }, []);
1101
+ const sharedLocal = useMemo2(() => ({
1102
+ state: sharedLocalState,
1103
+ setLocal: handleSharedSetLocal
1104
+ }), [sharedLocalState, handleSharedSetLocal]);
1105
+ const rootScope = useMemo2(() => buildScope({
1106
+ auth: playerCtx?.auth ?? initialScope?.auth,
1107
+ entity,
1108
+ localState: initialScope?.$local ?? {},
1109
+ actionScope: initialScope?.$action ?? {
1110
+ transition: async () => {
1111
+ },
1112
+ create: async () => "",
1113
+ update: async () => {
1114
+ },
1115
+ remove: async () => {
1116
+ },
1117
+ setLocal: () => {
1118
+ },
1119
+ navigate: () => {
1120
+ },
1121
+ toast: () => {
1122
+ },
1123
+ refreshQuery: () => {
1124
+ },
1125
+ scrollTo: () => {
1126
+ },
1127
+ openModal: () => {
1128
+ },
1129
+ closeModal: () => {
1130
+ },
1131
+ emit: () => {
1132
+ }
1133
+ }
1134
+ }), [playerCtx?.auth, entity, initialScope]);
1135
+ return /* @__PURE__ */ jsx2(SharedLocalContext.Provider, { value: sharedLocal, children: /* @__PURE__ */ jsx2(ScopeContext.Provider, { value: rootScope, children: /* @__PURE__ */ jsx2("div", { className, children: nodes.map((node, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: node.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node, fallback }) }, node.id ?? i)) }) }) });
1136
+ };
1137
+
1138
+ // src/player/resolver.ts
1139
+ function getToken(token) {
1140
+ if (!token) return null;
1141
+ if (typeof token === "function") return token();
1142
+ return token;
1143
+ }
1144
+ function normalizeInstance(raw) {
1145
+ return {
1146
+ id: String(raw.id ?? ""),
1147
+ state: String(raw.current_state ?? raw.state ?? "unknown"),
1148
+ fields: raw.state_data ?? raw.fields ?? {},
1149
+ slug: raw.definition_slug,
1150
+ created_at: raw.created_at,
1151
+ updated_at: raw.updated_at,
1152
+ ...raw
1153
+ };
1154
+ }
1155
+ function createApiResolver(config) {
1156
+ const { baseUrl, defaults } = config;
1157
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
1158
+ const defCache = /* @__PURE__ */ new Map();
1159
+ async function apiRequest(path, options = {}) {
1160
+ const tok = getToken(config.token);
1161
+ const headers = {
1162
+ "Content-Type": "application/json",
1163
+ ...options.headers ?? {}
1164
+ };
1165
+ if (tok) headers["Authorization"] = `Bearer ${tok}`;
1166
+ const response = await fetchFn(`${baseUrl}${path}`, {
1167
+ ...options,
1168
+ headers
1169
+ });
1170
+ if (!response.ok) {
1171
+ const body = await response.text().catch(() => "");
1172
+ let message = `API error ${response.status}: ${response.statusText}`;
1173
+ try {
1174
+ const parsed = JSON.parse(body);
1175
+ if (parsed.message) message = parsed.message;
1176
+ if (parsed.error) message = `${parsed.error}: ${parsed.message || ""}`;
1177
+ } catch {
1178
+ }
1179
+ throw new Error(message);
1180
+ }
1181
+ return response.json();
1182
+ }
1183
+ const resolver = {
1184
+ async query(slug, params) {
1185
+ const searchParams = new URLSearchParams();
1186
+ searchParams.set("definition", slug);
1187
+ if (params.state) {
1188
+ const states = Array.isArray(params.state) ? params.state : [params.state];
1189
+ states.forEach((s) => searchParams.append("state", s));
1190
+ }
1191
+ if (params.status) searchParams.set("status", params.status);
1192
+ if (params.limit ?? defaults?.limit) searchParams.set("limit", String(params.limit ?? defaults?.limit ?? 20));
1193
+ if (params.page) searchParams.set("page", String(params.page));
1194
+ if (params.offset) searchParams.set("offset", String(params.offset));
1195
+ if (params.search) searchParams.set("search", params.search);
1196
+ if (params.searchFields?.length) searchParams.set("search_fields", params.searchFields.join(","));
1197
+ if (params.sort) {
1198
+ if (typeof params.sort === "string") {
1199
+ searchParams.set("sort", params.sort);
1200
+ } else if (Array.isArray(params.sort)) {
1201
+ const sortStr = params.sort.map((s) => `${s.direction === "desc" ? "-" : ""}${s.field}`).join(",");
1202
+ searchParams.set("sort", sortStr);
1203
+ }
1204
+ }
1205
+ if (params.filter) {
1206
+ searchParams.set("state_filter", JSON.stringify(params.filter));
1207
+ }
1208
+ if (params.facets?.length) {
1209
+ searchParams.set("facets", params.facets.join(","));
1210
+ }
1211
+ if (params.entity) {
1212
+ searchParams.set("entity_type", params.entity.type);
1213
+ searchParams.set("entity_id", params.entity.id);
1214
+ }
1215
+ if (params.parentInstanceId) {
1216
+ searchParams.set("spawned_by_instance_id", params.parentInstanceId);
1217
+ }
1218
+ if (params.includeDefinition) {
1219
+ searchParams.set("include_definition", "true");
1220
+ }
1221
+ const raw = await apiRequest(
1222
+ `/workflow/instances?${searchParams.toString()}`
1223
+ );
1224
+ const items = raw.items ?? raw.data ?? [];
1225
+ const total = Number(raw.total ?? raw.count ?? items.length);
1226
+ const page = Number(raw.page ?? params.page ?? 1);
1227
+ const pageSize = Number(raw.page_size ?? raw.pageSize ?? params.limit ?? defaults?.limit ?? 20);
1228
+ const result = {
1229
+ data: items.map(normalizeInstance),
1230
+ total,
1231
+ page,
1232
+ pageSize
1233
+ };
1234
+ if (raw.definition) result.definition = raw.definition;
1235
+ if (raw.facets) result.facets = raw.facets;
1236
+ if (raw.aggregates) result.aggregates = raw.aggregates;
1237
+ if (raw.grouped) result.grouped = raw.grouped;
1238
+ return result;
1239
+ },
1240
+ async getInstance(id) {
1241
+ const raw = await apiRequest(`/workflow/instances/${id}`);
1242
+ return normalizeInstance(raw);
1243
+ },
1244
+ async getDefinition(slug) {
1245
+ const cached = defCache.get(slug);
1246
+ if (cached && cached.expires > Date.now()) return cached.data;
1247
+ const raw = await apiRequest(`/workflow/definitions/slug/${slug}`);
1248
+ defCache.set(slug, { data: raw, expires: Date.now() + 5 * 60 * 1e3 });
1249
+ return raw;
1250
+ },
1251
+ async create(slug, data) {
1252
+ const raw = await apiRequest("/workflow/instances", {
1253
+ method: "POST",
1254
+ body: JSON.stringify({
1255
+ definition_slug: slug,
1256
+ state_data: data ?? {}
1257
+ })
1258
+ });
1259
+ return String(raw.id);
1260
+ },
1261
+ async update(id, fields) {
1262
+ await apiRequest(`/workflow/instances/${id}/state-data`, {
1263
+ method: "PATCH",
1264
+ body: JSON.stringify(fields)
1265
+ });
1266
+ },
1267
+ async transition(id, name, data) {
1268
+ const raw = await apiRequest(
1269
+ `/workflow/instances/${id}/transitions/${name}`,
1270
+ {
1271
+ method: "POST",
1272
+ body: JSON.stringify({ data: data ?? {} })
1273
+ }
1274
+ );
1275
+ return raw;
1276
+ },
1277
+ async remove(id) {
1278
+ await apiRequest(`/workflow/instances/${id}`, { method: "DELETE" });
1279
+ },
1280
+ async availableTransitions(id) {
1281
+ const raw = await apiRequest(`/workflow/instances/${id}/transitions`);
1282
+ return Array.isArray(raw) ? raw : [];
1283
+ },
1284
+ async fetch(endpoint, fetchConfig) {
1285
+ return apiRequest(endpoint, {
1286
+ method: fetchConfig.method ?? "GET",
1287
+ body: fetchConfig.body ? JSON.stringify(fetchConfig.body) : void 0,
1288
+ headers: fetchConfig.headers
1289
+ });
1290
+ }
1291
+ };
1292
+ return resolver;
1293
+ }
1294
+
1295
+ // src/player/ComponentTreeRenderer.tsx
1296
+ import React4, { useMemo as useMemo3, useCallback as useCallback4 } from "react";
1297
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1298
+ var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
1299
+ function containsExpression(value) {
1300
+ return typeof value === "string" && EXPR_PATTERN.test(value);
1301
+ }
1302
+ function evaluateProp(value, scopes) {
1303
+ if (typeof value !== "string") return value;
1304
+ const fullMatch = value.match(/^\{\{(.+)\}\}$/s);
1305
+ if (fullMatch) return evaluateExpression(fullMatch[1], scopes);
1306
+ if (containsExpression(value)) {
1307
+ return value.replace(EXPR_PATTERN, (_, expr) => {
1308
+ const result = evaluateExpression(expr, scopes);
1309
+ return result == null ? "" : String(result);
1310
+ });
1311
+ }
1312
+ return value;
1313
+ }
1314
+ var UnknownAtom = ({ type, children }) => /* @__PURE__ */ jsxs2("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
1315
+ /* @__PURE__ */ jsxs2("span", { style: { fontWeight: 600 }, children: [
1316
+ "Unknown: ",
1317
+ type
1318
+ ] }),
1319
+ children && /* @__PURE__ */ jsx3("div", { style: { marginTop: 4 }, children })
1320
+ ] });
1321
+ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
1322
+ const nodeType = node.type || node.component || "";
1323
+ const nodeProps = node.props || node.config || {};
1324
+ if (node.$if) {
1325
+ const condition = evaluateProp(node.$if, scopes);
1326
+ if (!condition) return null;
1327
+ }
1328
+ if (node.$for) {
1329
+ const { each, as, key: keyField } = node.$for;
1330
+ const items = evaluateProp(each, scopes);
1331
+ if (!Array.isArray(items)) return null;
1332
+ return /* @__PURE__ */ jsx3(Fragment, { children: items.map((item, index) => {
1333
+ const loopScopes = {
1334
+ ...scopes,
1335
+ state_data: {
1336
+ ...scopes.state_data ?? {},
1337
+ [as]: item,
1338
+ [`${as}Index`]: index
1339
+ }
1340
+ };
1341
+ const nodeWithoutFor = { ...node, $for: void 0 };
1342
+ const itemKey = keyField ? String(item[keyField] ?? index) : String(index);
1343
+ return /* @__PURE__ */ jsx3(RenderNode, { node: nodeWithoutFor, scopes: loopScopes, atoms, onEvent }, itemKey);
1344
+ }) });
1345
+ }
1346
+ const Component = atoms[nodeType];
1347
+ if (!Component) {
1348
+ return /* @__PURE__ */ jsx3(UnknownAtom, { type: nodeType });
1349
+ }
1350
+ const evaluatedProps = {};
1351
+ if (node.className) evaluatedProps.className = node.className;
1352
+ if (node.id) evaluatedProps["data-node-id"] = node.id;
1353
+ for (const [key, value] of Object.entries(nodeProps)) {
1354
+ if (key.startsWith("on") && typeof value === "string") {
1355
+ evaluatedProps[key] = (...args) => {
1356
+ if (containsExpression(value)) {
1357
+ evaluateExpression(value.replace(/^\{\{|\}\}$/g, ""), scopes);
1358
+ } else {
1359
+ onEvent(value, args[0]);
1360
+ }
1361
+ };
1362
+ } else {
1363
+ evaluatedProps[key] = evaluateProp(value, scopes);
1364
+ }
1365
+ }
1366
+ let children = null;
1367
+ if (node.children) {
1368
+ if (typeof node.children === "string") {
1369
+ children = evaluateProp(node.children, scopes);
1370
+ } else if (Array.isArray(node.children)) {
1371
+ children = node.children.map((child, index) => /* @__PURE__ */ jsx3(RenderNode, { node: child, scopes, atoms, onEvent }, child.id || index));
1372
+ }
1373
+ }
1374
+ return /* @__PURE__ */ jsx3(Component, { ...evaluatedProps, children });
1375
+ };
1376
+ var CTRErrorBoundary = class extends React4.Component {
1377
+ constructor(props) {
1378
+ super(props);
1379
+ this.state = { hasError: false };
1380
+ }
1381
+ static getDerivedStateFromError(error) {
1382
+ return { hasError: true, error };
1383
+ }
1384
+ componentDidCatch(error, errorInfo) {
1385
+ console.error("CTR rendering error:", error, errorInfo);
1386
+ }
1387
+ render() {
1388
+ if (this.state.hasError) {
1389
+ return this.props.fallback || /* @__PURE__ */ jsxs2("div", { style: { padding: 16, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 8 }, children: [
1390
+ /* @__PURE__ */ jsx3("strong", { style: { color: "#c53030" }, children: "Rendering Error" }),
1391
+ /* @__PURE__ */ jsx3("p", { style: { color: "#e53e3e", fontSize: 14, marginTop: 4 }, children: this.state.error?.message || "An error occurred while rendering" })
1392
+ ] });
1393
+ }
1394
+ return this.props.children;
1395
+ }
1396
+ };
1397
+ var ComponentTreeRenderer = ({
1398
+ tree,
1399
+ scopes,
1400
+ atoms = {},
1401
+ onEvent = () => {
1402
+ },
1403
+ fallback
1404
+ }) => {
1405
+ const allAtoms = useMemo3(() => ({ ...atoms }), [atoms]);
1406
+ const handleEvent = useCallback4(
1407
+ (eventName, payload) => onEvent(eventName, payload),
1408
+ [onEvent]
1409
+ );
1410
+ const nodes = Array.isArray(tree) ? tree : [tree];
1411
+ return /* @__PURE__ */ jsx3(CTRErrorBoundary, { fallback, children: nodes.map((node, index) => /* @__PURE__ */ jsx3(RenderNode, { node, scopes, atoms: allAtoms, onEvent: handleEvent }, index)) });
1412
+ };
1413
+
1414
+ // src/player/builtin-atoms.tsx
1415
+ import React5 from "react";
1416
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1417
+ var Stack = ({ children, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, ...rest, children });
1418
+ var Row = ({ children, gap = 8, align, justify, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "row", gap, alignItems: align, justifyContent: justify, ...style }, ...rest, children });
1419
+ var Column = ({ children, span, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { flex: span ? `0 0 ${Number(span) / 12 * 100}%` : 1, ...style }, ...rest, children });
1420
+ var Grid = ({ children, columns = 2, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap, ...style }, ...rest, children });
1421
+ var Divider = ({ style }) => /* @__PURE__ */ jsx4("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "8px 0", ...style } });
1422
+ var Spacer = ({ size = 16 }) => /* @__PURE__ */ jsx4("div", { style: { height: size, flexShrink: 0 } });
1423
+ var Text = ({ children, size, weight, color, style, ...rest }) => /* @__PURE__ */ jsx4("span", { style: { fontSize: size, fontWeight: weight, color, ...style }, ...rest, children });
1424
+ var Heading = ({ children, level = 2, style, ...rest }) => {
1425
+ const lvl = Math.min(Math.max(Number(level), 1), 6);
1426
+ const s = { margin: "0 0 8px", ...style };
1427
+ const c = children;
1428
+ if (lvl === 1) return /* @__PURE__ */ jsx4("h1", { style: s, ...rest, children: c });
1429
+ if (lvl === 2) return /* @__PURE__ */ jsx4("h2", { style: s, ...rest, children: c });
1430
+ if (lvl === 3) return /* @__PURE__ */ jsx4("h3", { style: s, ...rest, children: c });
1431
+ if (lvl === 4) return /* @__PURE__ */ jsx4("h4", { style: s, ...rest, children: c });
1432
+ if (lvl === 5) return /* @__PURE__ */ jsx4("h5", { style: s, ...rest, children: c });
1433
+ return /* @__PURE__ */ jsx4("h6", { style: s, ...rest, children: c });
1434
+ };
1435
+ var Field = ({ label, value, children, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8, ...style }, children: [
1436
+ label ? /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1437
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 14 }, children: children ?? value ?? "\u2014" })
1438
+ ] });
1439
+ var Badge = ({ children, variant = "default", style }) => {
1440
+ const colors = {
1441
+ default: { bg: "#edf2f7", fg: "#4a5568" },
1442
+ success: { bg: "#c6f6d5", fg: "#276749" },
1443
+ warning: { bg: "#fefcbf", fg: "#975a16" },
1444
+ error: { bg: "#fed7d7", fg: "#9b2c2c" },
1445
+ info: { bg: "#bee3f8", fg: "#2a4365" }
1446
+ };
1447
+ const c = colors[variant] ?? colors.default;
1448
+ return /* @__PURE__ */ jsx4("span", { style: { display: "inline-block", padding: "2px 8px", borderRadius: 9999, fontSize: 12, fontWeight: 500, background: c.bg, color: c.fg, ...style }, children });
1449
+ };
1450
+ var ImageAtom = ({ src, alt, width, height, style, ...rest }) => /* @__PURE__ */ jsx4("img", { src, alt: alt ?? "", width, height, style: { maxWidth: "100%", ...style }, ...rest });
1451
+ var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest }) => {
1452
+ const styles = {
1453
+ primary: { background: "#3182ce", color: "#fff", border: "none" },
1454
+ secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
1455
+ danger: { background: "#e53e3e", color: "#fff", border: "none" },
1456
+ ghost: { background: "transparent", color: "#4a5568", border: "none" }
1457
+ };
1458
+ const base = styles[variant] ?? styles.primary;
1459
+ return /* @__PURE__ */ jsx4(
1460
+ "button",
1461
+ {
1462
+ onClick,
1463
+ disabled,
1464
+ style: { padding: "6px 16px", borderRadius: 6, fontSize: 14, fontWeight: 500, cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1, ...base, ...style },
1465
+ ...rest,
1466
+ children
1467
+ }
1468
+ );
1469
+ };
1470
+ var LinkAtom = ({ children, href, style, ...rest }) => /* @__PURE__ */ jsx4("a", { href, style: { color: "#3182ce", textDecoration: "underline", ...style }, ...rest, children });
1471
+ var TextInput = ({ value, onChange, placeholder, label, bind: _bind, style }) => {
1472
+ const isControlled = typeof onChange === "function";
1473
+ const [localValue, setLocalValue] = React5.useState(value ?? "");
1474
+ const handleChange = (e) => {
1475
+ setLocalValue(e.target.value);
1476
+ if (typeof onChange === "function") onChange(e);
1477
+ };
1478
+ return /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1479
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1480
+ /* @__PURE__ */ jsx4(
1481
+ "input",
1482
+ {
1483
+ type: "text",
1484
+ value: isControlled ? value ?? "" : localValue,
1485
+ onChange: handleChange,
1486
+ placeholder,
1487
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style }
1488
+ }
1489
+ )
1490
+ ] });
1491
+ };
1492
+ var SelectAtom = ({ value, onChange, options, label, placeholder, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1493
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1494
+ /* @__PURE__ */ jsxs3(
1495
+ "select",
1496
+ {
1497
+ value: value ?? "",
1498
+ onChange,
1499
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
1500
+ children: [
1501
+ placeholder ? /* @__PURE__ */ jsx4("option", { value: "", children: placeholder }) : null,
1502
+ Array.isArray(options) && options.map((opt) => {
1503
+ const v = typeof opt === "string" ? opt : opt.value;
1504
+ const l = typeof opt === "string" ? opt : opt.label;
1505
+ return /* @__PURE__ */ jsx4("option", { value: v, children: l }, v);
1506
+ })
1507
+ ]
1508
+ }
1509
+ )
1510
+ ] });
1511
+ var Card = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("div", { style: { border: "1px solid #e2e8f0", borderRadius: 8, padding: 16, background: "#fff", ...style }, ...rest, children: [
1512
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: 12 }, children: title }) : null,
1513
+ children
1514
+ ] });
1515
+ var Section = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("section", { style: { marginBottom: 24, ...style }, ...rest, children: [
1516
+ title ? /* @__PURE__ */ jsx4("h3", { style: { fontSize: 18, fontWeight: 600, marginBottom: 8 }, children: title }) : null,
1517
+ children
1518
+ ] });
1519
+ var Show = ({ when, children, fallback }) => when ? /* @__PURE__ */ jsx4(Fragment2, { children }) : /* @__PURE__ */ jsx4(Fragment2, { children: fallback ?? null });
1520
+ var Each = ({ items, children, renderItem }) => {
1521
+ if (!Array.isArray(items)) return null;
1522
+ if (typeof renderItem === "function") return /* @__PURE__ */ jsx4(Fragment2, { children: items.map((item, i) => renderItem(item, i)) });
1523
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1524
+ };
1525
+ var RouterContext = React5.createContext({ path: "/", navigate: () => {
1526
+ } });
1527
+ var Router = ({ children, basePath, className, style, ...rest }) => {
1528
+ const [path, setPath] = React5.useState("/");
1529
+ const navigate = React5.useCallback((to) => setPath(to), []);
1530
+ return /* @__PURE__ */ jsx4(RouterContext.Provider, { value: { path, navigate }, children: /* @__PURE__ */ jsx4("div", { className, style, ...rest, children }) });
1531
+ };
1532
+ var Route = ({ children, path, exact, fallback: _fallback, className, style }) => {
1533
+ const { path: currentPath } = React5.useContext(RouterContext);
1534
+ const routePath = path || "/";
1535
+ const isExact = exact !== false;
1536
+ const matches = isExact ? currentPath === routePath || routePath === "/" && currentPath === "/" : currentPath.startsWith(routePath);
1537
+ if (!matches) return null;
1538
+ return /* @__PURE__ */ jsx4("div", { className, style, children });
1539
+ };
1540
+ var NavLink = ({ children, to, label, icon, className, style, ...rest }) => {
1541
+ const { path, navigate } = React5.useContext(RouterContext);
1542
+ const target = to || "/";
1543
+ const isActive = path === target;
1544
+ return /* @__PURE__ */ jsx4(
1545
+ "button",
1546
+ {
1547
+ onClick: () => navigate(target),
1548
+ className,
1549
+ style: {
1550
+ background: isActive ? "#edf2f7" : "transparent",
1551
+ border: "none",
1552
+ borderRadius: 4,
1553
+ padding: "4px 12px",
1554
+ fontSize: 13,
1555
+ cursor: "pointer",
1556
+ fontWeight: isActive ? 600 : 400,
1557
+ color: isActive ? "#2d3748" : "#718096",
1558
+ ...style
1559
+ },
1560
+ ...rest,
1561
+ children: children || label || target
1562
+ }
1563
+ );
1564
+ };
1565
+ var RoleGuard = ({ children, role: _role, fallback: _fallback }) => {
1566
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1567
+ };
1568
+ var Icon = ({ name, size = 16, color, style }) => /* @__PURE__ */ jsx4("span", { style: { display: "inline-flex", alignItems: "center", justifyContent: "center", width: size, height: size, fontSize: size, color, ...style }, title: name, children: iconGlyphs[name] || "\u25A1" });
1569
+ var iconGlyphs = {
1570
+ home: "\u2302",
1571
+ settings: "\u2699",
1572
+ plus: "+",
1573
+ search: "\u{1F50D}",
1574
+ box: "\u25A1",
1575
+ inbox: "\u2709",
1576
+ chevronRight: "\u203A",
1577
+ chevronLeft: "\u2039",
1578
+ x: "\u2715",
1579
+ check: "\u2713",
1580
+ edit: "\u270E",
1581
+ trash: "\u{1F5D1}",
1582
+ star: "\u2605",
1583
+ heart: "\u2665",
1584
+ user: "\u{1F464}",
1585
+ menu: "\u2630",
1586
+ close: "\u2715",
1587
+ arrow_right: "\u2192",
1588
+ arrow_left: "\u2190"
1589
+ };
1590
+ var Tabs = ({ children, tabs, defaultTab, style }) => {
1591
+ const tabList = tabs || [];
1592
+ const [active, setActive] = React5.useState(defaultTab || tabList[0]?.id || "");
1593
+ return /* @__PURE__ */ jsxs3("div", { style, children: [
1594
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", borderBottom: "1px solid #e2e8f0", marginBottom: 12 }, children: tabList.map((t) => /* @__PURE__ */ jsx4(
1595
+ "button",
1596
+ {
1597
+ onClick: () => setActive(t.id),
1598
+ style: { padding: "6px 16px", border: "none", borderBottom: active === t.id ? "2px solid #3182ce" : "2px solid transparent", background: "none", cursor: "pointer", fontWeight: active === t.id ? 600 : 400, color: active === t.id ? "#3182ce" : "#718096" },
1599
+ children: t.label
1600
+ },
1601
+ t.id
1602
+ )) }),
1603
+ children
1604
+ ] });
1605
+ };
1606
+ var Accordion = ({ children, style }) => /* @__PURE__ */ jsx4("div", { style, children });
1607
+ var Modal = ({ children, open, title, onClose: _onClose, style }) => {
1608
+ if (!open) return null;
1609
+ return /* @__PURE__ */ jsx4("div", { style: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1e3 }, children: /* @__PURE__ */ jsxs3("div", { style: { background: "#fff", borderRadius: 12, padding: 24, maxWidth: 480, width: "100%", ...style }, children: [
1610
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 18, marginBottom: 16 }, children: String(title) }) : null,
1611
+ children
1612
+ ] }) });
1613
+ };
1614
+ var Markdown = ({ content, children, style }) => /* @__PURE__ */ jsx4("div", { style: { lineHeight: 1.6, ...style }, children: content || children });
1615
+ var ScrollArea = ({ children, maxHeight = 400, style }) => /* @__PURE__ */ jsx4("div", { style: { overflow: "auto", maxHeight, ...style }, children });
1616
+ var Slot = ({ children, fallback }) => /* @__PURE__ */ jsx4(Fragment2, { children: children || fallback || null });
1617
+ var ModuleOutlet = ({ children, module: moduleName, fallback }) => /* @__PURE__ */ jsx4("div", { "data-module": moduleName, children: children || fallback || /* @__PURE__ */ jsxs3("span", { style: { color: "#a0aec0", fontSize: 13 }, children: [
1618
+ "Module: ",
1619
+ moduleName
1620
+ ] }) });
1621
+ var builtinAtoms = {
1622
+ // Layout
1623
+ Stack,
1624
+ Row,
1625
+ Column,
1626
+ Grid,
1627
+ Divider,
1628
+ Spacer,
1629
+ // Typography
1630
+ Text,
1631
+ Heading,
1632
+ Field,
1633
+ Badge,
1634
+ Image: ImageAtom,
1635
+ Icon,
1636
+ // Interactive
1637
+ Button,
1638
+ Link: LinkAtom,
1639
+ // Form
1640
+ TextInput,
1641
+ Select: SelectAtom,
1642
+ // Containers
1643
+ Card,
1644
+ Section,
1645
+ Tabs,
1646
+ Accordion,
1647
+ Modal,
1648
+ // Content
1649
+ Markdown,
1650
+ ScrollArea,
1651
+ // Control Flow
1652
+ Show,
1653
+ Each,
1654
+ // Routing
1655
+ Router,
1656
+ Route,
1657
+ NavLink,
1658
+ RoleGuard,
1659
+ // Composition
1660
+ Slot,
1661
+ ModuleOutlet
1662
+ };
1663
+
1664
+ // src/player/DevPlayer.tsx
1665
+ import { useState as useState4, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect4, useMemo as useMemo4 } from "react";
1666
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1667
+ var S = {
1668
+ shell: {
1669
+ display: "flex",
1670
+ flexDirection: "column",
1671
+ height: "100%",
1672
+ minHeight: "100vh",
1673
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1674
+ background: "#f7fafc",
1675
+ color: "#1a202c"
1676
+ },
1677
+ toolbar: {
1678
+ display: "flex",
1679
+ alignItems: "center",
1680
+ gap: 12,
1681
+ padding: "8px 16px",
1682
+ background: "#1a202c",
1683
+ color: "#e2e8f0",
1684
+ fontSize: 13,
1685
+ flexShrink: 0
1686
+ },
1687
+ toolbarTitle: { fontWeight: 600, fontSize: 14 },
1688
+ toolbarBadge: {
1689
+ display: "inline-block",
1690
+ padding: "1px 8px",
1691
+ borderRadius: 4,
1692
+ background: "#2d3748",
1693
+ color: "#a0aec0",
1694
+ fontSize: 11,
1695
+ fontFamily: "monospace"
1696
+ },
1697
+ toolbarBtn: {
1698
+ background: "none",
1699
+ border: "1px solid #4a5568",
1700
+ borderRadius: 4,
1701
+ color: "#a0aec0",
1702
+ padding: "2px 10px",
1703
+ fontSize: 12,
1704
+ cursor: "pointer"
1705
+ },
1706
+ toolbarBtnActive: {
1707
+ background: "#2b6cb0",
1708
+ borderColor: "#2b6cb0",
1709
+ color: "#fff"
1710
+ },
1711
+ body: { display: "flex", flex: 1, overflow: "hidden" },
1712
+ preview: { flex: 1, overflow: "auto", padding: 24 },
1713
+ sidebar: {
1714
+ width: 340,
1715
+ flexShrink: 0,
1716
+ borderLeft: "1px solid #e2e8f0",
1717
+ background: "#fff",
1718
+ overflow: "auto",
1719
+ fontSize: 13
1720
+ },
1721
+ sidebarSection: { padding: "12px 16px", borderBottom: "1px solid #f0f0f0" },
1722
+ sidebarHeading: {
1723
+ fontSize: 11,
1724
+ fontWeight: 700,
1725
+ textTransform: "uppercase",
1726
+ color: "#a0aec0",
1727
+ letterSpacing: "0.05em",
1728
+ marginBottom: 8
1729
+ },
1730
+ pre: {
1731
+ background: "#f7fafc",
1732
+ border: "1px solid #e2e8f0",
1733
+ borderRadius: 6,
1734
+ padding: "8px 12px",
1735
+ fontSize: 12,
1736
+ fontFamily: "monospace",
1737
+ whiteSpace: "pre-wrap",
1738
+ wordBreak: "break-word",
1739
+ maxHeight: 260,
1740
+ overflow: "auto"
1741
+ },
1742
+ eventRow: {
1743
+ display: "flex",
1744
+ gap: 8,
1745
+ padding: "4px 0",
1746
+ borderBottom: "1px solid #f7fafc",
1747
+ fontSize: 12,
1748
+ fontFamily: "monospace"
1749
+ },
1750
+ eventTime: { color: "#a0aec0", flexShrink: 0 },
1751
+ eventName: { color: "#3182ce", fontWeight: 500 },
1752
+ dot: (connected) => ({
1753
+ width: 8,
1754
+ height: 8,
1755
+ borderRadius: "50%",
1756
+ background: connected ? "#48bb78" : "#e53e3e",
1757
+ flexShrink: 0
1758
+ })
1759
+ };
1760
+ function useDevSocket(wsUrl, onReload) {
1761
+ const [connected, setConnected] = useState4(false);
1762
+ const wsRef = useRef5(null);
1763
+ useEffect4(() => {
1764
+ if (typeof window === "undefined") return;
1765
+ const url = wsUrl ?? `ws://${window.location.host}/__mm_dev`;
1766
+ let ws;
1767
+ let reconnectTimer;
1768
+ function connect() {
1769
+ try {
1770
+ ws = new WebSocket(url);
1771
+ wsRef.current = ws;
1772
+ ws.onopen = () => setConnected(true);
1773
+ ws.onclose = () => {
1774
+ setConnected(false);
1775
+ reconnectTimer = setTimeout(connect, 3e3);
1776
+ };
1777
+ ws.onmessage = (ev) => {
1778
+ try {
1779
+ const msg = JSON.parse(ev.data);
1780
+ if (msg.type === "workflow:compiled" || msg.type === "workflow:rebuild") {
1781
+ onReload?.();
1782
+ }
1783
+ } catch {
1784
+ }
1785
+ };
1786
+ } catch {
1787
+ reconnectTimer = setTimeout(connect, 3e3);
1788
+ }
1789
+ }
1790
+ connect();
1791
+ return () => {
1792
+ clearTimeout(reconnectTimer);
1793
+ wsRef.current?.close();
1794
+ wsRef.current = null;
1795
+ };
1796
+ }, [wsUrl, onReload]);
1797
+ return connected;
1798
+ }
1799
+ var DevPlayer = ({
1800
+ tree,
1801
+ scopes = {},
1802
+ atoms: userAtoms,
1803
+ title = "DevPlayer",
1804
+ bare = false,
1805
+ wsUrl,
1806
+ onReload,
1807
+ onEvent: externalOnEvent
1808
+ }) => {
1809
+ const [showSidebar, setShowSidebar] = useState4(true);
1810
+ const [events, setEvents] = useState4([]);
1811
+ const nextId = useRef5(0);
1812
+ const connected = useDevSocket(wsUrl, onReload);
1813
+ const mergedAtoms = useMemo4(
1814
+ () => ({ ...builtinAtoms, ...userAtoms }),
1815
+ [userAtoms]
1816
+ );
1817
+ const handleEvent = useCallback5(
1818
+ (name, payload) => {
1819
+ setEvents((prev) => {
1820
+ const entry = {
1821
+ id: nextId.current++,
1822
+ time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }),
1823
+ name,
1824
+ payload
1825
+ };
1826
+ const next = [entry, ...prev];
1827
+ return next.length > 100 ? next.slice(0, 100) : next;
1828
+ });
1829
+ externalOnEvent?.(name, payload);
1830
+ },
1831
+ [externalOnEvent]
1832
+ );
1833
+ if (bare) {
1834
+ return /* @__PURE__ */ jsx5(
1835
+ ComponentTreeRenderer,
1836
+ {
1837
+ tree,
1838
+ scopes,
1839
+ atoms: mergedAtoms,
1840
+ onEvent: handleEvent
1841
+ }
1842
+ );
1843
+ }
1844
+ return /* @__PURE__ */ jsxs4("div", { style: S.shell, children: [
1845
+ /* @__PURE__ */ jsxs4("div", { style: S.toolbar, children: [
1846
+ /* @__PURE__ */ jsx5("div", { style: S.dot(connected), title: connected ? "HMR connected" : "HMR disconnected" }),
1847
+ /* @__PURE__ */ jsx5("span", { style: S.toolbarTitle, children: title }),
1848
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1849
+ Array.isArray(tree) ? tree.length : 1,
1850
+ " node",
1851
+ Array.isArray(tree) && tree.length !== 1 ? "s" : ""
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1854
+ Object.keys(mergedAtoms).length,
1855
+ " atoms"
1856
+ ] }),
1857
+ /* @__PURE__ */ jsx5("div", { style: { flex: 1 } }),
1858
+ /* @__PURE__ */ jsx5(
1859
+ "button",
1860
+ {
1861
+ style: { ...S.toolbarBtn, ...showSidebar ? S.toolbarBtnActive : {} },
1862
+ onClick: () => setShowSidebar((v) => !v),
1863
+ children: "Inspector"
1864
+ }
1865
+ )
1866
+ ] }),
1867
+ /* @__PURE__ */ jsxs4("div", { style: S.body, children: [
1868
+ /* @__PURE__ */ jsx5("div", { style: S.preview, children: /* @__PURE__ */ jsx5(
1869
+ ComponentTreeRenderer,
1870
+ {
1871
+ tree,
1872
+ scopes,
1873
+ atoms: mergedAtoms,
1874
+ onEvent: handleEvent
1875
+ }
1876
+ ) }),
1877
+ showSidebar && /* @__PURE__ */ jsxs4("div", { style: S.sidebar, children: [
1878
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1879
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Scopes" }),
1880
+ /* @__PURE__ */ jsx5("pre", { style: S.pre, children: JSON.stringify(scopes, null, 2) })
1881
+ ] }),
1882
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1883
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1884
+ "Atoms (",
1885
+ Object.keys(mergedAtoms).length,
1886
+ ")"
1887
+ ] }),
1888
+ /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(mergedAtoms).sort().map((name) => /* @__PURE__ */ jsx5(
1889
+ "span",
1890
+ {
1891
+ style: {
1892
+ display: "inline-block",
1893
+ padding: "1px 6px",
1894
+ borderRadius: 3,
1895
+ background: userAtoms?.[name] ? "#ebf8ff" : "#f7fafc",
1896
+ border: `1px solid ${userAtoms?.[name] ? "#90cdf4" : "#e2e8f0"}`,
1897
+ fontSize: 11,
1898
+ fontFamily: "monospace",
1899
+ color: userAtoms?.[name] ? "#2b6cb0" : "#718096"
1900
+ },
1901
+ children: name
1902
+ },
1903
+ name
1904
+ )) })
1905
+ ] }),
1906
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1907
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
1908
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1909
+ "Events (",
1910
+ events.length,
1911
+ ")"
1912
+ ] }),
1913
+ events.length > 0 && /* @__PURE__ */ jsx5(
1914
+ "button",
1915
+ {
1916
+ style: { background: "none", border: "none", color: "#a0aec0", fontSize: 11, cursor: "pointer" },
1917
+ onClick: () => setEvents([]),
1918
+ children: "Clear"
1919
+ }
1920
+ )
1921
+ ] }),
1922
+ events.length === 0 && /* @__PURE__ */ jsx5("div", { style: { color: "#a0aec0", fontSize: 12, fontStyle: "italic" }, children: "No events yet" }),
1923
+ events.slice(0, 50).map((e) => /* @__PURE__ */ jsxs4("div", { style: S.eventRow, children: [
1924
+ /* @__PURE__ */ jsx5("span", { style: S.eventTime, children: e.time }),
1925
+ /* @__PURE__ */ jsx5("span", { style: S.eventName, children: e.name }),
1926
+ e.payload !== void 0 && /* @__PURE__ */ jsx5("span", { style: { color: "#718096", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: JSON.stringify(e.payload) })
1927
+ ] }, e.id))
1928
+ ] }),
1929
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1930
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Tree (JSON)" }),
1931
+ /* @__PURE__ */ jsx5("pre", { style: { ...S.pre, maxHeight: 400 }, children: JSON.stringify(tree, null, 2) })
1932
+ ] })
1933
+ ] })
1934
+ ] })
1935
+ ] });
1936
+ };
1937
+
1938
+ export {
1939
+ setQueryResolver,
1940
+ useQuery,
1941
+ setMutationResolver,
1942
+ useMutation,
1943
+ classifyBinding,
1944
+ resolveBinding,
1945
+ resolveAllBindings,
1946
+ buildEvalContext,
1947
+ buildActionScope,
1948
+ AtomRegistryImpl,
1949
+ createCoreAtomRegistry,
1950
+ mergeRegistries,
1951
+ DEFAULT_DESIGN_TOKENS,
1952
+ usePlayerContext,
1953
+ useTheme,
1954
+ PlayerProvider,
1955
+ ExperienceRenderer,
1956
+ createApiResolver,
1957
+ ComponentTreeRenderer,
1958
+ builtinAtoms,
1959
+ DevPlayer
1960
+ };