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

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 (52) hide show
  1. package/dist/actions-MFI2V4DX.mjs +116 -0
  2. package/dist/atoms/index.d.mts +2 -2
  3. package/dist/atoms/index.d.ts +2 -2
  4. package/dist/atoms/index.js +1 -1
  5. package/dist/atoms/index.mjs +1 -1
  6. package/dist/builtin-atoms-C-sNyYJl.d.mts +647 -0
  7. package/dist/builtin-atoms-C-sNyYJl.d.ts +647 -0
  8. package/dist/builtin-atoms-DCKrjG7i.d.mts +96 -0
  9. package/dist/builtin-atoms-DCKrjG7i.d.ts +96 -0
  10. package/dist/builtin-atoms-DRD3EwG6.d.mts +648 -0
  11. package/dist/builtin-atoms-DRD3EwG6.d.ts +648 -0
  12. package/dist/builtin-atoms-jt04b7Rw.d.mts +643 -0
  13. package/dist/builtin-atoms-jt04b7Rw.d.ts +643 -0
  14. package/dist/chunk-247T4GDJ.mjs +677 -0
  15. package/dist/chunk-3H6CR7E7.mjs +1924 -0
  16. package/dist/chunk-3PL6FL6I.mjs +96 -0
  17. package/dist/chunk-3SJSW3C4.mjs +2039 -0
  18. package/dist/chunk-5OI2VI57.mjs +1964 -0
  19. package/dist/chunk-CL6FYZ43.mjs +105 -0
  20. package/dist/chunk-ENQOCZI5.mjs +1938 -0
  21. package/dist/chunk-FB3WCZAU.mjs +512 -0
  22. package/dist/chunk-GLJ7VC7Z.mjs +684 -0
  23. package/dist/chunk-HHMWR6NA.mjs +504 -0
  24. package/dist/chunk-HULEMSN2.mjs +120 -0
  25. package/dist/chunk-J5MW6CRU.mjs +1938 -0
  26. package/dist/chunk-PNTTKNYU.mjs +677 -0
  27. package/dist/chunk-TY5OTJP4.mjs +684 -0
  28. package/dist/chunk-WV7DVCP6.mjs +513 -0
  29. package/dist/chunk-YFMPTGUF.mjs +677 -0
  30. package/dist/{chunk-2VJQJM7S.mjs → chunk-ZDWACXZN.mjs} +1 -1
  31. package/dist/composition-BJ6QQTWT.mjs +12 -0
  32. package/dist/composition-XBGKKCI7.mjs +57 -0
  33. package/dist/content-QVPFUG4P.mjs +246 -0
  34. package/dist/control-flow-CBREHWJW.mjs +35 -0
  35. package/dist/control-flow-FWBOI6SM.mjs +35 -0
  36. package/dist/control-flow-ZWUGCDSP.mjs +35 -0
  37. package/dist/data-WCMIZYKD.mjs +97 -0
  38. package/dist/grouping-E6F377VZ.mjs +204 -0
  39. package/dist/grouping-FRPOEXO3.mjs +233 -0
  40. package/dist/index.d.mts +4 -433
  41. package/dist/index.d.ts +4 -433
  42. package/dist/index.js +3648 -581
  43. package/dist/index.mjs +335 -1040
  44. package/dist/input-PUOZDNSI.mjs +222 -0
  45. package/dist/layout-RATDMCLP.mjs +106 -0
  46. package/dist/navigation-VCT7ZBMA.mjs +15 -0
  47. package/dist/navigation-WFV7YWOU.mjs +14 -0
  48. package/dist/player/index.d.mts +37 -11
  49. package/dist/player/index.d.ts +37 -11
  50. package/dist/player/index.js +3280 -174
  51. package/dist/player/index.mjs +55 -5
  52. package/package.json +4 -4
