@mmapp/react 0.1.0-alpha.24 → 0.1.0-alpha.25

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