@@ -0,0 +1,1938 @@
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-MFI2V4DX.mjs"), "Button"));
526
+ registry.register("Link", namedExport(() => import("./actions-MFI2V4DX.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 NodeErrorBoundary = class extends React3.Component {
710
+ constructor(props) {
711
+ super(props);
712
+ this.state = { hasError: false };
713
+ }
714
+ static getDerivedStateFromError(error) {
715
+ return { hasError: true, error };
716
+ }
717
+ componentDidCatch(error, info) {
718
+ console.error(`[ExperienceRenderer] Error in node ${this.props.nodeId}:`, error, info);
719
+ }
720
+ render() {
721
+ if (this.state.hasError) {
722
+ return this.props.fallback ?? /* @__PURE__ */ jsxs("div", { style: { padding: 8, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 6, fontSize: 12, color: "#c53030" }, children: [
723
+ "Error: ",
724
+ this.state.error?.message ?? "Render failed"
725
+ ] });
726
+ }
727
+ return this.props.children;
728
+ }
729
+ };
730
+ function useDataSources(dataSources, resolver, scope) {
731
+ const [results, setResults] = useState3({});
732
+ const mountedRef = useRef4(true);
733
+ useEffect3(() => {
734
+ mountedRef.current = true;
735
+ return () => {
736
+ mountedRef.current = false;
737
+ };
738
+ }, []);
739
+ useEffect3(() => {
740
+ if (!dataSources?.length || !resolver) return;
741
+ const loading = {};
742
+ for (const ds of dataSources) {
743
+ loading[ds.name] = { loading: true, error: null };
744
+ }
745
+ setResults(loading);
746
+ const fetchAll = async () => {
747
+ const entries = await Promise.all(
748
+ dataSources.map(async (ds) => {
749
+ try {
750
+ const result = await fetchDataSource(ds, resolver, scope);
751
+ return [ds.name, result];
752
+ } catch (err) {
753
+ return [ds.name, { loading: false, error: err instanceof Error ? err : new Error(String(err)) }];
754
+ }
755
+ })
756
+ );
757
+ if (mountedRef.current) {
758
+ setResults(Object.fromEntries(entries));
759
+ }
760
+ };
761
+ fetchAll();
762
+ }, [dataSources, resolver]);
763
+ return results;
764
+ }
765
+ async function fetchDataSource(ds, resolver, scope) {
766
+ switch (ds.type) {
767
+ case "workflow": {
768
+ const slug = ds.slug ?? "";
769
+ if (!slug) return { loading: false, error: new Error("workflow dataSource missing slug") };
770
+ const queryResult = await resolver.query(slug, {
771
+ state: ds.filter?.current_state,
772
+ filter: ds.filter,
773
+ limit: ds.pageSize ?? 20,
774
+ page: scope.$local?.[ds.pageKey ?? "page"] ?? 1,
775
+ search: ds.search ? interpolateTemplate(ds.search, scope) : void 0,
776
+ searchFields: ds.searchFields,
777
+ sort: ds.sort,
778
+ facets: ds.facets,
779
+ entity: ds.entity,
780
+ includeDefinition: ds.includeDefinition,
781
+ parentInstanceId: ds.parentInstanceId ? interpolateTemplate(ds.parentInstanceId, scope) : void 0
782
+ });
783
+ const result = {
784
+ instances: queryResult.data,
785
+ loading: false,
786
+ error: null
787
+ };
788
+ if (queryResult.data.length === 1 && ds.query !== "list") {
789
+ result.instance = queryResult.data[0];
790
+ }
791
+ if (queryResult.definition) result.definition = queryResult.definition;
792
+ if (queryResult.total != null) {
793
+ result.pagination = {
794
+ total: queryResult.total,
795
+ page: queryResult.page,
796
+ pageSize: queryResult.pageSize
797
+ };
798
+ }
799
+ if (queryResult.facets) result.facets = queryResult.facets;
800
+ if (queryResult.aggregates) result.aggregates = queryResult.aggregates;
801
+ if (ds.autoStart && queryResult.data.length === 0) {
802
+ try {
803
+ const id = await resolver.create(slug, ds.initialData);
804
+ const instance = await resolver.getInstance(id);
805
+ result.instance = instance;
806
+ result.instances = [instance];
807
+ } catch {
808
+ }
809
+ }
810
+ return result;
811
+ }
812
+ case "api": {
813
+ if (!resolver.fetch) return { loading: false, error: new Error("API datasource: resolver.fetch not implemented") };
814
+ const endpoint = interpolateTemplate(ds.endpoint, scope);
815
+ const raw = await resolver.fetch(endpoint, {
816
+ method: ds.method,
817
+ body: ds.body,
818
+ headers: ds.headers
819
+ });
820
+ const mapped = mapApiResponse(raw, ds.mapping);
821
+ return { instances: mapped.items, loading: false, error: null, pagination: mapped.pagination };
822
+ }
823
+ case "static": {
824
+ const data = ds.data;
825
+ if (Array.isArray(data)) {
826
+ return {
827
+ instances: data.map((d, i) => ({
828
+ id: String(d.id ?? i),
829
+ state: "static",
830
+ fields: d
831
+ })),
832
+ loading: false,
833
+ error: null
834
+ };
835
+ }
836
+ return {
837
+ instance: { id: "static", state: "static", fields: data },
838
+ loading: false,
839
+ error: null
840
+ };
841
+ }
842
+ case "ref": {
843
+ const ctx = buildEvalContext(scope);
844
+ const resolved = evaluateExpression(ds.expression, ctx);
845
+ if (Array.isArray(resolved)) {
846
+ return {
847
+ instances: resolved.map((item, i) => ({
848
+ id: String(item?.id ?? i),
849
+ state: String(item?.state ?? "ref"),
850
+ fields: item && typeof item === "object" ? item : { value: item }
851
+ })),
852
+ loading: false,
853
+ error: null
854
+ };
855
+ }
856
+ if (resolved != null && typeof resolved === "object") {
857
+ const obj = resolved;
858
+ return {
859
+ instance: {
860
+ id: String(obj.id ?? "ref"),
861
+ state: String(obj.state ?? "ref"),
862
+ fields: obj
863
+ },
864
+ loading: false,
865
+ error: null
866
+ };
867
+ }
868
+ return { loading: false, error: null };
869
+ }
870
+ default:
871
+ return { loading: false, error: new Error(`Unknown dataSource type: ${ds.type}`) };
872
+ }
873
+ }
874
+ function interpolateTemplate(template, scope) {
875
+ return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
876
+ const val = resolveBinding(`$${path}`, scope) ?? resolveBinding(path, scope);
877
+ return val != null ? String(val) : "";
878
+ });
879
+ }
880
+ function mapApiResponse(raw, mapping) {
881
+ if (!raw || typeof raw !== "object") return { items: [] };
882
+ const obj = raw;
883
+ let items;
884
+ if (mapping?.items || mapping?.data) {
885
+ items = obj[mapping.items ?? mapping.data ?? "data"] ?? [];
886
+ } else if (Array.isArray(raw)) {
887
+ items = raw;
888
+ } else if (Array.isArray(obj.data)) {
889
+ items = obj.data;
890
+ } else if (Array.isArray(obj.items)) {
891
+ items = obj.items;
892
+ } else {
893
+ items = [raw];
894
+ }
895
+ const result = items.map((item, i) => ({
896
+ id: String(item?.id ?? i),
897
+ state: String(item?.state ?? "unknown"),
898
+ fields: item ?? {}
899
+ }));
900
+ let pagination;
901
+ const total = mapping?.total ? obj[mapping.total] : obj.total;
902
+ if (total != null) {
903
+ pagination = { total: Number(total), page: Number(obj.page ?? 1), pageSize: Number(obj.pageSize ?? items.length) };
904
+ }
905
+ return { items: result, pagination };
906
+ }
907
+ function resolveTokens(value, tokens) {
908
+ if (typeof value === "string" && value.startsWith("token:")) {
909
+ return tokens[value] ?? value;
910
+ }
911
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
912
+ const resolved = {};
913
+ for (const [k, v] of Object.entries(value)) {
914
+ resolved[k] = resolveTokens(v, tokens);
915
+ }
916
+ return resolved;
917
+ }
918
+ return value;
919
+ }
920
+ var NodeRenderer = ({ node, fallback }) => {
921
+ const parentScope = useScope();
922
+ const playerCtx = usePlayerContext();
923
+ const resolver = playerCtx?.resolver ?? null;
924
+ const atomRegistry = playerCtx?.atomRegistry;
925
+ const themeTokens = useTheme();
926
+ const localDefaults = node.config?.localDefaults ?? {};
927
+ const [localState, setLocalState] = useState3(() => ({
928
+ ...localDefaults
929
+ }));
930
+ const handleSetLocal = useCallback3((key, value) => {
931
+ setLocalState((prev) => ({ ...prev, [key]: value }));
932
+ }, []);
933
+ const [, setFetchVersion] = useState3(0);
934
+ const handleRefreshQuery = useCallback3(() => {
935
+ setFetchVersion((v) => v + 1);
936
+ }, []);
937
+ const dsResults = useDataSources(node.dataSources, resolver, parentScope);
938
+ const primaryInstance = Object.values(dsResults).find((r) => r.instance)?.instance;
939
+ const primarySlug = node.dataSources?.find((ds) => ds.type === "workflow")?.slug;
940
+ const actionScope = useMemo2(() => {
941
+ if (!resolver) {
942
+ return {
943
+ transition: async () => {
944
+ },
945
+ create: async () => "",
946
+ update: async () => {
947
+ },
948
+ remove: async () => {
949
+ },
950
+ setLocal: handleSetLocal,
951
+ navigate: () => {
952
+ },
953
+ toast: () => {
954
+ },
955
+ refreshQuery: handleRefreshQuery,
956
+ scrollTo: () => {
957
+ },
958
+ openModal: () => {
959
+ },
960
+ closeModal: () => {
961
+ },
962
+ emit: () => {
963
+ }
964
+ };
965
+ }
966
+ return buildActionScope({
967
+ resolver,
968
+ instanceId: primaryInstance?.id,
969
+ slug: primarySlug,
970
+ setLocal: handleSetLocal,
971
+ router: playerCtx?.router,
972
+ toast: playerCtx?.toast,
973
+ refreshQuery: handleRefreshQuery,
974
+ onEvent: playerCtx?.onEvent
975
+ });
976
+ }, [resolver, primaryInstance?.id, primarySlug, handleSetLocal, handleRefreshQuery, playerCtx]);
977
+ const scope = useMemo2(() => buildScope({
978
+ dataSources: dsResults,
979
+ localState,
980
+ auth: playerCtx?.auth,
981
+ entity: node.dataSources?.find((ds) => ds.type === "workflow")?.entity,
982
+ parentScope,
983
+ actionScope
984
+ }), [dsResults, localState, parentScope, actionScope, playerCtx?.auth]);
985
+ const enrichedScope = useMemo2(() => {
986
+ const handleCreate = () => {
987
+ if (primarySlug && resolver) {
988
+ resolver.create(primarySlug).then(() => handleRefreshQuery());
989
+ }
990
+ };
991
+ const setSearch = (e) => {
992
+ const val = typeof e === "object" && e !== null && "target" in e ? e.target.value : String(e ?? "");
993
+ handleSetLocal("search", val);
994
+ };
995
+ const enrichedAction = {
996
+ ...scope.$action,
997
+ handleCreate,
998
+ setSearch
999
+ };
1000
+ const enrichedInstance = scope.$instance ? { ...scope.$instance, handleCreate, setSearch } : void 0;
1001
+ return {
1002
+ ...scope,
1003
+ $action: enrichedAction,
1004
+ $instance: enrichedInstance,
1005
+ // Also add at top-level for direct access
1006
+ handleCreate,
1007
+ setSearch
1008
+ };
1009
+ }, [scope, primarySlug, resolver, handleRefreshQuery, handleSetLocal]);
1010
+ if (node.visible_when) {
1011
+ const ctx = buildEvalContext(enrichedScope);
1012
+ const visible = evaluateExpression(node.visible_when, ctx);
1013
+ if (!visible) return null;
1014
+ }
1015
+ if (node.$if) {
1016
+ const ctx = buildEvalContext(enrichedScope);
1017
+ const visible = evaluateExpression(node.$if, ctx);
1018
+ if (!visible) return null;
1019
+ }
1020
+ const resolvedBindings = node.bindings ? resolveAllBindings(node.bindings, enrichedScope) : {};
1021
+ const config = node.config ?? node.props ?? {};
1022
+ const rawMerged = { ...config, ...resolvedBindings };
1023
+ const mergedProps = {};
1024
+ for (const [k, v] of Object.entries(rawMerged)) {
1025
+ mergedProps[k] = resolveTokens(v, themeTokens);
1026
+ }
1027
+ if (node.className) mergedProps.className = node.className;
1028
+ if (node.id) mergedProps["data-node-id"] = node.id;
1029
+ const loadingAny = Object.values(dsResults).some((r) => r.loading);
1030
+ if (Object.keys(dsResults).length > 0) {
1031
+ mergedProps.loading = loadingAny;
1032
+ const firstResult = Object.values(dsResults)[0];
1033
+ if (firstResult?.instances) mergedProps.data = firstResult.instances;
1034
+ if (firstResult?.instance) mergedProps.instance = firstResult.instance;
1035
+ if (firstResult?.pagination) mergedProps.pagination = firstResult.pagination;
1036
+ if (firstResult?.definition) mergedProps.definition = firstResult.definition;
1037
+ }
1038
+ const componentName = node.component ?? node.type ?? "";
1039
+ let AtomComponent = null;
1040
+ if (atomRegistry) {
1041
+ const lazy = atomRegistry.resolve(componentName);
1042
+ if (lazy) AtomComponent = lazy;
1043
+ }
1044
+ if (!AtomComponent) {
1045
+ if (!componentName && node.children?.length) {
1046
+ 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)) }) });
1047
+ }
1048
+ if (componentName) {
1049
+ return /* @__PURE__ */ jsxs("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
1050
+ "Unknown: ",
1051
+ componentName
1052
+ ] });
1053
+ }
1054
+ return null;
1055
+ }
1056
+ let children = null;
1057
+ if (node.children?.length) {
1058
+ children = node.children.map((child, i) => /* @__PURE__ */ jsx2(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ jsx2(NodeRenderer, { node: child, fallback }) }, child.id ?? i));
1059
+ }
1060
+ if (!children && mergedProps.children != null) {
1061
+ children = mergedProps.children;
1062
+ delete mergedProps.children;
1063
+ }
1064
+ delete mergedProps.localDefaults;
1065
+ delete mergedProps.dataSources;
1066
+ delete mergedProps.bindings;
1067
+ delete mergedProps.visible_when;
1068
+ 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: [
1069
+ "Loading ",
1070
+ componentName,
1071
+ "..."
1072
+ ] }), children: /* @__PURE__ */ jsx2(AtomComponent, { ...mergedProps, children }) }) }) });
1073
+ };
1074
+ var ExperienceRenderer = ({
1075
+ tree,
1076
+ initialScope,
1077
+ entity,
1078
+ fallback,
1079
+ className
1080
+ }) => {
1081
+ const playerCtx = usePlayerContext();
1082
+ const nodes = Array.isArray(tree) ? tree : [tree];
1083
+ const rootScope = useMemo2(() => buildScope({
1084
+ auth: playerCtx?.auth ?? initialScope?.auth,
1085
+ entity,
1086
+ localState: initialScope?.$local ?? {},
1087
+ actionScope: initialScope?.$action ?? {
1088
+ transition: async () => {
1089
+ },
1090
+ create: async () => "",
1091
+ update: async () => {
1092
+ },
1093
+ remove: async () => {
1094
+ },
1095
+ setLocal: () => {
1096
+ },
1097
+ navigate: () => {
1098
+ },
1099
+ toast: () => {
1100
+ },
1101
+ refreshQuery: () => {
1102
+ },
1103
+ scrollTo: () => {
1104
+ },
1105
+ openModal: () => {
1106
+ },
1107
+ closeModal: () => {
1108
+ },
1109
+ emit: () => {
1110
+ }
1111
+ }
1112
+ }), [playerCtx?.auth, entity, initialScope]);
1113
+ return /* @__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)) }) });
1114
+ };
1115
+
1116
+ // src/player/resolver.ts
1117
+ function getToken(token) {
1118
+ if (!token) return null;
1119
+ if (typeof token === "function") return token();
1120
+ return token;
1121
+ }
1122
+ function normalizeInstance(raw) {
1123
+ return {
1124
+ id: String(raw.id ?? ""),
1125
+ state: String(raw.current_state ?? raw.state ?? "unknown"),
1126
+ fields: raw.state_data ?? raw.fields ?? {},
1127
+ slug: raw.definition_slug,
1128
+ created_at: raw.created_at,
1129
+ updated_at: raw.updated_at,
1130
+ ...raw
1131
+ };
1132
+ }
1133
+ function createApiResolver(config) {
1134
+ const { baseUrl, defaults } = config;
1135
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
1136
+ const defCache = /* @__PURE__ */ new Map();
1137
+ async function apiRequest(path, options = {}) {
1138
+ const tok = getToken(config.token);
1139
+ const headers = {
1140
+ "Content-Type": "application/json",
1141
+ ...options.headers ?? {}
1142
+ };
1143
+ if (tok) headers["Authorization"] = `Bearer ${tok}`;
1144
+ const response = await fetchFn(`${baseUrl}${path}`, {
1145
+ ...options,
1146
+ headers
1147
+ });
1148
+ if (!response.ok) {
1149
+ const body = await response.text().catch(() => "");
1150
+ let message = `API error ${response.status}: ${response.statusText}`;
1151
+ try {
1152
+ const parsed = JSON.parse(body);
1153
+ if (parsed.message) message = parsed.message;
1154
+ if (parsed.error) message = `${parsed.error}: ${parsed.message || ""}`;
1155
+ } catch {
1156
+ }
1157
+ throw new Error(message);
1158
+ }
1159
+ return response.json();
1160
+ }
1161
+ const resolver = {
1162
+ async query(slug, params) {
1163
+ const searchParams = new URLSearchParams();
1164
+ searchParams.set("definition", slug);
1165
+ if (params.state) {
1166
+ const states = Array.isArray(params.state) ? params.state : [params.state];
1167
+ states.forEach((s) => searchParams.append("state", s));
1168
+ }
1169
+ if (params.status) searchParams.set("status", params.status);
1170
+ if (params.limit ?? defaults?.limit) searchParams.set("limit", String(params.limit ?? defaults?.limit ?? 20));
1171
+ if (params.page) searchParams.set("page", String(params.page));
1172
+ if (params.offset) searchParams.set("offset", String(params.offset));
1173
+ if (params.search) searchParams.set("search", params.search);
1174
+ if (params.searchFields?.length) searchParams.set("search_fields", params.searchFields.join(","));
1175
+ if (params.sort) {
1176
+ if (typeof params.sort === "string") {
1177
+ searchParams.set("sort", params.sort);
1178
+ } else if (Array.isArray(params.sort)) {
1179
+ const sortStr = params.sort.map((s) => `${s.direction === "desc" ? "-" : ""}${s.field}`).join(",");
1180
+ searchParams.set("sort", sortStr);
1181
+ }
1182
+ }
1183
+ if (params.filter) {
1184
+ searchParams.set("state_filter", JSON.stringify(params.filter));
1185
+ }
1186
+ if (params.facets?.length) {
1187
+ searchParams.set("facets", params.facets.join(","));
1188
+ }
1189
+ if (params.entity) {
1190
+ searchParams.set("entity_type", params.entity.type);
1191
+ searchParams.set("entity_id", params.entity.id);
1192
+ }
1193
+ if (params.parentInstanceId) {
1194
+ searchParams.set("spawned_by_instance_id", params.parentInstanceId);
1195
+ }
1196
+ if (params.includeDefinition) {
1197
+ searchParams.set("include_definition", "true");
1198
+ }
1199
+ const raw = await apiRequest(
1200
+ `/workflow/instances?${searchParams.toString()}`
1201
+ );
1202
+ const items = raw.items ?? raw.data ?? [];
1203
+ const total = Number(raw.total ?? raw.count ?? items.length);
1204
+ const page = Number(raw.page ?? params.page ?? 1);
1205
+ const pageSize = Number(raw.page_size ?? raw.pageSize ?? params.limit ?? defaults?.limit ?? 20);
1206
+ const result = {
1207
+ data: items.map(normalizeInstance),
1208
+ total,
1209
+ page,
1210
+ pageSize
1211
+ };
1212
+ if (raw.definition) result.definition = raw.definition;
1213
+ if (raw.facets) result.facets = raw.facets;
1214
+ if (raw.aggregates) result.aggregates = raw.aggregates;
1215
+ if (raw.grouped) result.grouped = raw.grouped;
1216
+ return result;
1217
+ },
1218
+ async getInstance(id) {
1219
+ const raw = await apiRequest(`/workflow/instances/${id}`);
1220
+ return normalizeInstance(raw);
1221
+ },
1222
+ async getDefinition(slug) {
1223
+ const cached = defCache.get(slug);
1224
+ if (cached && cached.expires > Date.now()) return cached.data;
1225
+ const raw = await apiRequest(`/workflow/definitions/slug/${slug}`);
1226
+ defCache.set(slug, { data: raw, expires: Date.now() + 5 * 60 * 1e3 });
1227
+ return raw;
1228
+ },
1229
+ async create(slug, data) {
1230
+ const raw = await apiRequest("/workflow/instances", {
1231
+ method: "POST",
1232
+ body: JSON.stringify({
1233
+ definition_slug: slug,
1234
+ state_data: data ?? {}
1235
+ })
1236
+ });
1237
+ return String(raw.id);
1238
+ },
1239
+ async update(id, fields) {
1240
+ await apiRequest(`/workflow/instances/${id}/state-data`, {
1241
+ method: "PATCH",
1242
+ body: JSON.stringify(fields)
1243
+ });
1244
+ },
1245
+ async transition(id, name, data) {
1246
+ const raw = await apiRequest(
1247
+ `/workflow/instances/${id}/transitions/${name}`,
1248
+ {
1249
+ method: "POST",
1250
+ body: JSON.stringify({ data: data ?? {} })
1251
+ }
1252
+ );
1253
+ return raw;
1254
+ },
1255
+ async remove(id) {
1256
+ await apiRequest(`/workflow/instances/${id}`, { method: "DELETE" });
1257
+ },
1258
+ async availableTransitions(id) {
1259
+ const raw = await apiRequest(`/workflow/instances/${id}/transitions`);
1260
+ return Array.isArray(raw) ? raw : [];
1261
+ },
1262
+ async fetch(endpoint, fetchConfig) {
1263
+ return apiRequest(endpoint, {
1264
+ method: fetchConfig.method ?? "GET",
1265
+ body: fetchConfig.body ? JSON.stringify(fetchConfig.body) : void 0,
1266
+ headers: fetchConfig.headers
1267
+ });
1268
+ }
1269
+ };
1270
+ return resolver;
1271
+ }
1272
+
1273
+ // src/player/ComponentTreeRenderer.tsx
1274
+ import React4, { useMemo as useMemo3, useCallback as useCallback4 } from "react";
1275
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1276
+ var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
1277
+ function containsExpression(value) {
1278
+ return typeof value === "string" && EXPR_PATTERN.test(value);
1279
+ }
1280
+ function evaluateProp(value, scopes) {
1281
+ if (typeof value !== "string") return value;
1282
+ const fullMatch = value.match(/^\{\{(.+)\}\}$/s);
1283
+ if (fullMatch) return evaluateExpression(fullMatch[1], scopes);
1284
+ if (containsExpression(value)) {
1285
+ return value.replace(EXPR_PATTERN, (_, expr) => {
1286
+ const result = evaluateExpression(expr, scopes);
1287
+ return result == null ? "" : String(result);
1288
+ });
1289
+ }
1290
+ return value;
1291
+ }
1292
+ 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: [
1293
+ /* @__PURE__ */ jsxs2("span", { style: { fontWeight: 600 }, children: [
1294
+ "Unknown: ",
1295
+ type
1296
+ ] }),
1297
+ children && /* @__PURE__ */ jsx3("div", { style: { marginTop: 4 }, children })
1298
+ ] });
1299
+ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
1300
+ const nodeType = node.type || node.component || "";
1301
+ const nodeProps = node.props || node.config || {};
1302
+ if (node.$if) {
1303
+ const condition = evaluateProp(node.$if, scopes);
1304
+ if (!condition) return null;
1305
+ }
1306
+ if (node.$for) {
1307
+ const { each, as, key: keyField } = node.$for;
1308
+ const items = evaluateProp(each, scopes);
1309
+ if (!Array.isArray(items)) return null;
1310
+ return /* @__PURE__ */ jsx3(Fragment, { children: items.map((item, index) => {
1311
+ const loopScopes = {
1312
+ ...scopes,
1313
+ state_data: {
1314
+ ...scopes.state_data ?? {},
1315
+ [as]: item,
1316
+ [`${as}Index`]: index
1317
+ }
1318
+ };
1319
+ const nodeWithoutFor = { ...node, $for: void 0 };
1320
+ const itemKey = keyField ? String(item[keyField] ?? index) : String(index);
1321
+ return /* @__PURE__ */ jsx3(RenderNode, { node: nodeWithoutFor, scopes: loopScopes, atoms, onEvent }, itemKey);
1322
+ }) });
1323
+ }
1324
+ const Component = atoms[nodeType];
1325
+ if (!Component) {
1326
+ return /* @__PURE__ */ jsx3(UnknownAtom, { type: nodeType });
1327
+ }
1328
+ const evaluatedProps = {};
1329
+ if (node.className) evaluatedProps.className = node.className;
1330
+ if (node.id) evaluatedProps["data-node-id"] = node.id;
1331
+ for (const [key, value] of Object.entries(nodeProps)) {
1332
+ if (key.startsWith("on") && typeof value === "string") {
1333
+ evaluatedProps[key] = (...args) => {
1334
+ if (containsExpression(value)) {
1335
+ evaluateExpression(value.replace(/^\{\{|\}\}$/g, ""), scopes);
1336
+ } else {
1337
+ onEvent(value, args[0]);
1338
+ }
1339
+ };
1340
+ } else {
1341
+ evaluatedProps[key] = evaluateProp(value, scopes);
1342
+ }
1343
+ }
1344
+ let children = null;
1345
+ if (node.children) {
1346
+ if (typeof node.children === "string") {
1347
+ children = evaluateProp(node.children, scopes);
1348
+ } else if (Array.isArray(node.children)) {
1349
+ children = node.children.map((child, index) => /* @__PURE__ */ jsx3(RenderNode, { node: child, scopes, atoms, onEvent }, child.id || index));
1350
+ }
1351
+ }
1352
+ return /* @__PURE__ */ jsx3(Component, { ...evaluatedProps, children });
1353
+ };
1354
+ var CTRErrorBoundary = class extends React4.Component {
1355
+ constructor(props) {
1356
+ super(props);
1357
+ this.state = { hasError: false };
1358
+ }
1359
+ static getDerivedStateFromError(error) {
1360
+ return { hasError: true, error };
1361
+ }
1362
+ componentDidCatch(error, errorInfo) {
1363
+ console.error("CTR rendering error:", error, errorInfo);
1364
+ }
1365
+ render() {
1366
+ if (this.state.hasError) {
1367
+ return this.props.fallback || /* @__PURE__ */ jsxs2("div", { style: { padding: 16, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 8 }, children: [
1368
+ /* @__PURE__ */ jsx3("strong", { style: { color: "#c53030" }, children: "Rendering Error" }),
1369
+ /* @__PURE__ */ jsx3("p", { style: { color: "#e53e3e", fontSize: 14, marginTop: 4 }, children: this.state.error?.message || "An error occurred while rendering" })
1370
+ ] });
1371
+ }
1372
+ return this.props.children;
1373
+ }
1374
+ };
1375
+ var ComponentTreeRenderer = ({
1376
+ tree,
1377
+ scopes,
1378
+ atoms = {},
1379
+ onEvent = () => {
1380
+ },
1381
+ fallback
1382
+ }) => {
1383
+ const allAtoms = useMemo3(() => ({ ...atoms }), [atoms]);
1384
+ const handleEvent = useCallback4(
1385
+ (eventName, payload) => onEvent(eventName, payload),
1386
+ [onEvent]
1387
+ );
1388
+ const nodes = Array.isArray(tree) ? tree : [tree];
1389
+ return /* @__PURE__ */ jsx3(CTRErrorBoundary, { fallback, children: nodes.map((node, index) => /* @__PURE__ */ jsx3(RenderNode, { node, scopes, atoms: allAtoms, onEvent: handleEvent }, index)) });
1390
+ };
1391
+
1392
+ // src/player/builtin-atoms.tsx
1393
+ import React5 from "react";
1394
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1395
+ var Stack = ({ children, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, ...rest, children });
1396
+ 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 });
1397
+ var Column = ({ children, span, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { flex: span ? `0 0 ${Number(span) / 12 * 100}%` : 1, ...style }, ...rest, children });
1398
+ var Grid = ({ children, columns = 2, gap = 8, style, ...rest }) => /* @__PURE__ */ jsx4("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap, ...style }, ...rest, children });
1399
+ var Divider = ({ style }) => /* @__PURE__ */ jsx4("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "8px 0", ...style } });
1400
+ var Spacer = ({ size = 16 }) => /* @__PURE__ */ jsx4("div", { style: { height: size, flexShrink: 0 } });
1401
+ var Text = ({ children, size, weight, color, style, ...rest }) => /* @__PURE__ */ jsx4("span", { style: { fontSize: size, fontWeight: weight, color, ...style }, ...rest, children });
1402
+ var Heading = ({ children, level = 2, style, ...rest }) => {
1403
+ const lvl = Math.min(Math.max(Number(level), 1), 6);
1404
+ const s = { margin: "0 0 8px", ...style };
1405
+ const c = children;
1406
+ if (lvl === 1) return /* @__PURE__ */ jsx4("h1", { style: s, ...rest, children: c });
1407
+ if (lvl === 2) return /* @__PURE__ */ jsx4("h2", { style: s, ...rest, children: c });
1408
+ if (lvl === 3) return /* @__PURE__ */ jsx4("h3", { style: s, ...rest, children: c });
1409
+ if (lvl === 4) return /* @__PURE__ */ jsx4("h4", { style: s, ...rest, children: c });
1410
+ if (lvl === 5) return /* @__PURE__ */ jsx4("h5", { style: s, ...rest, children: c });
1411
+ return /* @__PURE__ */ jsx4("h6", { style: s, ...rest, children: c });
1412
+ };
1413
+ var Field = ({ label, value, children, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8, ...style }, children: [
1414
+ label ? /* @__PURE__ */ jsx4("div", { style: { fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1415
+ /* @__PURE__ */ jsx4("div", { style: { fontSize: 14 }, children: children ?? value ?? "\u2014" })
1416
+ ] });
1417
+ var Badge = ({ children, variant = "default", style }) => {
1418
+ const colors = {
1419
+ default: { bg: "#edf2f7", fg: "#4a5568" },
1420
+ success: { bg: "#c6f6d5", fg: "#276749" },
1421
+ warning: { bg: "#fefcbf", fg: "#975a16" },
1422
+ error: { bg: "#fed7d7", fg: "#9b2c2c" },
1423
+ info: { bg: "#bee3f8", fg: "#2a4365" }
1424
+ };
1425
+ const c = colors[variant] ?? colors.default;
1426
+ 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 });
1427
+ };
1428
+ var ImageAtom = ({ src, alt, width, height, style, ...rest }) => /* @__PURE__ */ jsx4("img", { src, alt: alt ?? "", width, height, style: { maxWidth: "100%", ...style }, ...rest });
1429
+ var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest }) => {
1430
+ const styles = {
1431
+ primary: { background: "#3182ce", color: "#fff", border: "none" },
1432
+ secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
1433
+ danger: { background: "#e53e3e", color: "#fff", border: "none" },
1434
+ ghost: { background: "transparent", color: "#4a5568", border: "none" }
1435
+ };
1436
+ const base = styles[variant] ?? styles.primary;
1437
+ return /* @__PURE__ */ jsx4(
1438
+ "button",
1439
+ {
1440
+ onClick,
1441
+ disabled,
1442
+ style: { padding: "6px 16px", borderRadius: 6, fontSize: 14, fontWeight: 500, cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1, ...base, ...style },
1443
+ ...rest,
1444
+ children
1445
+ }
1446
+ );
1447
+ };
1448
+ var LinkAtom = ({ children, href, style, ...rest }) => /* @__PURE__ */ jsx4("a", { href, style: { color: "#3182ce", textDecoration: "underline", ...style }, ...rest, children });
1449
+ var TextInput = ({ value, onChange, placeholder, label, bind: _bind, style }) => {
1450
+ const isControlled = typeof onChange === "function";
1451
+ const [localValue, setLocalValue] = React5.useState(value ?? "");
1452
+ const handleChange = (e) => {
1453
+ setLocalValue(e.target.value);
1454
+ if (typeof onChange === "function") onChange(e);
1455
+ };
1456
+ return /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1457
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1458
+ /* @__PURE__ */ jsx4(
1459
+ "input",
1460
+ {
1461
+ type: "text",
1462
+ value: isControlled ? value ?? "" : localValue,
1463
+ onChange: handleChange,
1464
+ placeholder,
1465
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style }
1466
+ }
1467
+ )
1468
+ ] });
1469
+ };
1470
+ var SelectAtom = ({ value, onChange, options, label, placeholder, style }) => /* @__PURE__ */ jsxs3("div", { style: { marginBottom: 8 }, children: [
1471
+ label ? /* @__PURE__ */ jsx4("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
1472
+ /* @__PURE__ */ jsxs3(
1473
+ "select",
1474
+ {
1475
+ value: value ?? "",
1476
+ onChange,
1477
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
1478
+ children: [
1479
+ placeholder ? /* @__PURE__ */ jsx4("option", { value: "", children: placeholder }) : null,
1480
+ Array.isArray(options) && options.map((opt) => {
1481
+ const v = typeof opt === "string" ? opt : opt.value;
1482
+ const l = typeof opt === "string" ? opt : opt.label;
1483
+ return /* @__PURE__ */ jsx4("option", { value: v, children: l }, v);
1484
+ })
1485
+ ]
1486
+ }
1487
+ )
1488
+ ] });
1489
+ var Card = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("div", { style: { border: "1px solid #e2e8f0", borderRadius: 8, padding: 16, background: "#fff", ...style }, ...rest, children: [
1490
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: 12 }, children: title }) : null,
1491
+ children
1492
+ ] });
1493
+ var Section = ({ children, title, style, ...rest }) => /* @__PURE__ */ jsxs3("section", { style: { marginBottom: 24, ...style }, ...rest, children: [
1494
+ title ? /* @__PURE__ */ jsx4("h3", { style: { fontSize: 18, fontWeight: 600, marginBottom: 8 }, children: title }) : null,
1495
+ children
1496
+ ] });
1497
+ var Show = ({ when, children, fallback }) => when ? /* @__PURE__ */ jsx4(Fragment2, { children }) : /* @__PURE__ */ jsx4(Fragment2, { children: fallback ?? null });
1498
+ var Each = ({ items, children, renderItem }) => {
1499
+ if (!Array.isArray(items)) return null;
1500
+ if (typeof renderItem === "function") return /* @__PURE__ */ jsx4(Fragment2, { children: items.map((item, i) => renderItem(item, i)) });
1501
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1502
+ };
1503
+ var RouterContext = React5.createContext({ path: "/", navigate: () => {
1504
+ } });
1505
+ var Router = ({ children, basePath, className, style, ...rest }) => {
1506
+ const [path, setPath] = React5.useState("/");
1507
+ const navigate = React5.useCallback((to) => setPath(to), []);
1508
+ return /* @__PURE__ */ jsx4(RouterContext.Provider, { value: { path, navigate }, children: /* @__PURE__ */ jsx4("div", { className, style, ...rest, children }) });
1509
+ };
1510
+ var Route = ({ children, path, exact, fallback: _fallback, className, style }) => {
1511
+ const { path: currentPath } = React5.useContext(RouterContext);
1512
+ const routePath = path || "/";
1513
+ const isExact = exact !== false;
1514
+ const matches = isExact ? currentPath === routePath || routePath === "/" && currentPath === "/" : currentPath.startsWith(routePath);
1515
+ if (!matches) return null;
1516
+ return /* @__PURE__ */ jsx4("div", { className, style, children });
1517
+ };
1518
+ var NavLink = ({ children, to, label, icon, className, style, ...rest }) => {
1519
+ const { path, navigate } = React5.useContext(RouterContext);
1520
+ const target = to || "/";
1521
+ const isActive = path === target;
1522
+ return /* @__PURE__ */ jsx4(
1523
+ "button",
1524
+ {
1525
+ onClick: () => navigate(target),
1526
+ className,
1527
+ style: {
1528
+ background: isActive ? "#edf2f7" : "transparent",
1529
+ border: "none",
1530
+ borderRadius: 4,
1531
+ padding: "4px 12px",
1532
+ fontSize: 13,
1533
+ cursor: "pointer",
1534
+ fontWeight: isActive ? 600 : 400,
1535
+ color: isActive ? "#2d3748" : "#718096",
1536
+ ...style
1537
+ },
1538
+ ...rest,
1539
+ children: children || label || target
1540
+ }
1541
+ );
1542
+ };
1543
+ var RoleGuard = ({ children, role: _role, fallback: _fallback }) => {
1544
+ return /* @__PURE__ */ jsx4(Fragment2, { children });
1545
+ };
1546
+ 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" });
1547
+ var iconGlyphs = {
1548
+ home: "\u2302",
1549
+ settings: "\u2699",
1550
+ plus: "+",
1551
+ search: "\u{1F50D}",
1552
+ box: "\u25A1",
1553
+ inbox: "\u2709",
1554
+ chevronRight: "\u203A",
1555
+ chevronLeft: "\u2039",
1556
+ x: "\u2715",
1557
+ check: "\u2713",
1558
+ edit: "\u270E",
1559
+ trash: "\u{1F5D1}",
1560
+ star: "\u2605",
1561
+ heart: "\u2665",
1562
+ user: "\u{1F464}",
1563
+ menu: "\u2630",
1564
+ close: "\u2715",
1565
+ arrow_right: "\u2192",
1566
+ arrow_left: "\u2190"
1567
+ };
1568
+ var Tabs = ({ children, tabs, defaultTab, style }) => {
1569
+ const tabList = tabs || [];
1570
+ const [active, setActive] = React5.useState(defaultTab || tabList[0]?.id || "");
1571
+ return /* @__PURE__ */ jsxs3("div", { style, children: [
1572
+ /* @__PURE__ */ jsx4("div", { style: { display: "flex", borderBottom: "1px solid #e2e8f0", marginBottom: 12 }, children: tabList.map((t) => /* @__PURE__ */ jsx4(
1573
+ "button",
1574
+ {
1575
+ onClick: () => setActive(t.id),
1576
+ 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" },
1577
+ children: t.label
1578
+ },
1579
+ t.id
1580
+ )) }),
1581
+ children
1582
+ ] });
1583
+ };
1584
+ var Accordion = ({ children, style }) => /* @__PURE__ */ jsx4("div", { style, children });
1585
+ var Modal = ({ children, open, title, onClose: _onClose, style }) => {
1586
+ if (!open) return null;
1587
+ 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: [
1588
+ title ? /* @__PURE__ */ jsx4("div", { style: { fontWeight: 600, fontSize: 18, marginBottom: 16 }, children: String(title) }) : null,
1589
+ children
1590
+ ] }) });
1591
+ };
1592
+ var Markdown = ({ content, children, style }) => /* @__PURE__ */ jsx4("div", { style: { lineHeight: 1.6, ...style }, children: content || children });
1593
+ var ScrollArea = ({ children, maxHeight = 400, style }) => /* @__PURE__ */ jsx4("div", { style: { overflow: "auto", maxHeight, ...style }, children });
1594
+ var Slot = ({ children, fallback }) => /* @__PURE__ */ jsx4(Fragment2, { children: children || fallback || null });
1595
+ var ModuleOutlet = ({ children, module: moduleName, fallback }) => /* @__PURE__ */ jsx4("div", { "data-module": moduleName, children: children || fallback || /* @__PURE__ */ jsxs3("span", { style: { color: "#a0aec0", fontSize: 13 }, children: [
1596
+ "Module: ",
1597
+ moduleName
1598
+ ] }) });
1599
+ var builtinAtoms = {
1600
+ // Layout
1601
+ Stack,
1602
+ Row,
1603
+ Column,
1604
+ Grid,
1605
+ Divider,
1606
+ Spacer,
1607
+ // Typography
1608
+ Text,
1609
+ Heading,
1610
+ Field,
1611
+ Badge,
1612
+ Image: ImageAtom,
1613
+ Icon,
1614
+ // Interactive
1615
+ Button,
1616
+ Link: LinkAtom,
1617
+ // Form
1618
+ TextInput,
1619
+ Select: SelectAtom,
1620
+ // Containers
1621
+ Card,
1622
+ Section,
1623
+ Tabs,
1624
+ Accordion,
1625
+ Modal,
1626
+ // Content
1627
+ Markdown,
1628
+ ScrollArea,
1629
+ // Control Flow
1630
+ Show,
1631
+ Each,
1632
+ // Routing
1633
+ Router,
1634
+ Route,
1635
+ NavLink,
1636
+ RoleGuard,
1637
+ // Composition
1638
+ Slot,
1639
+ ModuleOutlet
1640
+ };
1641
+
1642
+ // src/player/DevPlayer.tsx
1643
+ import { useState as useState4, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect4, useMemo as useMemo4 } from "react";
1644
+ import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
1645
+ var S = {
1646
+ shell: {
1647
+ display: "flex",
1648
+ flexDirection: "column",
1649
+ height: "100%",
1650
+ minHeight: "100vh",
1651
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
1652
+ background: "#f7fafc",
1653
+ color: "#1a202c"
1654
+ },
1655
+ toolbar: {
1656
+ display: "flex",
1657
+ alignItems: "center",
1658
+ gap: 12,
1659
+ padding: "8px 16px",
1660
+ background: "#1a202c",
1661
+ color: "#e2e8f0",
1662
+ fontSize: 13,
1663
+ flexShrink: 0
1664
+ },
1665
+ toolbarTitle: { fontWeight: 600, fontSize: 14 },
1666
+ toolbarBadge: {
1667
+ display: "inline-block",
1668
+ padding: "1px 8px",
1669
+ borderRadius: 4,
1670
+ background: "#2d3748",
1671
+ color: "#a0aec0",
1672
+ fontSize: 11,
1673
+ fontFamily: "monospace"
1674
+ },
1675
+ toolbarBtn: {
1676
+ background: "none",
1677
+ border: "1px solid #4a5568",
1678
+ borderRadius: 4,
1679
+ color: "#a0aec0",
1680
+ padding: "2px 10px",
1681
+ fontSize: 12,
1682
+ cursor: "pointer"
1683
+ },
1684
+ toolbarBtnActive: {
1685
+ background: "#2b6cb0",
1686
+ borderColor: "#2b6cb0",
1687
+ color: "#fff"
1688
+ },
1689
+ body: { display: "flex", flex: 1, overflow: "hidden" },
1690
+ preview: { flex: 1, overflow: "auto", padding: 24 },
1691
+ sidebar: {
1692
+ width: 340,
1693
+ flexShrink: 0,
1694
+ borderLeft: "1px solid #e2e8f0",
1695
+ background: "#fff",
1696
+ overflow: "auto",
1697
+ fontSize: 13
1698
+ },
1699
+ sidebarSection: { padding: "12px 16px", borderBottom: "1px solid #f0f0f0" },
1700
+ sidebarHeading: {
1701
+ fontSize: 11,
1702
+ fontWeight: 700,
1703
+ textTransform: "uppercase",
1704
+ color: "#a0aec0",
1705
+ letterSpacing: "0.05em",
1706
+ marginBottom: 8
1707
+ },
1708
+ pre: {
1709
+ background: "#f7fafc",
1710
+ border: "1px solid #e2e8f0",
1711
+ borderRadius: 6,
1712
+ padding: "8px 12px",
1713
+ fontSize: 12,
1714
+ fontFamily: "monospace",
1715
+ whiteSpace: "pre-wrap",
1716
+ wordBreak: "break-word",
1717
+ maxHeight: 260,
1718
+ overflow: "auto"
1719
+ },
1720
+ eventRow: {
1721
+ display: "flex",
1722
+ gap: 8,
1723
+ padding: "4px 0",
1724
+ borderBottom: "1px solid #f7fafc",
1725
+ fontSize: 12,
1726
+ fontFamily: "monospace"
1727
+ },
1728
+ eventTime: { color: "#a0aec0", flexShrink: 0 },
1729
+ eventName: { color: "#3182ce", fontWeight: 500 },
1730
+ dot: (connected) => ({
1731
+ width: 8,
1732
+ height: 8,
1733
+ borderRadius: "50%",
1734
+ background: connected ? "#48bb78" : "#e53e3e",
1735
+ flexShrink: 0
1736
+ })
1737
+ };
1738
+ function useDevSocket(wsUrl, onReload) {
1739
+ const [connected, setConnected] = useState4(false);
1740
+ const wsRef = useRef5(null);
1741
+ useEffect4(() => {
1742
+ if (typeof window === "undefined") return;
1743
+ const url = wsUrl ?? `ws://${window.location.host}/__mm_dev`;
1744
+ let ws;
1745
+ let reconnectTimer;
1746
+ function connect() {
1747
+ try {
1748
+ ws = new WebSocket(url);
1749
+ wsRef.current = ws;
1750
+ ws.onopen = () => setConnected(true);
1751
+ ws.onclose = () => {
1752
+ setConnected(false);
1753
+ reconnectTimer = setTimeout(connect, 3e3);
1754
+ };
1755
+ ws.onmessage = (ev) => {
1756
+ try {
1757
+ const msg = JSON.parse(ev.data);
1758
+ if (msg.type === "workflow:compiled" || msg.type === "workflow:rebuild") {
1759
+ onReload?.();
1760
+ }
1761
+ } catch {
1762
+ }
1763
+ };
1764
+ } catch {
1765
+ reconnectTimer = setTimeout(connect, 3e3);
1766
+ }
1767
+ }
1768
+ connect();
1769
+ return () => {
1770
+ clearTimeout(reconnectTimer);
1771
+ wsRef.current?.close();
1772
+ wsRef.current = null;
1773
+ };
1774
+ }, [wsUrl, onReload]);
1775
+ return connected;
1776
+ }
1777
+ var DevPlayer = ({
1778
+ tree,
1779
+ scopes = {},
1780
+ atoms: userAtoms,
1781
+ title = "DevPlayer",
1782
+ bare = false,
1783
+ wsUrl,
1784
+ onReload,
1785
+ onEvent: externalOnEvent
1786
+ }) => {
1787
+ const [showSidebar, setShowSidebar] = useState4(true);
1788
+ const [events, setEvents] = useState4([]);
1789
+ const nextId = useRef5(0);
1790
+ const connected = useDevSocket(wsUrl, onReload);
1791
+ const mergedAtoms = useMemo4(
1792
+ () => ({ ...builtinAtoms, ...userAtoms }),
1793
+ [userAtoms]
1794
+ );
1795
+ const handleEvent = useCallback5(
1796
+ (name, payload) => {
1797
+ setEvents((prev) => {
1798
+ const entry = {
1799
+ id: nextId.current++,
1800
+ time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }),
1801
+ name,
1802
+ payload
1803
+ };
1804
+ const next = [entry, ...prev];
1805
+ return next.length > 100 ? next.slice(0, 100) : next;
1806
+ });
1807
+ externalOnEvent?.(name, payload);
1808
+ },
1809
+ [externalOnEvent]
1810
+ );
1811
+ if (bare) {
1812
+ return /* @__PURE__ */ jsx5(
1813
+ ComponentTreeRenderer,
1814
+ {
1815
+ tree,
1816
+ scopes,
1817
+ atoms: mergedAtoms,
1818
+ onEvent: handleEvent
1819
+ }
1820
+ );
1821
+ }
1822
+ return /* @__PURE__ */ jsxs4("div", { style: S.shell, children: [
1823
+ /* @__PURE__ */ jsxs4("div", { style: S.toolbar, children: [
1824
+ /* @__PURE__ */ jsx5("div", { style: S.dot(connected), title: connected ? "HMR connected" : "HMR disconnected" }),
1825
+ /* @__PURE__ */ jsx5("span", { style: S.toolbarTitle, children: title }),
1826
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1827
+ Array.isArray(tree) ? tree.length : 1,
1828
+ " node",
1829
+ Array.isArray(tree) && tree.length !== 1 ? "s" : ""
1830
+ ] }),
1831
+ /* @__PURE__ */ jsxs4("span", { style: S.toolbarBadge, children: [
1832
+ Object.keys(mergedAtoms).length,
1833
+ " atoms"
1834
+ ] }),
1835
+ /* @__PURE__ */ jsx5("div", { style: { flex: 1 } }),
1836
+ /* @__PURE__ */ jsx5(
1837
+ "button",
1838
+ {
1839
+ style: { ...S.toolbarBtn, ...showSidebar ? S.toolbarBtnActive : {} },
1840
+ onClick: () => setShowSidebar((v) => !v),
1841
+ children: "Inspector"
1842
+ }
1843
+ )
1844
+ ] }),
1845
+ /* @__PURE__ */ jsxs4("div", { style: S.body, children: [
1846
+ /* @__PURE__ */ jsx5("div", { style: S.preview, children: /* @__PURE__ */ jsx5(
1847
+ ComponentTreeRenderer,
1848
+ {
1849
+ tree,
1850
+ scopes,
1851
+ atoms: mergedAtoms,
1852
+ onEvent: handleEvent
1853
+ }
1854
+ ) }),
1855
+ showSidebar && /* @__PURE__ */ jsxs4("div", { style: S.sidebar, children: [
1856
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1857
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Scopes" }),
1858
+ /* @__PURE__ */ jsx5("pre", { style: S.pre, children: JSON.stringify(scopes, null, 2) })
1859
+ ] }),
1860
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1861
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1862
+ "Atoms (",
1863
+ Object.keys(mergedAtoms).length,
1864
+ ")"
1865
+ ] }),
1866
+ /* @__PURE__ */ jsx5("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(mergedAtoms).sort().map((name) => /* @__PURE__ */ jsx5(
1867
+ "span",
1868
+ {
1869
+ style: {
1870
+ display: "inline-block",
1871
+ padding: "1px 6px",
1872
+ borderRadius: 3,
1873
+ background: userAtoms?.[name] ? "#ebf8ff" : "#f7fafc",
1874
+ border: `1px solid ${userAtoms?.[name] ? "#90cdf4" : "#e2e8f0"}`,
1875
+ fontSize: 11,
1876
+ fontFamily: "monospace",
1877
+ color: userAtoms?.[name] ? "#2b6cb0" : "#718096"
1878
+ },
1879
+ children: name
1880
+ },
1881
+ name
1882
+ )) })
1883
+ ] }),
1884
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1885
+ /* @__PURE__ */ jsxs4("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
1886
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarHeading, children: [
1887
+ "Events (",
1888
+ events.length,
1889
+ ")"
1890
+ ] }),
1891
+ events.length > 0 && /* @__PURE__ */ jsx5(
1892
+ "button",
1893
+ {
1894
+ style: { background: "none", border: "none", color: "#a0aec0", fontSize: 11, cursor: "pointer" },
1895
+ onClick: () => setEvents([]),
1896
+ children: "Clear"
1897
+ }
1898
+ )
1899
+ ] }),
1900
+ events.length === 0 && /* @__PURE__ */ jsx5("div", { style: { color: "#a0aec0", fontSize: 12, fontStyle: "italic" }, children: "No events yet" }),
1901
+ events.slice(0, 50).map((e) => /* @__PURE__ */ jsxs4("div", { style: S.eventRow, children: [
1902
+ /* @__PURE__ */ jsx5("span", { style: S.eventTime, children: e.time }),
1903
+ /* @__PURE__ */ jsx5("span", { style: S.eventName, children: e.name }),
1904
+ e.payload !== void 0 && /* @__PURE__ */ jsx5("span", { style: { color: "#718096", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: JSON.stringify(e.payload) })
1905
+ ] }, e.id))
1906
+ ] }),
1907
+ /* @__PURE__ */ jsxs4("div", { style: S.sidebarSection, children: [
1908
+ /* @__PURE__ */ jsx5("div", { style: S.sidebarHeading, children: "Tree (JSON)" }),
1909
+ /* @__PURE__ */ jsx5("pre", { style: { ...S.pre, maxHeight: 400 }, children: JSON.stringify(tree, null, 2) })
1910
+ ] })
1911
+ ] })
1912
+ ] })
1913
+ ] });
1914
+ };
1915
+
1916
+ export {
1917
+ setQueryResolver,
1918
+ useQuery,
1919
+ setMutationResolver,
1920
+ useMutation,
1921
+ classifyBinding,
1922
+ resolveBinding,
1923
+ resolveAllBindings,
1924
+ buildEvalContext,
1925
+ buildActionScope,
1926
+ AtomRegistryImpl,
1927
+ createCoreAtomRegistry,
1928
+ mergeRegistries,
1929
+ DEFAULT_DESIGN_TOKENS,
1930
+ usePlayerContext,
1931
+ useTheme,
1932
+ PlayerProvider,
1933
+ ExperienceRenderer,
1934
+ createApiResolver,
1935
+ ComponentTreeRenderer,
1936
+ builtinAtoms,
1937
+ DevPlayer
1938
+ };