@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
@@ -5,6 +5,9 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
8
11
  var __export = (target, all) => {
9
12
  for (var name in all)
10
13
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,61 +30,3018 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
30
  ));
28
31
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
32
 
33
+ // src/player/expression-engine.ts
34
+ function setWasmModule(module2) {
35
+ _wasmModule = module2;
36
+ _wasmAvailable = module2 != null;
37
+ }
38
+ function classifyExpression(expr) {
39
+ const cached = classificationCache.get(expr);
40
+ if (cached) return cached;
41
+ const cls = classifyUncached(expr);
42
+ classificationCache.set(expr, cls);
43
+ return cls;
44
+ }
45
+ function classifyUncached(expr) {
46
+ const t = expr.trim();
47
+ if (t === "[Expression]" || t.includes("[Expression]")) return "literal";
48
+ if (t.startsWith("$expr(") && t.endsWith(")")) return "condition";
49
+ if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) return "literal";
50
+ if (/^-?\d+(\.\d+)?$/.test(t)) return "literal";
51
+ if (t === "true" || t === "false" || t === "null" || t === "undefined") return "literal";
52
+ if (t === "[]" || t === "{}") return "literal";
53
+ if (/^\$fn\.\w+\(/.test(t)) return "function";
54
+ if (/^\$action\.\w+\(/.test(t)) return "action";
55
+ if (t.startsWith("$action.") && !t.includes("(")) return "action";
56
+ if (t.startsWith("$") && !/[!=<>&|+\-*/%?:]/.test(t) && !t.includes("(")) return "path";
57
+ if (/^[a-zA-Z_]\w*(\.\w+)+$/.test(t) && !/[!=<>&|+\-*/%?:]/.test(t)) return "path";
58
+ if (/^[a-zA-Z_]\w*$/.test(t)) return "path";
59
+ return "condition";
60
+ }
61
+ function resolvePath(path, scope) {
62
+ const parts = path.split(".");
63
+ let current = scope;
64
+ for (const part of parts) {
65
+ if (current == null) return void 0;
66
+ if (typeof current !== "object") return void 0;
67
+ const asNum = Number(part);
68
+ if (Array.isArray(current) && !isNaN(asNum)) {
69
+ current = current[asNum];
70
+ } else {
71
+ current = current[part];
72
+ }
73
+ }
74
+ return current;
75
+ }
76
+ function validateExpression(expr) {
77
+ for (const pat of FORBIDDEN_PATTERNS) {
78
+ if (pat.test(expr)) {
79
+ return { valid: false, error: `Forbidden pattern: ${pat.source}` };
80
+ }
81
+ }
82
+ const depth = (expr.match(/\(/g) || []).length;
83
+ if (depth > 15) return { valid: false, error: "Expression too deeply nested" };
84
+ return { valid: true };
85
+ }
86
+ function compileToFunction(expr, paramNames) {
87
+ const cached = compiledCache.get(expr);
88
+ if (cached) return cached;
89
+ const validation = validateExpression(expr);
90
+ if (!validation.valid) {
91
+ console.warn(`[expression-engine] Unsafe expression blocked: ${validation.error} in "${expr}"`);
92
+ return null;
93
+ }
94
+ try {
95
+ const fn = new Function(...paramNames, `"use strict"; try { return (${expr}); } catch(e) { return undefined; }`);
96
+ compiledCache.set(expr, fn);
97
+ return fn;
98
+ } catch {
99
+ try {
100
+ const fn = new Function(...paramNames, `"use strict"; try { ${expr} } catch(e) { return undefined; }`);
101
+ compiledCache.set(expr, fn);
102
+ return fn;
103
+ } catch {
104
+ return null;
105
+ }
106
+ }
107
+ }
108
+ function evaluateExpression(expr, context) {
109
+ const trimmed = expr.trim();
110
+ if (!trimmed) return void 0;
111
+ const cls = classifyExpression(trimmed);
112
+ if (cls === "literal") return parseLiteral(trimmed);
113
+ if (cls === "path") return resolveScopePath(trimmed, context);
114
+ let evalExpr = trimmed;
115
+ if (evalExpr.startsWith("$expr(") && evalExpr.endsWith(")")) {
116
+ evalExpr = evalExpr.slice(6, -1);
117
+ }
118
+ if (_wasmAvailable && _wasmModule) {
119
+ try {
120
+ const translated = translateForWasm(evalExpr);
121
+ const contextJson = JSON.stringify(buildWasmContext(context));
122
+ const resultJson = _wasmModule.evaluateExpressionSync(translated, contextJson);
123
+ return JSON.parse(resultJson);
124
+ } catch {
125
+ }
126
+ }
127
+ return evaluateWithJS(evalExpr, context);
128
+ }
129
+ function parseLiteral(expr) {
130
+ if (expr.startsWith('"') && expr.endsWith('"') || expr.startsWith("'") && expr.endsWith("'")) {
131
+ return expr.slice(1, -1);
132
+ }
133
+ if (/^-?\d+(\.\d+)?$/.test(expr)) return Number(expr);
134
+ if (expr === "true") return true;
135
+ if (expr === "false") return false;
136
+ if (expr === "null") return null;
137
+ if (expr === "undefined") return void 0;
138
+ if (expr === "[]") return [];
139
+ if (expr === "{}") return {};
140
+ if (expr === "[Expression]") return void 0;
141
+ return void 0;
142
+ }
143
+ function resolveScopePath(expr, context) {
144
+ const trimmed = expr.trim();
145
+ if (trimmed.startsWith("$")) {
146
+ const dotIdx = trimmed.indexOf(".");
147
+ if (dotIdx === -1) {
148
+ return context[trimmed];
149
+ }
150
+ const root = trimmed.slice(0, dotIdx);
151
+ const rest = trimmed.slice(dotIdx + 1);
152
+ const rootVal = context[root];
153
+ if (rootVal == null) return void 0;
154
+ return resolvePath(rest, rootVal);
155
+ }
156
+ return resolvePath(trimmed, context);
157
+ }
158
+ function translateForWasm(expr) {
159
+ return expr.replace(/\$fn\./g, "").replace(/\$instance\./g, "state_data.").replace(/\$data\./g, "state_data.").replace(/\$row\./g, "state_data.");
160
+ }
161
+ function buildWasmContext(context) {
162
+ const wasmCtx = {};
163
+ if (context.$instance && typeof context.$instance === "object") {
164
+ const inst = context.$instance;
165
+ wasmCtx.state_data = inst.fields ?? inst;
166
+ }
167
+ if (context.$local) wasmCtx.$local = context.$local;
168
+ if (context.$user) wasmCtx.$user = context.$user;
169
+ if (context.$entity) wasmCtx.$entity = context.$entity;
170
+ if (context.state_data) wasmCtx.state_data = context.state_data;
171
+ if (context.memory) wasmCtx.memory = context.memory;
172
+ if (context.context) wasmCtx.context = context.context;
173
+ return wasmCtx;
174
+ }
175
+ function evaluateWithJS(expr, context) {
176
+ const paramNames = [];
177
+ const paramValues = [];
178
+ for (const [key, value] of Object.entries(context)) {
179
+ if (key.startsWith("$")) {
180
+ paramNames.push(key);
181
+ paramValues.push(value);
182
+ }
183
+ }
184
+ if (context.$fn && typeof context.$fn === "object") {
185
+ for (const [name, fn2] of Object.entries(context.$fn)) {
186
+ if (!paramNames.includes(name)) {
187
+ paramNames.push(name);
188
+ paramValues.push(fn2);
189
+ }
190
+ }
191
+ }
192
+ if ("item" in context) {
193
+ paramNames.push("item");
194
+ paramValues.push(context.item);
195
+ }
196
+ if ("index" in context) {
197
+ paramNames.push("index");
198
+ paramValues.push(context.index);
199
+ }
200
+ if (context.$instances) {
201
+ paramNames.push("items");
202
+ paramValues.push(context.$instances);
203
+ }
204
+ if (context.$instance) {
205
+ paramNames.push("instance");
206
+ paramValues.push(context.$instance);
207
+ }
208
+ if ("loading" in context) {
209
+ paramNames.push("loading");
210
+ paramValues.push(context.loading);
211
+ }
212
+ if (context.$local && typeof context.$local === "object") {
213
+ for (const [k, v] of Object.entries(context.$local)) {
214
+ if (!paramNames.includes(k)) {
215
+ paramNames.push(k);
216
+ paramValues.push(v);
217
+ }
218
+ }
219
+ }
220
+ const fn = compileToFunction(expr, paramNames);
221
+ if (!fn) return void 0;
222
+ try {
223
+ return fn(...paramValues);
224
+ } catch {
225
+ return void 0;
226
+ }
227
+ }
228
+ var _wasmModule, _wasmAvailable, LRUCache, classificationCache, builtinFunctions, compiledCache, FORBIDDEN_PATTERNS;
229
+ var init_expression_engine = __esm({
230
+ "src/player/expression-engine.ts"() {
231
+ "use strict";
232
+ _wasmModule = null;
233
+ _wasmAvailable = false;
234
+ LRUCache = class {
235
+ constructor(maxSize) {
236
+ this.maxSize = maxSize;
237
+ }
238
+ map = /* @__PURE__ */ new Map();
239
+ get(key) {
240
+ const val = this.map.get(key);
241
+ if (val !== void 0) {
242
+ this.map.delete(key);
243
+ this.map.set(key, val);
244
+ }
245
+ return val;
246
+ }
247
+ set(key, value) {
248
+ if (this.map.has(key)) this.map.delete(key);
249
+ this.map.set(key, value);
250
+ if (this.map.size > this.maxSize) {
251
+ const first = this.map.keys().next().value;
252
+ if (first !== void 0) this.map.delete(first);
253
+ }
254
+ }
255
+ has(key) {
256
+ return this.map.has(key);
257
+ }
258
+ };
259
+ classificationCache = new LRUCache(500);
260
+ builtinFunctions = {
261
+ // Array
262
+ filter: (arr, fn) => {
263
+ if (!Array.isArray(arr)) return [];
264
+ if (typeof fn === "function") return arr.filter(fn);
265
+ return arr;
266
+ },
267
+ map: (arr, fn) => {
268
+ if (!Array.isArray(arr)) return [];
269
+ if (typeof fn === "function") return arr.map(fn);
270
+ return arr;
271
+ },
272
+ reduce: (arr, fn, init) => {
273
+ if (!Array.isArray(arr)) return init;
274
+ if (typeof fn === "function") return arr.reduce(fn, init);
275
+ return init;
276
+ },
277
+ find: (arr, fn) => {
278
+ if (!Array.isArray(arr)) return void 0;
279
+ if (typeof fn === "function") return arr.find(fn);
280
+ return void 0;
281
+ },
282
+ includes: (arr, item) => {
283
+ if (Array.isArray(arr)) return arr.includes(item);
284
+ if (typeof arr === "string") return arr.includes(String(item));
285
+ return false;
286
+ },
287
+ indexOf: (arr, item) => {
288
+ if (Array.isArray(arr)) return arr.indexOf(item);
289
+ if (typeof arr === "string") return arr.indexOf(String(item));
290
+ return -1;
291
+ },
292
+ slice: (arr, start, end) => {
293
+ if (Array.isArray(arr) || typeof arr === "string") {
294
+ return arr.slice(Number(start) || 0, end != null ? Number(end) : void 0);
295
+ }
296
+ return arr;
297
+ },
298
+ sort: (arr, fn) => {
299
+ if (!Array.isArray(arr)) return [];
300
+ const copy = [...arr];
301
+ if (typeof fn === "function") return copy.sort(fn);
302
+ return copy.sort();
303
+ },
304
+ reverse: (arr) => {
305
+ if (!Array.isArray(arr)) return [];
306
+ return [...arr].reverse();
307
+ },
308
+ unique: (arr) => {
309
+ if (!Array.isArray(arr)) return [];
310
+ return [...new Set(arr)];
311
+ },
312
+ flat: (arr, depth) => {
313
+ if (!Array.isArray(arr)) return [];
314
+ return arr.flat(Number(depth) || 1);
315
+ },
316
+ concat: (a, b) => {
317
+ if (Array.isArray(a)) return a.concat(Array.isArray(b) ? b : [b]);
318
+ if (typeof a === "string") return a + String(b ?? "");
319
+ return [a, b];
320
+ },
321
+ any: (arr, fn) => {
322
+ if (!Array.isArray(arr)) return false;
323
+ if (typeof fn === "function") return arr.some(fn);
324
+ return arr.length > 0;
325
+ },
326
+ all: (arr, fn) => {
327
+ if (!Array.isArray(arr)) return false;
328
+ if (typeof fn === "function") return arr.every(fn);
329
+ return false;
330
+ },
331
+ group_by: (arr, key) => {
332
+ if (!Array.isArray(arr) || typeof key !== "string") return {};
333
+ const groups = {};
334
+ for (const item of arr) {
335
+ const k = String(item?.[key] ?? "undefined");
336
+ (groups[k] ??= []).push(item);
337
+ }
338
+ return groups;
339
+ },
340
+ count: (arr) => Array.isArray(arr) ? arr.length : 0,
341
+ sum: (arr, key) => {
342
+ if (!Array.isArray(arr)) return 0;
343
+ if (typeof key === "string") {
344
+ return arr.reduce((s, item) => s + (Number(item?.[key]) || 0), 0);
345
+ }
346
+ return arr.reduce((s, v) => s + (Number(v) || 0), 0);
347
+ },
348
+ avg: (arr, key) => {
349
+ if (!Array.isArray(arr) || arr.length === 0) return 0;
350
+ const s = builtinFunctions.sum(arr, key);
351
+ return s / arr.length;
352
+ },
353
+ min: (...args) => {
354
+ if (args.length === 1 && Array.isArray(args[0])) return Math.min(...args[0].map(Number));
355
+ return Math.min(...args.map(Number));
356
+ },
357
+ max: (...args) => {
358
+ if (args.length === 1 && Array.isArray(args[0])) return Math.max(...args[0].map(Number));
359
+ return Math.max(...args.map(Number));
360
+ },
361
+ // String
362
+ len: (v) => {
363
+ if (Array.isArray(v)) return v.length;
364
+ if (typeof v === "string") return v.length;
365
+ return 0;
366
+ },
367
+ upper: (v) => typeof v === "string" ? v.toUpperCase() : String(v ?? "").toUpperCase(),
368
+ lower: (v) => typeof v === "string" ? v.toLowerCase() : String(v ?? "").toLowerCase(),
369
+ trim: (v) => typeof v === "string" ? v.trim() : String(v ?? "").trim(),
370
+ contains: (haystack, needle) => {
371
+ if (typeof haystack === "string") return haystack.includes(String(needle));
372
+ if (Array.isArray(haystack)) return haystack.includes(needle);
373
+ return false;
374
+ },
375
+ starts_with: (v, prefix) => typeof v === "string" ? v.startsWith(String(prefix)) : false,
376
+ ends_with: (v, suffix) => typeof v === "string" ? v.endsWith(String(suffix)) : false,
377
+ replace: (v, search, rep) => typeof v === "string" ? v.replaceAll(String(search), String(rep)) : v,
378
+ split: (v, sep) => typeof v === "string" ? v.split(String(sep)) : [],
379
+ join: (arr, sep) => Array.isArray(arr) ? arr.join(String(sep ?? ",")) : String(arr),
380
+ substr: (v, start, len) => {
381
+ if (typeof v !== "string") return "";
382
+ return v.substring(Number(start) || 0, len != null ? (Number(start) || 0) + Number(len) : void 0);
383
+ },
384
+ format: (template, ...args) => {
385
+ if (typeof template !== "string") return String(template);
386
+ return template.replace(/\{(\d+)\}/g, (_, i) => String(args[Number(i)] ?? ""));
387
+ },
388
+ // Math
389
+ abs: (v) => Math.abs(Number(v) || 0),
390
+ ceil: (v) => Math.ceil(Number(v) || 0),
391
+ floor: (v) => Math.floor(Number(v) || 0),
392
+ round: (v, decimals) => {
393
+ const n = Number(v) || 0;
394
+ const d = Number(decimals) || 0;
395
+ const f = Math.pow(10, d);
396
+ return Math.round(n * f) / f;
397
+ },
398
+ pow: (base, exp) => Math.pow(Number(base) || 0, Number(exp) || 0),
399
+ sqrt: (v) => Math.sqrt(Number(v) || 0),
400
+ random: () => Math.random(),
401
+ clamp: (v, lo, hi) => Math.min(Math.max(Number(v), Number(lo)), Number(hi)),
402
+ // Date
403
+ now: () => (/* @__PURE__ */ new Date()).toISOString(),
404
+ formatDate: (v, fmt) => {
405
+ try {
406
+ const d = new Date(v);
407
+ if (isNaN(d.getTime())) return String(v);
408
+ if (fmt === "relative") {
409
+ const diff = Date.now() - d.getTime();
410
+ if (diff < 6e4) return "just now";
411
+ if (diff < 36e5) return `${Math.floor(diff / 6e4)}m ago`;
412
+ if (diff < 864e5) return `${Math.floor(diff / 36e5)}h ago`;
413
+ return `${Math.floor(diff / 864e5)}d ago`;
414
+ }
415
+ return d.toLocaleDateString();
416
+ } catch {
417
+ return String(v);
418
+ }
419
+ },
420
+ // Utility
421
+ coalesce: (...args) => args.find((a) => a != null),
422
+ default: (v, fallback) => v ?? fallback,
423
+ json: (v) => JSON.stringify(v),
424
+ keys: (v) => v && typeof v === "object" && !Array.isArray(v) ? Object.keys(v) : [],
425
+ values: (v) => v && typeof v === "object" && !Array.isArray(v) ? Object.values(v) : [],
426
+ entries: (v) => v && typeof v === "object" && !Array.isArray(v) ? Object.entries(v) : [],
427
+ merge: (...args) => Object.assign({}, ...args.filter((a) => a && typeof a === "object")),
428
+ debug: (v, label) => {
429
+ console.log(label ? `[debug:${label}]` : "[debug]", v);
430
+ return v;
431
+ },
432
+ Boolean: (v) => Boolean(v),
433
+ Number: (v) => Number(v),
434
+ String: (v) => String(v ?? "")
435
+ };
436
+ compiledCache = new LRUCache(2e3);
437
+ FORBIDDEN_PATTERNS = [
438
+ /\beval\b/,
439
+ /\bFunction\b/,
440
+ /\bfetch\b/,
441
+ /\bdocument\b/,
442
+ /\bwindow\b/,
443
+ /\bprocess\b/,
444
+ /\bglobalThis\b/,
445
+ /\bimport\b/,
446
+ /\brequire\b/,
447
+ /\b__proto__\b/,
448
+ /\bconstructor\b/
449
+ ];
450
+ }
451
+ });
452
+
453
+ // src/player/scope-builder.ts
454
+ function useScope() {
455
+ return (0, import_react.useContext)(ScopeContext);
456
+ }
457
+ function buildScope(opts) {
458
+ const {
459
+ dataSources = {},
460
+ localState = {},
461
+ auth,
462
+ entity,
463
+ parentScope,
464
+ actionScope,
465
+ functions = {}
466
+ } = opts;
467
+ const scope = {
468
+ ...parentScope ?? emptyScopeData,
469
+ $local: { ...parentScope?.$local ?? {}, ...localState },
470
+ $fn: { ...builtinFunctions, ...parentScope?.$fn ?? {}, ...functions }
471
+ };
472
+ if (auth) {
473
+ scope.$user = { id: auth.userId, roles: auth.roles ?? [] };
474
+ }
475
+ if (entity) {
476
+ scope.$entity = entity;
477
+ }
478
+ if (actionScope) {
479
+ scope.$action = actionScope;
480
+ }
481
+ if (Object.keys(dataSources).length > 0) {
482
+ const allInstances = [];
483
+ let primaryInstance;
484
+ let primaryDefinition;
485
+ let primaryPagination;
486
+ for (const [name, result] of Object.entries(dataSources)) {
487
+ if (result.instance) {
488
+ primaryInstance = result.instance;
489
+ scope[name] = result.instance;
490
+ }
491
+ if (result.instances) {
492
+ allInstances.push(...result.instances);
493
+ scope[name] = result.instances;
494
+ }
495
+ if (result.definition) {
496
+ primaryDefinition = result.definition;
497
+ }
498
+ if (result.pagination) {
499
+ primaryPagination = result.pagination;
500
+ }
501
+ }
502
+ if (primaryInstance) scope.$instance = primaryInstance;
503
+ if (allInstances.length > 0) scope.$instances = allInstances;
504
+ if (primaryDefinition) scope.$definition = primaryDefinition;
505
+ if (primaryPagination) scope.$pagination = primaryPagination;
506
+ const anyLoading = Object.values(dataSources).some((r) => r.loading);
507
+ scope.loading = anyLoading;
508
+ }
509
+ return scope;
510
+ }
511
+ function mergeScope(parent, child) {
512
+ return {
513
+ ...parent,
514
+ ...child,
515
+ $local: { ...parent.$local, ...child.$local ?? {} },
516
+ $fn: { ...parent.$fn, ...child.$fn ?? {} },
517
+ $action: child.$action ?? parent.$action
518
+ };
519
+ }
520
+ function buildLoopScope(parent, item, index, as) {
521
+ return {
522
+ ...parent,
523
+ $item: item,
524
+ $index: index,
525
+ [as]: item,
526
+ // Convenience: flatten item fields for direct access
527
+ item,
528
+ index
529
+ };
530
+ }
531
+ var import_react, emptyScopeData, ScopeContext;
532
+ var init_scope_builder = __esm({
533
+ "src/player/scope-builder.ts"() {
534
+ "use strict";
535
+ import_react = require("react");
536
+ init_expression_engine();
537
+ emptyScopeData = {
538
+ $local: {},
539
+ $user: { roles: [] },
540
+ $fn: builtinFunctions,
541
+ $action: {}
542
+ };
543
+ ScopeContext = (0, import_react.createContext)(emptyScopeData);
544
+ }
545
+ });
546
+
547
+ // src/player/atoms/layout.tsx
548
+ var layout_exports = {};
549
+ __export(layout_exports, {
550
+ Column: () => Column,
551
+ Divider: () => Divider,
552
+ Grid: () => Grid,
553
+ Row: () => Row,
554
+ Spacer: () => Spacer,
555
+ Stack: () => Stack
556
+ });
557
+ var import_jsx_runtime, filterHtmlProps, Stack, Row, Grid, Column, Divider, Spacer;
558
+ var init_layout = __esm({
559
+ "src/player/atoms/layout.tsx"() {
560
+ "use strict";
561
+ import_jsx_runtime = require("react/jsx-runtime");
562
+ filterHtmlProps = (props) => {
563
+ const html = {};
564
+ for (const [k, v] of Object.entries(props)) {
565
+ if (["className", "style", "id", "role", "tabIndex", "title", "onClick", "data-node-id"].includes(k)) {
566
+ html[k] = v;
567
+ }
568
+ if (k.startsWith("data-") || k.startsWith("aria-")) html[k] = v;
569
+ }
570
+ return html;
571
+ };
572
+ Stack = ({ children, gap, padding, align, justify, className, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
573
+ "div",
574
+ {
575
+ ...filterHtmlProps(rest),
576
+ className,
577
+ style: {
578
+ display: "flex",
579
+ flexDirection: "column",
580
+ gap: gap != null ? Number(gap) * 4 : void 0,
581
+ padding: padding != null ? Number(padding) * 4 : void 0,
582
+ alignItems: align,
583
+ justifyContent: justify,
584
+ ...style
585
+ },
586
+ children
587
+ }
588
+ );
589
+ Row = ({ children, gap, padding, align, justify, wrap, className, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
590
+ "div",
591
+ {
592
+ ...filterHtmlProps(rest),
593
+ className,
594
+ style: {
595
+ display: "flex",
596
+ flexDirection: "row",
597
+ gap: gap != null ? Number(gap) * 4 : void 0,
598
+ padding: padding != null ? Number(padding) * 4 : void 0,
599
+ alignItems: align ?? "center",
600
+ justifyContent: justify,
601
+ flexWrap: wrap ? "wrap" : void 0,
602
+ ...style
603
+ },
604
+ children
605
+ }
606
+ );
607
+ Grid = ({ children, columns, gap, padding, minChildWidth, className, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
608
+ "div",
609
+ {
610
+ ...filterHtmlProps(rest),
611
+ className,
612
+ style: {
613
+ display: "grid",
614
+ gridTemplateColumns: minChildWidth ? `repeat(auto-fill, minmax(${Number(minChildWidth)}px, 1fr))` : columns ? `repeat(${Number(columns)}, 1fr)` : "repeat(auto-fill, minmax(200px, 1fr))",
615
+ gap: gap != null ? Number(gap) * 4 : 16,
616
+ padding: padding != null ? Number(padding) * 4 : void 0,
617
+ ...style
618
+ },
619
+ children
620
+ }
621
+ );
622
+ Column = ({ children, span, className, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
623
+ "div",
624
+ {
625
+ ...filterHtmlProps(rest),
626
+ className,
627
+ style: {
628
+ gridColumn: span ? `span ${Number(span)}` : void 0,
629
+ ...style
630
+ },
631
+ children
632
+ }
633
+ );
634
+ Divider = ({ orientation, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
635
+ "hr",
636
+ {
637
+ className,
638
+ style: {
639
+ border: "none",
640
+ borderTop: orientation === "vertical" ? "none" : "1px solid #e2e8f0",
641
+ borderLeft: orientation === "vertical" ? "1px solid #e2e8f0" : "none",
642
+ margin: orientation === "vertical" ? "0 8px" : "8px 0",
643
+ alignSelf: orientation === "vertical" ? "stretch" : void 0,
644
+ ...style
645
+ }
646
+ }
647
+ );
648
+ Spacer = ({ size, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
649
+ "div",
650
+ {
651
+ className,
652
+ style: {
653
+ flex: size ? `0 0 ${Number(size) * 4}px` : "1",
654
+ ...style
655
+ }
656
+ }
657
+ );
658
+ }
659
+ });
660
+
661
+ // src/player/atoms/content.tsx
662
+ var content_exports = {};
663
+ __export(content_exports, {
664
+ Alert: () => Alert,
665
+ Badge: () => Badge,
666
+ EmptyState: () => EmptyState,
667
+ Field: () => Field,
668
+ Heading: () => Heading,
669
+ Icon: () => Icon,
670
+ Image: () => Image,
671
+ Markdown: () => Markdown,
672
+ Progress: () => Progress,
673
+ Separator: () => Separator,
674
+ Text: () => Text
675
+ });
676
+ var import_jsx_runtime2, Text, Heading, Field, Image, Badge, ICON_MAP, Icon, Alert, EmptyState, Markdown, Progress, Separator;
677
+ var init_content = __esm({
678
+ "src/player/atoms/content.tsx"() {
679
+ "use strict";
680
+ import_jsx_runtime2 = require("react/jsx-runtime");
681
+ Text = ({ value, children, variant, size, weight, color, align, className, style }) => {
682
+ const text = value ?? children;
683
+ const sizeMap = { xs: 11, sm: 13, md: 14, lg: 16, xl: 20, "2xl": 24 };
684
+ const weightMap = { light: 300, normal: 400, medium: 500, semibold: 600, bold: 700 };
685
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
686
+ "span",
687
+ {
688
+ className,
689
+ style: {
690
+ fontSize: size ? sizeMap[size] ?? Number(size) : void 0,
691
+ fontWeight: weight ? weightMap[weight] ?? weight : void 0,
692
+ color: variant === "muted" ? "#718096" : variant === "error" ? "#e53e3e" : variant === "success" ? "#38a169" : color,
693
+ textAlign: align,
694
+ ...style
695
+ },
696
+ children: text == null ? "" : String(text)
697
+ }
698
+ );
699
+ };
700
+ Heading = ({ value, children, level, className, style }) => {
701
+ const text = value ?? children;
702
+ const sizes = { 1: 32, 2: 24, 3: 20, 4: 16, 5: 14, 6: 12 };
703
+ const lvl = Number(level) || 2;
704
+ const Tag = `h${Math.min(Math.max(lvl, 1), 6)}`;
705
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
706
+ Tag,
707
+ {
708
+ className,
709
+ style: {
710
+ fontSize: sizes[lvl] ?? 20,
711
+ fontWeight: 600,
712
+ margin: "0 0 8px 0",
713
+ lineHeight: 1.3,
714
+ ...style
715
+ },
716
+ children: text == null ? "" : String(text)
717
+ }
718
+ );
719
+ };
720
+ Field = ({ label, value, type: _type, children, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: { marginBottom: 8, ...style }, children: [
721
+ label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { display: "block", fontSize: 12, fontWeight: 500, color: "#718096", marginBottom: 2 }, children: String(label) }) : null,
722
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 14 }, children: children ?? (value != null ? String(value) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#a0aec0" }, children: "\u2014" })) })
723
+ ] });
724
+ Image = ({ src, alt, width, height, fit, radius, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
725
+ "img",
726
+ {
727
+ src,
728
+ alt: alt ?? "",
729
+ className,
730
+ style: {
731
+ width: width ? Number(width) : void 0,
732
+ height: height ? Number(height) : void 0,
733
+ objectFit: fit ?? "cover",
734
+ borderRadius: radius ? Number(radius) : void 0,
735
+ maxWidth: "100%",
736
+ ...style
737
+ }
738
+ }
739
+ );
740
+ Badge = ({ value, children, variant, color, className, style }) => {
741
+ const text = value ?? children;
742
+ const colorMap = {
743
+ default: { bg: "#edf2f7", fg: "#4a5568" },
744
+ primary: { bg: "#ebf8ff", fg: "#2b6cb0" },
745
+ success: { bg: "#f0fff4", fg: "#276749" },
746
+ warning: { bg: "#fffaf0", fg: "#c05621" },
747
+ error: { bg: "#fff5f5", fg: "#c53030" },
748
+ info: { bg: "#ebf8ff", fg: "#2b6cb0" }
749
+ };
750
+ const c = colorMap[variant ?? "default"] ?? colorMap.default;
751
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
752
+ "span",
753
+ {
754
+ className,
755
+ style: {
756
+ display: "inline-block",
757
+ padding: "1px 8px",
758
+ borderRadius: 9999,
759
+ fontSize: 12,
760
+ fontWeight: 500,
761
+ background: color ? void 0 : c.bg,
762
+ color: color ?? c.fg,
763
+ ...style
764
+ },
765
+ children: text == null ? "" : String(text)
766
+ }
767
+ );
768
+ };
769
+ ICON_MAP = {
770
+ "check": "\u2713",
771
+ "x": "\u2715",
772
+ "plus": "+",
773
+ "minus": "\u2212",
774
+ "arrow-right": "\u2192",
775
+ "arrow-left": "\u2190",
776
+ "arrow-up": "\u2191",
777
+ "arrow-down": "\u2193",
778
+ "search": "\u{1F50D}",
779
+ "home": "\u{1F3E0}",
780
+ "user": "\u{1F464}",
781
+ "settings": "\u2699",
782
+ "star": "\u2B50",
783
+ "heart": "\u2764",
784
+ "mail": "\u2709",
785
+ "phone": "\u{1F4DE}",
786
+ "calendar": "\u{1F4C5}",
787
+ "clock": "\u{1F550}",
788
+ "edit": "\u270E",
789
+ "trash": "\u{1F5D1}",
790
+ "download": "\u2B07",
791
+ "upload": "\u2B06",
792
+ "share": "\u2197",
793
+ "lock": "\u{1F512}",
794
+ "unlock": "\u{1F513}",
795
+ "eye": "\u{1F441}",
796
+ "eye-off": "\u{1F648}",
797
+ "bell": "\u{1F514}",
798
+ "info": "\u2139",
799
+ "warning": "\u26A0",
800
+ "error": "\u274C",
801
+ "loading": "\u23F3",
802
+ "menu": "\u2630",
803
+ "close": "\u2715",
804
+ "chevron-right": "\u203A",
805
+ "chevron-left": "\u2039",
806
+ "chevron-up": "\u2038",
807
+ "chevron-down": "\u02EC",
808
+ "copy": "\u{1F4CB}",
809
+ "save": "\u{1F4BE}",
810
+ "refresh": "\u21BB",
811
+ "filter": "\u23CF",
812
+ "sort": "\u21C5"
813
+ };
814
+ Icon = ({ name, size, color, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
815
+ "span",
816
+ {
817
+ className,
818
+ role: "img",
819
+ "aria-label": name,
820
+ style: {
821
+ fontSize: size ? Number(size) : 16,
822
+ color,
823
+ display: "inline-flex",
824
+ alignItems: "center",
825
+ justifyContent: "center",
826
+ ...style
827
+ },
828
+ children: ICON_MAP[name?.toLowerCase()] ?? name ?? "?"
829
+ }
830
+ );
831
+ Alert = ({ children, variant, title, message, className, style }) => {
832
+ const colorMap = {
833
+ info: { bg: "#ebf8ff", border: "#90cdf4", fg: "#2b6cb0" },
834
+ success: { bg: "#f0fff4", border: "#9ae6b4", fg: "#276749" },
835
+ warning: { bg: "#fffaf0", border: "#fbd38d", fg: "#c05621" },
836
+ error: { bg: "#fff5f5", border: "#feb2b2", fg: "#c53030" }
837
+ };
838
+ const c = colorMap[variant ?? "info"] ?? colorMap.info;
839
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
840
+ "div",
841
+ {
842
+ className,
843
+ role: "alert",
844
+ style: {
845
+ padding: "12px 16px",
846
+ borderRadius: 6,
847
+ border: `1px solid ${c.border}`,
848
+ background: c.bg,
849
+ color: c.fg,
850
+ fontSize: 14,
851
+ ...style
852
+ },
853
+ children: [
854
+ title ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, marginBottom: 4 }, children: String(title) }) : null,
855
+ message ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { children: String(message) }) : null,
856
+ children
857
+ ]
858
+ }
859
+ );
860
+ };
861
+ EmptyState = ({ children, title, description, icon, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
862
+ "div",
863
+ {
864
+ className,
865
+ style: {
866
+ textAlign: "center",
867
+ padding: "32px 16px",
868
+ color: "#a0aec0",
869
+ ...style
870
+ },
871
+ children: [
872
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 40, marginBottom: 12 }, children: ICON_MAP[icon] ?? icon }) : null,
873
+ title ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 16, fontWeight: 600, color: "#4a5568", marginBottom: 4 }, children: String(title) }) : null,
874
+ description ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 14, marginBottom: 8 }, children: String(description) }) : null,
875
+ children
876
+ ]
877
+ }
878
+ );
879
+ Markdown = ({ value, children, className, style }) => {
880
+ const text = String(value ?? children ?? "");
881
+ const html = text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>").replace(/\*(.+?)\*/g, "<em>$1</em>").replace(/`(.+?)`/g, '<code style="background:#edf2f7;padding:1px 4px;border-radius:3px;font-size:13px">$1</code>').replace(/\n/g, "<br/>");
882
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
883
+ "div",
884
+ {
885
+ className,
886
+ style: { fontSize: 14, lineHeight: 1.6, ...style },
887
+ dangerouslySetInnerHTML: { __html: html }
888
+ }
889
+ );
890
+ };
891
+ Progress = ({ value, max, label, variant, className, style }) => {
892
+ const pct = Math.min(100, Math.max(0, Number(value) / (Number(max) || 100) * 100));
893
+ const colorMap = {
894
+ default: "#3182ce",
895
+ success: "#38a169",
896
+ warning: "#dd6b20",
897
+ error: "#e53e3e"
898
+ };
899
+ const color = colorMap[variant ?? "default"] ?? colorMap.default;
900
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className, style: { ...style }, children: [
901
+ label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 12, marginBottom: 4, color: "#718096" }, children: String(label) }) : null,
902
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: 8, background: "#edf2f7", borderRadius: 4, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: "100%", width: `${pct}%`, background: color, borderRadius: 4, transition: "width 0.3s" } }) })
903
+ ] });
904
+ };
905
+ Separator = ({ className, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
906
+ "hr",
907
+ {
908
+ className,
909
+ style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "16px 0", ...style }
910
+ }
911
+ );
912
+ }
913
+ });
914
+
915
+ // src/player/atoms/actions.tsx
916
+ var actions_exports = {};
917
+ __export(actions_exports, {
918
+ Button: () => Button,
919
+ Link: () => Link
920
+ });
921
+ var import_react4, import_jsx_runtime3, VARIANT_STYLES, SIZE_STYLES, Button, Link;
922
+ var init_actions = __esm({
923
+ "src/player/atoms/actions.tsx"() {
924
+ "use strict";
925
+ import_react4 = require("react");
926
+ import_jsx_runtime3 = require("react/jsx-runtime");
927
+ VARIANT_STYLES = {
928
+ primary: { background: "#3182ce", color: "#fff", border: "1px solid #3182ce" },
929
+ secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
930
+ outline: { background: "transparent", color: "#3182ce", border: "1px solid #3182ce" },
931
+ ghost: { background: "transparent", color: "#4a5568", border: "1px solid transparent" },
932
+ danger: { background: "#e53e3e", color: "#fff", border: "1px solid #e53e3e" },
933
+ destructive: { background: "#e53e3e", color: "#fff", border: "1px solid #e53e3e" },
934
+ success: { background: "#38a169", color: "#fff", border: "1px solid #38a169" },
935
+ link: { background: "transparent", color: "#3182ce", border: "none", textDecoration: "underline" },
936
+ default: { background: "#fff", color: "#1a202c", border: "1px solid #e2e8f0" }
937
+ };
938
+ SIZE_STYLES = {
939
+ xs: { padding: "2px 8px", fontSize: 11 },
940
+ sm: { padding: "4px 12px", fontSize: 13 },
941
+ md: { padding: "6px 16px", fontSize: 14 },
942
+ lg: { padding: "8px 24px", fontSize: 16 },
943
+ xl: { padding: "12px 32px", fontSize: 18 }
944
+ };
945
+ Button = ({
946
+ children,
947
+ label,
948
+ value,
949
+ onClick,
950
+ variant,
951
+ size,
952
+ disabled,
953
+ loading: loadingProp,
954
+ icon,
955
+ iconRight,
956
+ fullWidth,
957
+ className,
958
+ style
959
+ }) => {
960
+ const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
961
+ const text = children ?? label ?? value;
962
+ const isDisabled = Boolean(disabled) || isLoading || Boolean(loadingProp);
963
+ const vs = VARIANT_STYLES[variant ?? "default"] ?? VARIANT_STYLES.default;
964
+ const ss = SIZE_STYLES[size ?? "md"] ?? SIZE_STYLES.md;
965
+ const handleClick = (0, import_react4.useCallback)(async (e) => {
966
+ if (isDisabled) return;
967
+ if (typeof onClick === "function") {
968
+ const result = onClick(e);
969
+ if (result && typeof result === "object" && typeof result.then === "function") {
970
+ setIsLoading(true);
971
+ try {
972
+ await result;
973
+ } finally {
974
+ setIsLoading(false);
975
+ }
976
+ }
977
+ }
978
+ }, [onClick, isDisabled]);
979
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
980
+ "button",
981
+ {
982
+ className,
983
+ disabled: isDisabled,
984
+ onClick: handleClick,
985
+ style: {
986
+ ...vs,
987
+ ...ss,
988
+ borderRadius: 6,
989
+ cursor: isDisabled ? "not-allowed" : "pointer",
990
+ opacity: isDisabled ? 0.6 : 1,
991
+ fontWeight: 500,
992
+ display: "inline-flex",
993
+ alignItems: "center",
994
+ justifyContent: "center",
995
+ gap: 6,
996
+ width: fullWidth ? "100%" : void 0,
997
+ transition: "opacity 0.15s, background 0.15s",
998
+ ...style
999
+ },
1000
+ children: [
1001
+ isLoading || loadingProp ? "\u23F3" : icon ? String(icon) : null,
1002
+ text != null ? String(text) : null,
1003
+ iconRight ? String(iconRight) : null
1004
+ ]
1005
+ }
1006
+ );
1007
+ };
1008
+ Link = ({ children, href, to, label, onClick, external, className, style }) => {
1009
+ const text = children ?? label;
1010
+ const target = href ?? to;
1011
+ const handleClick = (0, import_react4.useCallback)((e) => {
1012
+ if (typeof onClick === "function") {
1013
+ e.preventDefault();
1014
+ onClick(e);
1015
+ }
1016
+ }, [onClick]);
1017
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
1018
+ "a",
1019
+ {
1020
+ href: target ?? "#",
1021
+ className,
1022
+ onClick: handleClick,
1023
+ target: external ? "_blank" : void 0,
1024
+ rel: external ? "noopener noreferrer" : void 0,
1025
+ style: {
1026
+ color: "#3182ce",
1027
+ textDecoration: "none",
1028
+ cursor: "pointer",
1029
+ fontSize: 14,
1030
+ ...style
1031
+ },
1032
+ children: text != null ? String(text) : target ?? "Link"
1033
+ }
1034
+ );
1035
+ };
1036
+ }
1037
+ });
1038
+
1039
+ // src/player/atoms/control-flow.tsx
1040
+ var control_flow_exports = {};
1041
+ __export(control_flow_exports, {
1042
+ Each: () => Each,
1043
+ Show: () => Show
1044
+ });
1045
+ var import_jsx_runtime4, Show, Each;
1046
+ var init_control_flow = __esm({
1047
+ "src/player/atoms/control-flow.tsx"() {
1048
+ "use strict";
1049
+ init_scope_builder();
1050
+ import_jsx_runtime4 = require("react/jsx-runtime");
1051
+ Show = ({ when, fallback, children }) => {
1052
+ if (when) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children });
1053
+ if (fallback) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: fallback });
1054
+ return null;
1055
+ };
1056
+ Each = ({ items, as: asName, keyField, children, renderItem, emptyState, className, style }) => {
1057
+ const parentScope = useScope();
1058
+ const itemArray = Array.isArray(items) ? items : [];
1059
+ const varName = asName ?? "item";
1060
+ const keyProp = keyField ?? "id";
1061
+ if (itemArray.length === 0) {
1062
+ if (emptyState) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: emptyState });
1063
+ return null;
1064
+ }
1065
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style, children: itemArray.map((item, index) => {
1066
+ const loopScope = buildLoopScope(parentScope, item, index, varName);
1067
+ const key = item && typeof item === "object" && keyProp in item ? String(item[keyProp]) : String(index);
1068
+ if (typeof renderItem === "function") {
1069
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ScopeContext.Provider, { value: loopScope, children: renderItem(item, index) }, key);
1070
+ }
1071
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(ScopeContext.Provider, { value: loopScope, children }, key);
1072
+ }) });
1073
+ };
1074
+ }
1075
+ });
1076
+
1077
+ // src/player/atoms/input.tsx
1078
+ var input_exports = {};
1079
+ __export(input_exports, {
1080
+ Select: () => Select,
1081
+ Slider: () => Slider,
1082
+ TextInput: () => TextInput,
1083
+ Toggle: () => Toggle
1084
+ });
1085
+ var import_react5, import_jsx_runtime5, inputBase, TextInput, Select, Toggle, Slider;
1086
+ var init_input = __esm({
1087
+ "src/player/atoms/input.tsx"() {
1088
+ "use strict";
1089
+ import_react5 = require("react");
1090
+ import_jsx_runtime5 = require("react/jsx-runtime");
1091
+ inputBase = {
1092
+ padding: "6px 12px",
1093
+ border: "1px solid #e2e8f0",
1094
+ borderRadius: 6,
1095
+ fontSize: 14,
1096
+ outline: "none",
1097
+ width: "100%",
1098
+ boxSizing: "border-box",
1099
+ background: "#fff",
1100
+ color: "#1a202c",
1101
+ transition: "border-color 0.15s"
1102
+ };
1103
+ TextInput = ({
1104
+ value,
1105
+ onChange,
1106
+ onBlur,
1107
+ placeholder,
1108
+ label,
1109
+ type,
1110
+ name,
1111
+ disabled,
1112
+ required,
1113
+ error,
1114
+ helperText,
1115
+ multiline,
1116
+ rows,
1117
+ maxLength,
1118
+ className,
1119
+ style,
1120
+ bind: _bind
1121
+ }) => {
1122
+ const isControlled = typeof onChange === "function";
1123
+ const [localValue, setLocalValue] = (0, import_react5.useState)(value ?? "");
1124
+ (0, import_react5.useEffect)(() => {
1125
+ if (value != null && String(value) !== localValue) {
1126
+ setLocalValue(String(value));
1127
+ }
1128
+ }, [value]);
1129
+ const handleChange = (0, import_react5.useCallback)((e) => {
1130
+ setLocalValue(e.target.value);
1131
+ if (typeof onChange === "function") {
1132
+ onChange(e);
1133
+ }
1134
+ }, [onChange]);
1135
+ const displayValue = isControlled ? value ?? "" : localValue;
1136
+ const hasError = Boolean(error);
1137
+ const inputStyle = {
1138
+ ...inputBase,
1139
+ borderColor: hasError ? "#e53e3e" : "#e2e8f0",
1140
+ ...style
1141
+ };
1142
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, style: { width: "100%" }, children: [
1143
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "block", fontSize: 13, fontWeight: 500, marginBottom: 4, color: "#4a5568" }, children: [
1144
+ String(label),
1145
+ required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: "#e53e3e" }, children: " *" }) : null
1146
+ ] }) : null,
1147
+ multiline ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1148
+ "textarea",
1149
+ {
1150
+ value: displayValue,
1151
+ onChange: handleChange,
1152
+ onBlur,
1153
+ placeholder,
1154
+ name,
1155
+ disabled: Boolean(disabled),
1156
+ required: Boolean(required),
1157
+ rows: Number(rows) || 3,
1158
+ maxLength: maxLength ? Number(maxLength) : void 0,
1159
+ style: inputStyle
1160
+ }
1161
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1162
+ "input",
1163
+ {
1164
+ type: type ?? "text",
1165
+ value: displayValue,
1166
+ onChange: handleChange,
1167
+ onBlur,
1168
+ placeholder,
1169
+ name,
1170
+ disabled: Boolean(disabled),
1171
+ required: Boolean(required),
1172
+ maxLength: maxLength ? Number(maxLength) : void 0,
1173
+ style: inputStyle
1174
+ }
1175
+ ),
1176
+ error || helperText ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { fontSize: 12, marginTop: 2, color: hasError ? "#e53e3e" : "#a0aec0" }, children: String(error || helperText) }) : null
1177
+ ] });
1178
+ };
1179
+ Select = ({
1180
+ value,
1181
+ onChange,
1182
+ options,
1183
+ placeholder,
1184
+ label,
1185
+ disabled,
1186
+ required,
1187
+ error,
1188
+ name,
1189
+ className,
1190
+ style
1191
+ }) => {
1192
+ const [localValue, setLocalValue] = (0, import_react5.useState)(value ?? "");
1193
+ const isControlled = typeof onChange === "function";
1194
+ (0, import_react5.useEffect)(() => {
1195
+ if (value != null && String(value) !== localValue) setLocalValue(String(value));
1196
+ }, [value]);
1197
+ const handleChange = (0, import_react5.useCallback)((e) => {
1198
+ setLocalValue(e.target.value);
1199
+ if (typeof onChange === "function") onChange(e);
1200
+ }, [onChange]);
1201
+ const displayValue = isControlled ? value ?? "" : localValue;
1202
+ const opts = Array.isArray(options) ? options : [];
1203
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, children: [
1204
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("label", { style: { display: "block", fontSize: 13, fontWeight: 500, marginBottom: 4, color: "#4a5568" }, children: [
1205
+ String(label),
1206
+ required ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: "#e53e3e" }, children: " *" }) : null
1207
+ ] }) : null,
1208
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1209
+ "select",
1210
+ {
1211
+ value: displayValue,
1212
+ onChange: handleChange,
1213
+ disabled: Boolean(disabled),
1214
+ name,
1215
+ style: {
1216
+ ...inputBase,
1217
+ borderColor: error ? "#e53e3e" : "#e2e8f0",
1218
+ ...style
1219
+ },
1220
+ children: [
1221
+ placeholder ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: "", children: String(placeholder) }) : null,
1222
+ opts.map((opt, i) => {
1223
+ const val = typeof opt === "object" ? opt.value : opt;
1224
+ const lbl = typeof opt === "object" ? opt.label ?? val : opt;
1225
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("option", { value: String(val), children: String(lbl) }, String(val) ?? i);
1226
+ })
1227
+ ]
1228
+ }
1229
+ )
1230
+ ] });
1231
+ };
1232
+ Toggle = ({ value, checked, onChange, label, disabled, className, style }) => {
1233
+ const isOn = Boolean(value ?? checked);
1234
+ const handleClick = (0, import_react5.useCallback)(() => {
1235
+ if (disabled) return;
1236
+ if (typeof onChange === "function") onChange(!isOn);
1237
+ }, [onChange, isOn, disabled]);
1238
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
1239
+ "div",
1240
+ {
1241
+ className,
1242
+ style: { display: "flex", alignItems: "center", gap: 8, ...style },
1243
+ children: [
1244
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1245
+ "button",
1246
+ {
1247
+ role: "switch",
1248
+ "aria-checked": isOn,
1249
+ disabled: Boolean(disabled),
1250
+ onClick: handleClick,
1251
+ style: {
1252
+ width: 40,
1253
+ height: 22,
1254
+ borderRadius: 11,
1255
+ border: "none",
1256
+ cursor: disabled ? "not-allowed" : "pointer",
1257
+ background: isOn ? "#3182ce" : "#cbd5e0",
1258
+ padding: 2,
1259
+ transition: "background 0.2s",
1260
+ display: "flex",
1261
+ alignItems: "center"
1262
+ },
1263
+ children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: {
1264
+ width: 18,
1265
+ height: 18,
1266
+ borderRadius: "50%",
1267
+ background: "#fff",
1268
+ transform: isOn ? "translateX(18px)" : "translateX(0)",
1269
+ transition: "transform 0.2s",
1270
+ boxShadow: "0 1px 3px rgba(0,0,0,0.2)"
1271
+ } })
1272
+ }
1273
+ ),
1274
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { fontSize: 14 }, children: String(label) }) : null
1275
+ ]
1276
+ }
1277
+ );
1278
+ };
1279
+ Slider = ({ value, onChange, min, max, step, label, disabled, className, style }) => {
1280
+ const numVal = Number(value) || Number(min) || 0;
1281
+ const handleChange = (0, import_react5.useCallback)((e) => {
1282
+ if (typeof onChange === "function") onChange(Number(e.target.value));
1283
+ }, [onChange]);
1284
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className, style: { ...style }, children: [
1285
+ label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 13, marginBottom: 4 }, children: [
1286
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: "#4a5568", fontWeight: 500 }, children: String(label) }),
1287
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { color: "#718096" }, children: numVal })
1288
+ ] }) : null,
1289
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
1290
+ "input",
1291
+ {
1292
+ type: "range",
1293
+ value: numVal,
1294
+ onChange: handleChange,
1295
+ min: Number(min) ?? 0,
1296
+ max: Number(max) ?? 100,
1297
+ step: Number(step) ?? 1,
1298
+ disabled: Boolean(disabled),
1299
+ style: { width: "100%" }
1300
+ }
1301
+ )
1302
+ ] });
1303
+ };
1304
+ }
1305
+ });
1306
+
1307
+ // src/player/atoms/grouping.tsx
1308
+ var grouping_exports = {};
1309
+ __export(grouping_exports, {
1310
+ Accordion: () => Accordion,
1311
+ Card: () => Card,
1312
+ Modal: () => Modal,
1313
+ ScrollArea: () => ScrollArea,
1314
+ Section: () => Section,
1315
+ Tabs: () => Tabs
1316
+ });
1317
+ var import_react6, import_jsx_runtime6, Card, Section, Tabs, Accordion, Modal, ScrollArea;
1318
+ var init_grouping = __esm({
1319
+ "src/player/atoms/grouping.tsx"() {
1320
+ "use strict";
1321
+ import_react6 = __toESM(require("react"));
1322
+ import_jsx_runtime6 = require("react/jsx-runtime");
1323
+ Card = ({ children, title, subtitle, padding, variant, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1324
+ "div",
1325
+ {
1326
+ className,
1327
+ style: {
1328
+ background: variant === "outlined" ? "transparent" : "#fff",
1329
+ border: "1px solid #e2e8f0",
1330
+ borderRadius: 8,
1331
+ padding: padding != null ? Number(padding) * 4 : 16,
1332
+ boxShadow: variant === "elevated" ? "0 2px 8px rgba(0,0,0,0.08)" : void 0,
1333
+ ...style
1334
+ },
1335
+ children: [
1336
+ title ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: subtitle ? 2 : 12 }, children: String(title) }) : null,
1337
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 13, color: "#718096", marginBottom: 12 }, children: String(subtitle) }) : null,
1338
+ children
1339
+ ]
1340
+ }
1341
+ );
1342
+ Section = ({ children, title, description, collapsible, defaultOpen, className, style }) => {
1343
+ const [open, setOpen] = (0, import_react6.useState)(defaultOpen !== false);
1344
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, style: { marginBottom: 16, ...style }, children: [
1345
+ title ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1346
+ "div",
1347
+ {
1348
+ style: {
1349
+ display: "flex",
1350
+ alignItems: "center",
1351
+ justifyContent: "space-between",
1352
+ marginBottom: open ? 12 : 0,
1353
+ cursor: collapsible ? "pointer" : void 0
1354
+ },
1355
+ onClick: collapsible ? () => setOpen((v) => !v) : void 0,
1356
+ children: [
1357
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { children: [
1358
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontWeight: 600, fontSize: 15 }, children: String(title) }),
1359
+ description ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontSize: 13, color: "#718096", marginTop: 2 }, children: String(description) }) : null
1360
+ ] }),
1361
+ collapsible ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: "#a0aec0", fontSize: 18 }, children: open ? "\u25BE" : "\u25B8" }) : null
1362
+ ]
1363
+ }
1364
+ ) : null,
1365
+ open ? children : null
1366
+ ] });
1367
+ };
1368
+ Tabs = ({ children, tabs, defaultTab, className, style }) => {
1369
+ const tabList = Array.isArray(tabs) ? tabs.map((t) => typeof t === "string" ? { label: t, value: t } : t) : [];
1370
+ const [active, setActive] = (0, import_react6.useState)(defaultTab ?? tabList[0]?.value ?? "");
1371
+ if (tabList.length === 0) {
1372
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style, children });
1373
+ }
1374
+ const childArray = import_react6.default.Children.toArray(children);
1375
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className, style, children: [
1376
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: "flex", borderBottom: "2px solid #e2e8f0", marginBottom: 12, gap: 0 }, children: tabList.map((tab) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1377
+ "button",
1378
+ {
1379
+ onClick: () => setActive(tab.value),
1380
+ style: {
1381
+ padding: "8px 16px",
1382
+ fontSize: 14,
1383
+ fontWeight: 500,
1384
+ cursor: "pointer",
1385
+ border: "none",
1386
+ background: "none",
1387
+ borderBottom: "2px solid transparent",
1388
+ marginBottom: -2,
1389
+ color: active === tab.value ? "#3182ce" : "#718096",
1390
+ borderBottomColor: active === tab.value ? "#3182ce" : "transparent"
1391
+ },
1392
+ children: tab.label
1393
+ },
1394
+ tab.value
1395
+ )) }),
1396
+ childArray.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { display: tabList[i]?.value === active ? "block" : "none" }, children: child }, i))
1397
+ ] });
1398
+ };
1399
+ Accordion = ({ children, items, allowMultiple, className, style }) => {
1400
+ const [openItems, setOpenItems] = (0, import_react6.useState)(/* @__PURE__ */ new Set([0]));
1401
+ const toggle = (0, import_react6.useCallback)((index) => {
1402
+ setOpenItems((prev) => {
1403
+ const next = new Set(allowMultiple ? prev : []);
1404
+ if (prev.has(index)) next.delete(index);
1405
+ else next.add(index);
1406
+ return next;
1407
+ });
1408
+ }, [allowMultiple]);
1409
+ const itemList = Array.isArray(items) ? items : [];
1410
+ if (itemList.length === 0) {
1411
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style, children });
1412
+ }
1413
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className, style: { border: "1px solid #e2e8f0", borderRadius: 8, overflow: "hidden", ...style }, children: itemList.map((item, i) => {
1414
+ const itm = item;
1415
+ const isOpen = openItems.has(i);
1416
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { borderBottom: i < itemList.length - 1 ? "1px solid #e2e8f0" : "none" }, children: [
1417
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1418
+ "button",
1419
+ {
1420
+ onClick: () => toggle(i),
1421
+ style: {
1422
+ width: "100%",
1423
+ padding: "12px 16px",
1424
+ background: "none",
1425
+ border: "none",
1426
+ textAlign: "left",
1427
+ cursor: "pointer",
1428
+ display: "flex",
1429
+ justifyContent: "space-between",
1430
+ alignItems: "center",
1431
+ fontSize: 14,
1432
+ fontWeight: 500
1433
+ },
1434
+ children: [
1435
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: String(itm.title ?? itm.label ?? `Item ${i + 1}`) }),
1436
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: "#a0aec0" }, children: isOpen ? "\u25BE" : "\u25B8" })
1437
+ ]
1438
+ }
1439
+ ),
1440
+ isOpen ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { padding: "0 16px 12px" }, children: itm.content ? String(itm.content) : null }) : null
1441
+ ] }, i);
1442
+ }) });
1443
+ };
1444
+ Modal = ({ children, open, isOpen, onClose, title, size, id, nodeId, className, style }) => {
1445
+ const modalId = id ?? nodeId;
1446
+ const [eventOpen, setEventOpen] = (0, import_react6.useState)(false);
1447
+ (0, import_react6.useEffect)(() => {
1448
+ if (!modalId) return;
1449
+ const handleOpen = (e) => {
1450
+ const detail = e.detail;
1451
+ if (detail === modalId || detail?.id === modalId) {
1452
+ setEventOpen(true);
1453
+ }
1454
+ };
1455
+ const handleClose = (e) => {
1456
+ const detail = e.detail;
1457
+ if (detail === modalId || detail?.id === modalId) {
1458
+ setEventOpen(false);
1459
+ }
1460
+ };
1461
+ window.addEventListener("openModal", handleOpen);
1462
+ window.addEventListener("closeModal", handleClose);
1463
+ return () => {
1464
+ window.removeEventListener("openModal", handleOpen);
1465
+ window.removeEventListener("closeModal", handleClose);
1466
+ };
1467
+ }, [modalId]);
1468
+ const visible = Boolean(open ?? isOpen ?? eventOpen);
1469
+ (0, import_react6.useEffect)(() => {
1470
+ if (visible) document.body.style.overflow = "hidden";
1471
+ return () => {
1472
+ document.body.style.overflow = "";
1473
+ };
1474
+ }, [visible]);
1475
+ if (!visible) return null;
1476
+ const widthMap = { sm: 400, md: 560, lg: 720, xl: 960, full: 9999 };
1477
+ const maxWidth = widthMap[size ?? "md"] ?? 560;
1478
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1479
+ "div",
1480
+ {
1481
+ style: {
1482
+ position: "fixed",
1483
+ inset: 0,
1484
+ zIndex: 9999,
1485
+ display: "flex",
1486
+ alignItems: "center",
1487
+ justifyContent: "center",
1488
+ background: "rgba(0,0,0,0.4)"
1489
+ },
1490
+ onClick: (e) => {
1491
+ if (e.target === e.currentTarget) {
1492
+ setEventOpen(false);
1493
+ if (typeof onClose === "function") onClose();
1494
+ }
1495
+ },
1496
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1497
+ "div",
1498
+ {
1499
+ className,
1500
+ style: {
1501
+ background: "#fff",
1502
+ borderRadius: 12,
1503
+ padding: 24,
1504
+ maxWidth,
1505
+ width: "90%",
1506
+ maxHeight: "85vh",
1507
+ overflow: "auto",
1508
+ boxShadow: "0 20px 60px rgba(0,0,0,0.2)",
1509
+ ...style
1510
+ },
1511
+ children: [
1512
+ title || onClose ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 16 }, children: [
1513
+ title ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { fontWeight: 600, fontSize: 18 }, children: String(title) }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", {}),
1514
+ typeof onClose === "function" ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1515
+ "button",
1516
+ {
1517
+ onClick: () => {
1518
+ setEventOpen(false);
1519
+ onClose();
1520
+ },
1521
+ style: { background: "none", border: "none", fontSize: 20, cursor: "pointer", color: "#a0aec0", padding: 4 },
1522
+ children: "\u2715"
1523
+ }
1524
+ ) : null
1525
+ ] }) : null,
1526
+ children
1527
+ ]
1528
+ }
1529
+ )
1530
+ }
1531
+ );
1532
+ };
1533
+ ScrollArea = ({ children, maxHeight, className, style }) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1534
+ "div",
1535
+ {
1536
+ className,
1537
+ style: {
1538
+ overflow: "auto",
1539
+ maxHeight: maxHeight ? Number(maxHeight) : void 0,
1540
+ ...style
1541
+ },
1542
+ children
1543
+ }
1544
+ );
1545
+ }
1546
+ });
1547
+
1548
+ // src/player/atoms/navigation.tsx
1549
+ var navigation_exports = {};
1550
+ __export(navigation_exports, {
1551
+ NavLink: () => NavLink,
1552
+ RoleGuard: () => RoleGuard,
1553
+ Route: () => Route,
1554
+ Router: () => Router,
1555
+ usePlayerRouter: () => usePlayerRouter
1556
+ });
1557
+ function usePlayerRouter() {
1558
+ return (0, import_react7.useContext)(RouterCtx);
1559
+ }
1560
+ function matchPath(pattern, currentPath, exact) {
1561
+ const params = {};
1562
+ const patternParts = pattern.split("/").filter(Boolean);
1563
+ const pathParts = currentPath.split("/").filter(Boolean);
1564
+ if (exact && patternParts.length !== pathParts.length) {
1565
+ return { match: false, params };
1566
+ }
1567
+ if (patternParts.length > pathParts.length) {
1568
+ return { match: false, params };
1569
+ }
1570
+ for (let i = 0; i < patternParts.length; i++) {
1571
+ const pp = patternParts[i];
1572
+ if (pp.startsWith(":")) {
1573
+ params[pp.slice(1)] = pathParts[i];
1574
+ } else if (pp === "*") {
1575
+ return { match: true, params };
1576
+ } else if (pp !== pathParts[i]) {
1577
+ return { match: false, params };
1578
+ }
1579
+ }
1580
+ return { match: true, params };
1581
+ }
1582
+ var import_react7, import_jsx_runtime7, RouterCtx, Router, Route, NavLink, RoleGuard;
1583
+ var init_navigation = __esm({
1584
+ "src/player/atoms/navigation.tsx"() {
1585
+ "use strict";
1586
+ import_react7 = require("react");
1587
+ init_scope_builder();
1588
+ import_jsx_runtime7 = require("react/jsx-runtime");
1589
+ RouterCtx = (0, import_react7.createContext)({
1590
+ path: "/",
1591
+ navigate: () => {
1592
+ },
1593
+ params: {}
1594
+ });
1595
+ Router = ({ children, basePath, className, style }) => {
1596
+ const [path, setPath] = (0, import_react7.useState)(basePath ?? "/");
1597
+ const navigate = (0, import_react7.useCallback)((to) => {
1598
+ setPath(to);
1599
+ }, []);
1600
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RouterCtx.Provider, { value: { path, navigate, params: {} }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style, children }) });
1601
+ };
1602
+ Route = ({ children, path: routePath, exact, className, style }) => {
1603
+ const { path } = (0, import_react7.useContext)(RouterCtx);
1604
+ const pattern = routePath ?? "/";
1605
+ const { match, params } = matchPath(pattern, path, exact !== false);
1606
+ if (!match) return null;
1607
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RouterCtx.Provider, { value: { path, navigate: (0, import_react7.useContext)(RouterCtx).navigate, params }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className, style, children }) });
1608
+ };
1609
+ NavLink = ({
1610
+ children,
1611
+ to,
1612
+ label,
1613
+ icon,
1614
+ activeClassName,
1615
+ className,
1616
+ style,
1617
+ onClick
1618
+ }) => {
1619
+ const { path, navigate } = (0, import_react7.useContext)(RouterCtx);
1620
+ const target = to ?? "/";
1621
+ const isActive = path === target || path.startsWith(target + "/");
1622
+ const text = children ?? label;
1623
+ const handleClick = (0, import_react7.useCallback)((e) => {
1624
+ e.preventDefault();
1625
+ navigate(target);
1626
+ if (typeof onClick === "function") onClick(e);
1627
+ }, [navigate, target, onClick]);
1628
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
1629
+ "button",
1630
+ {
1631
+ className: `${className ?? ""} ${isActive && activeClassName ? activeClassName : ""}`.trim() || void 0,
1632
+ onClick: handleClick,
1633
+ style: {
1634
+ background: isActive ? "#ebf8ff" : "transparent",
1635
+ color: isActive ? "#2b6cb0" : "#4a5568",
1636
+ border: "none",
1637
+ borderRadius: 6,
1638
+ padding: "6px 12px",
1639
+ fontSize: 14,
1640
+ fontWeight: isActive ? 600 : 400,
1641
+ cursor: "pointer",
1642
+ display: "inline-flex",
1643
+ alignItems: "center",
1644
+ gap: 6,
1645
+ transition: "background 0.15s, color 0.15s",
1646
+ ...style
1647
+ },
1648
+ children: [
1649
+ icon ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: String(icon) }) : null,
1650
+ text != null ? String(text) : null
1651
+ ]
1652
+ }
1653
+ );
1654
+ };
1655
+ RoleGuard = ({ children, role, roles, fallback }) => {
1656
+ const scope = useScope();
1657
+ const allowed = (0, import_react7.useMemo)(() => {
1658
+ const required = Array.isArray(roles) ? roles : role != null ? [String(role)] : [];
1659
+ if (required.length === 0) return true;
1660
+ const userRoles = scope.$user?.roles ?? [];
1661
+ if (userRoles.length === 0) return false;
1662
+ return required.some((r) => userRoles.includes(r));
1663
+ }, [role, roles, scope.$user]);
1664
+ if (!allowed) {
1665
+ return fallback ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children: fallback }) : null;
1666
+ }
1667
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(import_jsx_runtime7.Fragment, { children });
1668
+ };
1669
+ }
1670
+ });
1671
+
1672
+ // src/player/atoms/composition.tsx
1673
+ var composition_exports = {};
1674
+ __export(composition_exports, {
1675
+ ModuleOutlet: () => ModuleOutlet,
1676
+ Slot: () => Slot,
1677
+ SlotRegistryProvider: () => SlotRegistryProvider,
1678
+ useSlotContributions: () => useSlotContributions
1679
+ });
1680
+ function useSlotContributions(name) {
1681
+ const registry = (0, import_react8.useContext)(SlotRegistryContext);
1682
+ return registry.get(name) ?? [];
1683
+ }
1684
+ var import_react8, import_jsx_runtime8, SlotRegistryContext, SlotRegistryProvider, Slot, ModuleOutlet;
1685
+ var init_composition = __esm({
1686
+ "src/player/atoms/composition.tsx"() {
1687
+ "use strict";
1688
+ import_react8 = __toESM(require("react"));
1689
+ import_jsx_runtime8 = require("react/jsx-runtime");
1690
+ SlotRegistryContext = (0, import_react8.createContext)(/* @__PURE__ */ new Map());
1691
+ SlotRegistryProvider = ({ contributions, children }) => {
1692
+ const registry = (0, import_react8.useMemo)(() => {
1693
+ const map = /* @__PURE__ */ new Map();
1694
+ for (const c of contributions) {
1695
+ const list = map.get(c.name) ?? [];
1696
+ list.push(c);
1697
+ map.set(c.name, list);
1698
+ }
1699
+ for (const [, list] of map) {
1700
+ list.sort((a, b) => (b.priority ?? 0) - (a.priority ?? 0));
1701
+ }
1702
+ return map;
1703
+ }, [contributions]);
1704
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SlotRegistryContext.Provider, { value: registry, children });
1705
+ };
1706
+ Slot = ({ children, name, fallback, className, style }) => {
1707
+ const slotName = name ?? "";
1708
+ const contributions = useSlotContributions(slotName);
1709
+ const content = contributions.length > 0 ? contributions.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.default.Fragment, { children: c.tree }, i)) : children ?? fallback;
1710
+ if (!content) return null;
1711
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1712
+ "div",
1713
+ {
1714
+ className,
1715
+ "data-slot": slotName,
1716
+ style,
1717
+ children: content
1718
+ }
1719
+ );
1720
+ };
1721
+ ModuleOutlet = ({ children, module: moduleName, basePath, className, style }) => {
1722
+ const moduleKey = moduleName ?? "";
1723
+ const contributions = useSlotContributions(`module:${moduleKey}`);
1724
+ if (contributions.length > 0) {
1725
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1726
+ "div",
1727
+ {
1728
+ className,
1729
+ "data-module": moduleKey,
1730
+ style,
1731
+ children: contributions.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_react8.default.Fragment, { children: c.tree }, i))
1732
+ }
1733
+ );
1734
+ }
1735
+ if (children) {
1736
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1737
+ "div",
1738
+ {
1739
+ className,
1740
+ "data-module": moduleKey,
1741
+ style,
1742
+ children
1743
+ }
1744
+ );
1745
+ }
1746
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
1747
+ "div",
1748
+ {
1749
+ className,
1750
+ "data-module": moduleKey,
1751
+ style: {
1752
+ padding: 16,
1753
+ border: "1px dashed #cbd5e0",
1754
+ borderRadius: 8,
1755
+ color: "#a0aec0",
1756
+ fontSize: 13,
1757
+ textAlign: "center",
1758
+ ...style
1759
+ },
1760
+ children: [
1761
+ "Module: ",
1762
+ String(moduleName ?? "unknown"),
1763
+ basePath ? /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { children: [
1764
+ " (",
1765
+ String(basePath),
1766
+ ")"
1767
+ ] }) : null
1768
+ ]
1769
+ }
1770
+ );
1771
+ };
1772
+ }
1773
+ });
1774
+
1775
+ // src/player/atoms/data.tsx
1776
+ var data_exports = {};
1777
+ __export(data_exports, {
1778
+ DataGrid: () => DataGrid,
1779
+ Table: () => Table
1780
+ });
1781
+ var import_react9, import_jsx_runtime9, Table, DataGrid;
1782
+ var init_data = __esm({
1783
+ "src/player/atoms/data.tsx"() {
1784
+ "use strict";
1785
+ import_react9 = require("react");
1786
+ import_jsx_runtime9 = require("react/jsx-runtime");
1787
+ Table = ({ data, columns, rows, onRowClick, striped, compact, className, style }) => {
1788
+ const items = Array.isArray(data ?? rows) ? data ?? rows : [];
1789
+ const cols = Array.isArray(columns) ? columns.map(
1790
+ (c) => typeof c === "string" ? { key: c, label: c, header: c } : c
1791
+ ) : items.length > 0 ? Object.keys(items[0]).filter((k) => k !== "id" && !k.startsWith("_")).map((k) => ({ key: k, label: k, header: k })) : [];
1792
+ const pad = compact ? "4px 8px" : "8px 12px";
1793
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className, style: { overflow: "auto", ...style }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("table", { style: { width: "100%", borderCollapse: "collapse", fontSize: 14 }, children: [
1794
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { children: cols.map((col, i) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1795
+ "th",
1796
+ {
1797
+ style: {
1798
+ textAlign: "left",
1799
+ padding: pad,
1800
+ fontWeight: 600,
1801
+ fontSize: 12,
1802
+ color: "#718096",
1803
+ borderBottom: "2px solid #e2e8f0",
1804
+ textTransform: "uppercase",
1805
+ letterSpacing: "0.05em"
1806
+ },
1807
+ children: String(col.label ?? col.header ?? col.key ?? "")
1808
+ },
1809
+ String(col.key ?? i)
1810
+ )) }) }),
1811
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("tbody", { children: [
1812
+ items.map((row, ri) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1813
+ "tr",
1814
+ {
1815
+ onClick: typeof onRowClick === "function" ? () => onRowClick(row) : void 0,
1816
+ style: {
1817
+ cursor: typeof onRowClick === "function" ? "pointer" : void 0,
1818
+ background: striped && ri % 2 === 1 ? "#f7fafc" : void 0
1819
+ },
1820
+ children: cols.map((col, ci) => {
1821
+ const val = row[col.key];
1822
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1823
+ "td",
1824
+ {
1825
+ style: { padding: pad, borderBottom: "1px solid #edf2f7" },
1826
+ children: val != null ? String(val) : /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: "#cbd5e0" }, children: "\u2014" })
1827
+ },
1828
+ String(col.key ?? ci)
1829
+ );
1830
+ })
1831
+ },
1832
+ String(row.id ?? ri)
1833
+ )),
1834
+ items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1835
+ "td",
1836
+ {
1837
+ colSpan: cols.length,
1838
+ style: { padding: "24px 12px", textAlign: "center", color: "#a0aec0", fontStyle: "italic" },
1839
+ children: "No data"
1840
+ }
1841
+ ) }) : null
1842
+ ] })
1843
+ ] }) });
1844
+ };
1845
+ DataGrid = ({ data, columns, onRowClick, searchable, className, style, children }) => {
1846
+ const [search, setSearch] = (0, import_react9.useState)("");
1847
+ const items = Array.isArray(data) ? data : [];
1848
+ const filtered = (0, import_react9.useMemo)(() => {
1849
+ if (!search) return items;
1850
+ const q = search.toLowerCase();
1851
+ return items.filter(
1852
+ (item) => Object.values(item).some((v) => v != null && String(v).toLowerCase().includes(q))
1853
+ );
1854
+ }, [items, search]);
1855
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className, style, children: [
1856
+ searchable ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { marginBottom: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1857
+ "input",
1858
+ {
1859
+ type: "text",
1860
+ placeholder: "Search...",
1861
+ value: search,
1862
+ onChange: (e) => setSearch(e.target.value),
1863
+ style: {
1864
+ padding: "6px 12px",
1865
+ border: "1px solid #e2e8f0",
1866
+ borderRadius: 6,
1867
+ fontSize: 14,
1868
+ width: "100%",
1869
+ boxSizing: "border-box"
1870
+ }
1871
+ }
1872
+ ) }) : null,
1873
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Table, { data: filtered, columns, onRowClick, striped: true }),
1874
+ children
1875
+ ] });
1876
+ };
1877
+ }
1878
+ });
1879
+
30
1880
  // src/player/index.ts
31
1881
  var player_exports = {};
32
1882
  __export(player_exports, {
1883
+ AtomRegistryImpl: () => AtomRegistryImpl,
33
1884
  ComponentTreeRenderer: () => ComponentTreeRenderer,
1885
+ DEFAULT_DESIGN_TOKENS: () => DEFAULT_DESIGN_TOKENS,
34
1886
  DevPlayer: () => DevPlayer,
1887
+ ExperienceRenderer: () => ExperienceRenderer,
1888
+ PlayerProvider: () => PlayerProvider,
1889
+ ScopeContext: () => ScopeContext,
1890
+ SlotRegistryProvider: () => SlotRegistryProvider,
1891
+ buildActionScope: () => buildActionScope,
1892
+ buildEvalContext: () => buildEvalContext,
1893
+ buildLoopScope: () => buildLoopScope,
1894
+ buildScope: () => buildScope,
35
1895
  builtinAtoms: () => builtinAtoms,
36
- containsExpression: () => containsExpression,
1896
+ builtinFunctions: () => builtinFunctions,
1897
+ classifyBinding: () => classifyBinding,
1898
+ createApiResolver: () => createApiResolver,
1899
+ createCoreAtomRegistry: () => createCoreAtomRegistry,
37
1900
  evaluateExpression: () => evaluateExpression,
38
- evaluateProp: () => evaluateProp
1901
+ mergeRegistries: () => mergeRegistries,
1902
+ mergeScope: () => mergeScope,
1903
+ resolveAllBindings: () => resolveAllBindings,
1904
+ resolveBinding: () => resolveBinding,
1905
+ setWasmModule: () => setWasmModule,
1906
+ usePlayerContext: () => usePlayerContext,
1907
+ usePlayerRouter: () => usePlayerRouter,
1908
+ useScope: () => useScope,
1909
+ useSlotContributions: () => useSlotContributions,
1910
+ useTheme: () => useTheme
39
1911
  });
40
1912
  module.exports = __toCommonJS(player_exports);
41
1913
 
42
- // src/player/ComponentTreeRenderer.tsx
43
- var import_react = __toESM(require("react"));
1914
+ // src/player/ExperienceRenderer.tsx
1915
+ var import_react12 = __toESM(require("react"));
1916
+ init_scope_builder();
44
1917
 
45
- // src/player/evaluator.ts
46
- var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
47
- function containsExpression(value) {
48
- return typeof value === "string" && EXPR_PATTERN.test(value);
1918
+ // src/player/binding-resolver.ts
1919
+ init_expression_engine();
1920
+ function classifyBinding(expr) {
1921
+ const t = expr.trim();
1922
+ const type = classifyExpression(t);
1923
+ switch (type) {
1924
+ case "literal":
1925
+ return { type, value: parseLiteralValue(t) };
1926
+ case "path": {
1927
+ const dotIdx = t.indexOf(".");
1928
+ if (dotIdx === -1) return { type, root: t, rest: "" };
1929
+ return { type, root: t.slice(0, dotIdx), rest: t.slice(dotIdx + 1) };
1930
+ }
1931
+ case "function": {
1932
+ const fnCall = parseFunctionCall(t);
1933
+ if (fnCall) return { type, name: fnCall.name, rawArgs: fnCall.args };
1934
+ return { type, expression: t };
1935
+ }
1936
+ case "action": {
1937
+ const fnCall = parseFunctionCall(t);
1938
+ if (fnCall) return { type, name: fnCall.name, rawArgs: fnCall.args };
1939
+ if (t.startsWith("$action.")) return { type, name: t.slice("$action.".length), rawArgs: [] };
1940
+ return { type, expression: t };
1941
+ }
1942
+ case "condition":
1943
+ if (t.startsWith("$expr(") && t.endsWith(")")) return { type, expression: t.slice(6, -1) };
1944
+ return { type, expression: t };
1945
+ }
49
1946
  }
50
- function resolvePath(path, scope) {
51
- const parts = path.trim().split(".");
52
- let current = scope;
53
- for (const part of parts) {
54
- if (current == null || typeof current !== "object") return void 0;
55
- current = current[part];
1947
+ function parseLiteralValue(t) {
1948
+ if (t === "[Expression]" || t.includes("[Expression]")) return void 0;
1949
+ if (t.startsWith('"') && t.endsWith('"') || t.startsWith("'") && t.endsWith("'")) return t.slice(1, -1);
1950
+ if (/^-?\d+(\.\d+)?$/.test(t)) return Number(t);
1951
+ if (t === "true") return true;
1952
+ if (t === "false") return false;
1953
+ if (t === "null") return null;
1954
+ return void 0;
1955
+ }
1956
+ function parseFunctionCall(expr) {
1957
+ const match = expr.match(/^\$(fn|action)\.(\w+)\((.*)\)$/s);
1958
+ if (!match) return null;
1959
+ const [, namespace, name, argsStr] = match;
1960
+ const args = argsStr.trim() ? splitArgs(argsStr.trim()) : [];
1961
+ return { namespace, name, args };
1962
+ }
1963
+ function splitArgs(argsStr) {
1964
+ const args = [];
1965
+ let current = "";
1966
+ let depth = 0;
1967
+ let inString = null;
1968
+ for (let i = 0; i < argsStr.length; i++) {
1969
+ const ch = argsStr[i];
1970
+ if (inString) {
1971
+ current += ch;
1972
+ if (ch === inString && argsStr[i - 1] !== "\\") inString = null;
1973
+ } else if (ch === '"' || ch === "'") {
1974
+ current += ch;
1975
+ inString = ch;
1976
+ } else if (ch === "(" || ch === "[") {
1977
+ current += ch;
1978
+ depth++;
1979
+ } else if (ch === ")" || ch === "]") {
1980
+ current += ch;
1981
+ depth--;
1982
+ } else if (ch === "," && depth === 0) {
1983
+ args.push(current.trim());
1984
+ current = "";
1985
+ } else {
1986
+ current += ch;
1987
+ }
56
1988
  }
57
- return current;
1989
+ if (current.trim()) args.push(current.trim());
1990
+ return args;
58
1991
  }
59
- function evaluateExpression(expr, scopes) {
60
- const trimmed = expr.trim();
61
- if (trimmed.startsWith("'") && trimmed.endsWith("'") || trimmed.startsWith('"') && trimmed.endsWith('"')) {
62
- return trimmed.slice(1, -1);
1992
+ function resolveBinding(expr, scope) {
1993
+ const binding = classifyBinding(expr);
1994
+ switch (binding.type) {
1995
+ case "literal":
1996
+ return binding.value;
1997
+ case "path":
1998
+ return resolveScopedPath(binding.root, binding.rest, scope);
1999
+ case "function":
2000
+ return resolveFunction(binding.name, binding.rawArgs, scope);
2001
+ case "action":
2002
+ return resolveAction(binding.name, binding.rawArgs, scope);
2003
+ case "condition":
2004
+ return resolveCondition(binding.expression ?? expr, scope);
2005
+ default:
2006
+ return void 0;
2007
+ }
2008
+ }
2009
+ function resolveAllBindings(bindings, scope) {
2010
+ const resolved = {};
2011
+ for (const [propName, expr] of Object.entries(bindings)) {
2012
+ try {
2013
+ resolved[propName] = resolveBinding(expr, scope);
2014
+ } catch {
2015
+ resolved[propName] = void 0;
2016
+ }
2017
+ }
2018
+ return resolved;
2019
+ }
2020
+ function resolveScopedPath(root, rest, scope) {
2021
+ let rootValue;
2022
+ switch (root) {
2023
+ case "$instance":
2024
+ rootValue = scope.$instance;
2025
+ break;
2026
+ case "$instances":
2027
+ rootValue = scope.$instances;
2028
+ break;
2029
+ case "$definition":
2030
+ rootValue = scope.$definition;
2031
+ break;
2032
+ case "$pagination":
2033
+ rootValue = scope.$pagination;
2034
+ break;
2035
+ case "$entity":
2036
+ rootValue = scope.$entity;
2037
+ break;
2038
+ case "$local":
2039
+ rootValue = scope.$local;
2040
+ break;
2041
+ case "$user":
2042
+ rootValue = scope.$user;
2043
+ break;
2044
+ case "$action":
2045
+ rootValue = scope.$action;
2046
+ break;
2047
+ case "$fn":
2048
+ rootValue = scope.$fn;
2049
+ break;
2050
+ case "$item":
2051
+ rootValue = scope.$item;
2052
+ break;
2053
+ case "$index":
2054
+ rootValue = scope.$index;
2055
+ break;
2056
+ default:
2057
+ rootValue = scope[root];
2058
+ if (rootValue === void 0) {
2059
+ rootValue = scope.$item;
2060
+ if (rootValue != null && rest) {
2061
+ return resolvePath(`${root}.${rest}`, { [root]: scope.$item });
2062
+ }
2063
+ }
2064
+ }
2065
+ if (!rest) return rootValue;
2066
+ if (rootValue == null) return void 0;
2067
+ return resolvePath(rest, rootValue);
2068
+ }
2069
+ function resolveFunction(name, rawArgs, scope) {
2070
+ const fn = scope.$fn?.[name] ?? builtinFunctions[name];
2071
+ if (typeof fn !== "function") {
2072
+ console.warn(`[binding-resolver] Unknown function: $fn.${name}`);
2073
+ return void 0;
2074
+ }
2075
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
2076
+ try {
2077
+ return fn(...resolvedArgs);
2078
+ } catch (err) {
2079
+ console.warn(`[binding-resolver] Error calling $fn.${name}:`, err);
2080
+ return void 0;
2081
+ }
2082
+ }
2083
+ function resolveAction(name, rawArgs, scope) {
2084
+ const actions = scope.$action;
2085
+ if (!actions) return void 0;
2086
+ if (rawArgs.length === 0) {
2087
+ const actionFn2 = actions[name];
2088
+ if (typeof actionFn2 === "function") return actionFn2;
2089
+ return void 0;
2090
+ }
2091
+ const actionFn = actions[name];
2092
+ if (typeof actionFn !== "function") return void 0;
2093
+ return (...callArgs) => {
2094
+ const resolvedArgs = rawArgs.map((arg) => resolveBinding(arg.trim(), scope));
2095
+ return actionFn(...resolvedArgs, ...callArgs);
2096
+ };
2097
+ }
2098
+ function resolveCondition(expression, scope) {
2099
+ const context = buildEvalContext(scope);
2100
+ return evaluateExpression(expression, context);
2101
+ }
2102
+ function buildEvalContext(scope) {
2103
+ const ctx = {};
2104
+ ctx.$instance = scope.$instance;
2105
+ ctx.$instances = scope.$instances;
2106
+ ctx.$definition = scope.$definition;
2107
+ ctx.$pagination = scope.$pagination;
2108
+ ctx.$entity = scope.$entity;
2109
+ ctx.$local = scope.$local;
2110
+ ctx.$user = scope.$user;
2111
+ ctx.$action = scope.$action;
2112
+ ctx.$fn = scope.$fn;
2113
+ ctx.$item = scope.$item;
2114
+ ctx.$index = scope.$index;
2115
+ if (scope.$instances) ctx.items = scope.$instances;
2116
+ if (scope.$instance) {
2117
+ ctx.instance = scope.$instance;
2118
+ ctx.loading = false;
2119
+ }
2120
+ if (scope.$item) ctx.item = scope.$item;
2121
+ if (scope.$index != null) ctx.index = scope.$index;
2122
+ if (scope.state_data) ctx.state_data = scope.state_data;
2123
+ if (scope.memory) ctx.memory = scope.memory;
2124
+ if (scope.context) ctx.context = scope.context;
2125
+ return ctx;
2126
+ }
2127
+ function buildActionScope(opts) {
2128
+ const { resolver, instanceId, slug, setLocal, router, toast, refreshQuery, onEvent } = opts;
2129
+ return {
2130
+ transition: async (name, id, data) => {
2131
+ const targetId = id ?? instanceId;
2132
+ if (!targetId) {
2133
+ console.warn("[action] transition called without instanceId");
2134
+ return;
2135
+ }
2136
+ await resolver.transition(targetId, name, data);
2137
+ refreshQuery?.();
2138
+ },
2139
+ create: async (targetSlug, data) => {
2140
+ const id = await resolver.create(targetSlug || slug || "", data);
2141
+ refreshQuery?.();
2142
+ return id;
2143
+ },
2144
+ update: async (id, fields) => {
2145
+ await resolver.update(id, fields);
2146
+ refreshQuery?.();
2147
+ },
2148
+ remove: async (id) => {
2149
+ await resolver.remove(id);
2150
+ refreshQuery?.();
2151
+ },
2152
+ setLocal: (key, value) => {
2153
+ setLocal(key, value);
2154
+ },
2155
+ navigate: (path) => {
2156
+ router?.push(path);
2157
+ },
2158
+ toast: (message, variant) => {
2159
+ toast?.(message, variant);
2160
+ },
2161
+ refreshQuery: (dataSourceName) => {
2162
+ refreshQuery?.(dataSourceName);
2163
+ },
2164
+ scrollTo: (elementId) => {
2165
+ if (typeof document !== "undefined") {
2166
+ const el = document.getElementById(elementId);
2167
+ el?.scrollIntoView({ behavior: "smooth" });
2168
+ }
2169
+ },
2170
+ openModal: (modalId) => {
2171
+ if (typeof window !== "undefined") {
2172
+ window.dispatchEvent(new CustomEvent("player:open_modal", { detail: { id: modalId } }));
2173
+ }
2174
+ },
2175
+ closeModal: (modalId) => {
2176
+ if (typeof window !== "undefined") {
2177
+ window.dispatchEvent(new CustomEvent("player:close_modal", { detail: { id: modalId } }));
2178
+ }
2179
+ },
2180
+ emit: (event, payload) => {
2181
+ onEvent?.(event, payload);
2182
+ }
2183
+ };
2184
+ }
2185
+
2186
+ // src/player/ExperienceRenderer.tsx
2187
+ init_expression_engine();
2188
+
2189
+ // src/player/PlayerProvider.tsx
2190
+ var import_react11 = require("react");
2191
+
2192
+ // src/hooks/useQuery.ts
2193
+ var import_react2 = require("react");
2194
+ var _globalResolver = null;
2195
+ function setQueryResolver(resolver) {
2196
+ _globalResolver = resolver;
2197
+ }
2198
+
2199
+ // src/hooks/useMutation.ts
2200
+ var import_react3 = require("react");
2201
+ var _globalMutationResolver = null;
2202
+ function setMutationResolver(resolver) {
2203
+ _globalMutationResolver = resolver;
2204
+ }
2205
+
2206
+ // src/player/atom-registry.ts
2207
+ var import_react10 = __toESM(require("react"));
2208
+ function namedExport(loader, exportName) {
2209
+ return () => loader().then((mod) => ({ default: mod[exportName] }));
2210
+ }
2211
+ var AtomRegistryImpl = class _AtomRegistryImpl {
2212
+ loaders = /* @__PURE__ */ new Map();
2213
+ lazyCache = /* @__PURE__ */ new Map();
2214
+ eagerCache = /* @__PURE__ */ new Map();
2215
+ register(name, loader) {
2216
+ this.loaders.set(name, loader);
2217
+ this.lazyCache.delete(name);
2218
+ }
2219
+ registerEager(name, component) {
2220
+ this.eagerCache.set(name, component);
2221
+ }
2222
+ resolve(name) {
2223
+ const eager = this.eagerCache.get(name);
2224
+ if (eager) {
2225
+ const cached2 = this.lazyCache.get(name);
2226
+ if (cached2) return cached2;
2227
+ const lazy2 = import_react10.default.lazy(() => Promise.resolve({ default: eager }));
2228
+ this.lazyCache.set(name, lazy2);
2229
+ return lazy2;
2230
+ }
2231
+ const cached = this.lazyCache.get(name);
2232
+ if (cached) return cached;
2233
+ const loader = this.loaders.get(name);
2234
+ if (!loader) return null;
2235
+ const lazy = import_react10.default.lazy(loader);
2236
+ this.lazyCache.set(name, lazy);
2237
+ return lazy;
2238
+ }
2239
+ resolveSync(name) {
2240
+ return this.eagerCache.get(name) ?? null;
2241
+ }
2242
+ has(name) {
2243
+ return this.loaders.has(name) || this.eagerCache.has(name);
2244
+ }
2245
+ list() {
2246
+ const names = /* @__PURE__ */ new Set();
2247
+ for (const k of this.loaders.keys()) names.add(k);
2248
+ for (const k of this.eagerCache.keys()) names.add(k);
2249
+ return Array.from(names).sort();
2250
+ }
2251
+ merge(other) {
2252
+ const merged = new _AtomRegistryImpl();
2253
+ for (const [name, loader] of this.loaders) merged.loaders.set(name, loader);
2254
+ for (const [name, comp] of this.eagerCache) merged.eagerCache.set(name, comp);
2255
+ for (const name of other.list()) {
2256
+ const otherImpl = other;
2257
+ if (otherImpl.loaders?.has(name)) {
2258
+ merged.loaders.set(name, otherImpl.loaders.get(name));
2259
+ }
2260
+ if (otherImpl.eagerCache?.has(name)) {
2261
+ merged.eagerCache.set(name, otherImpl.eagerCache.get(name));
2262
+ }
2263
+ }
2264
+ return merged;
2265
+ }
2266
+ toRecord() {
2267
+ const record = {};
2268
+ for (const name of this.eagerCache.keys()) {
2269
+ record[name] = this.eagerCache.get(name);
2270
+ }
2271
+ return record;
2272
+ }
2273
+ };
2274
+ function createCoreAtomRegistry() {
2275
+ const registry = new AtomRegistryImpl();
2276
+ registry.register("Stack", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Stack"));
2277
+ registry.register("Row", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Row"));
2278
+ registry.register("Grid", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Grid"));
2279
+ registry.register("Column", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Column"));
2280
+ registry.register("Divider", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Divider"));
2281
+ registry.register("Spacer", namedExport(() => Promise.resolve().then(() => (init_layout(), layout_exports)), "Spacer"));
2282
+ registry.register("Text", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Text"));
2283
+ registry.register("Heading", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Heading"));
2284
+ registry.register("Field", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Field"));
2285
+ registry.register("Image", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Image"));
2286
+ registry.register("Badge", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Badge"));
2287
+ registry.register("Icon", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Icon"));
2288
+ registry.register("Button", namedExport(() => Promise.resolve().then(() => (init_actions(), actions_exports)), "Button"));
2289
+ registry.register("Link", namedExport(() => Promise.resolve().then(() => (init_actions(), actions_exports)), "Link"));
2290
+ registry.register("Show", namedExport(() => Promise.resolve().then(() => (init_control_flow(), control_flow_exports)), "Show"));
2291
+ registry.register("Each", namedExport(() => Promise.resolve().then(() => (init_control_flow(), control_flow_exports)), "Each"));
2292
+ registry.register("TextInput", namedExport(() => Promise.resolve().then(() => (init_input(), input_exports)), "TextInput"));
2293
+ registry.register("Input", namedExport(() => Promise.resolve().then(() => (init_input(), input_exports)), "TextInput"));
2294
+ registry.register("Select", namedExport(() => Promise.resolve().then(() => (init_input(), input_exports)), "Select"));
2295
+ registry.register("Toggle", namedExport(() => Promise.resolve().then(() => (init_input(), input_exports)), "Toggle"));
2296
+ registry.register("Slider", namedExport(() => Promise.resolve().then(() => (init_input(), input_exports)), "Slider"));
2297
+ registry.register("Card", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "Card"));
2298
+ registry.register("Section", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "Section"));
2299
+ registry.register("Tabs", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "Tabs"));
2300
+ registry.register("Accordion", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "Accordion"));
2301
+ registry.register("Modal", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "Modal"));
2302
+ registry.register("Router", namedExport(() => Promise.resolve().then(() => (init_navigation(), navigation_exports)), "Router"));
2303
+ registry.register("Route", namedExport(() => Promise.resolve().then(() => (init_navigation(), navigation_exports)), "Route"));
2304
+ registry.register("NavLink", namedExport(() => Promise.resolve().then(() => (init_navigation(), navigation_exports)), "NavLink"));
2305
+ registry.register("RoleGuard", namedExport(() => Promise.resolve().then(() => (init_navigation(), navigation_exports)), "RoleGuard"));
2306
+ registry.register("Slot", namedExport(() => Promise.resolve().then(() => (init_composition(), composition_exports)), "Slot"));
2307
+ registry.register("ModuleOutlet", namedExport(() => Promise.resolve().then(() => (init_composition(), composition_exports)), "ModuleOutlet"));
2308
+ registry.register("Markdown", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Markdown"));
2309
+ registry.register("ScrollArea", namedExport(() => Promise.resolve().then(() => (init_grouping(), grouping_exports)), "ScrollArea"));
2310
+ registry.register("Table", namedExport(() => Promise.resolve().then(() => (init_data(), data_exports)), "Table"));
2311
+ registry.register("DataGrid", namedExport(() => Promise.resolve().then(() => (init_data(), data_exports)), "DataGrid"));
2312
+ registry.register("Alert", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Alert"));
2313
+ registry.register("EmptyState", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "EmptyState"));
2314
+ registry.register("Progress", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Progress"));
2315
+ registry.register("Separator", namedExport(() => Promise.resolve().then(() => (init_content(), content_exports)), "Separator"));
2316
+ return registry;
2317
+ }
2318
+ function mergeRegistries(...registries) {
2319
+ let merged = new AtomRegistryImpl();
2320
+ for (const r of registries) {
2321
+ merged = merged.merge(r);
2322
+ }
2323
+ return merged;
2324
+ }
2325
+
2326
+ // src/player/theme.ts
2327
+ var DEFAULT_DESIGN_TOKENS = {
2328
+ // Colors
2329
+ "token:primary": "#3182ce",
2330
+ "token:primary-hover": "#2b6cb0",
2331
+ "token:primary-light": "#ebf8ff",
2332
+ "token:secondary": "#718096",
2333
+ "token:secondary-hover": "#4a5568",
2334
+ "token:accent": "#805ad5",
2335
+ "token:success": "#38a169",
2336
+ "token:warning": "#dd6b20",
2337
+ "token:error": "#e53e3e",
2338
+ "token:info": "#3182ce",
2339
+ // Surfaces
2340
+ "token:surface": "#ffffff",
2341
+ "token:surface-hover": "#f7fafc",
2342
+ "token:surface-secondary": "#edf2f7",
2343
+ "token:background": "#f7fafc",
2344
+ "token:card": "#ffffff",
2345
+ "token:overlay": "rgba(0, 0, 0, 0.4)",
2346
+ // Borders
2347
+ "token:border": "#e2e8f0",
2348
+ "token:border-light": "#edf2f7",
2349
+ "token:border-focus": "#3182ce",
2350
+ // Text
2351
+ "token:text": "#1a202c",
2352
+ "token:text-secondary": "#718096",
2353
+ "token:text-muted": "#a0aec0",
2354
+ "token:text-inverse": "#ffffff",
2355
+ "token:text-link": "#3182ce",
2356
+ // Shadows
2357
+ "token:shadow-sm": "0 1px 2px rgba(0, 0, 0, 0.05)",
2358
+ "token:shadow": "0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06)",
2359
+ "token:shadow-md": "0 4px 6px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.06)",
2360
+ "token:shadow-lg": "0 10px 15px rgba(0, 0, 0, 0.1), 0 4px 6px rgba(0, 0, 0, 0.05)",
2361
+ // Spacing
2362
+ "token:spacing-xs": "4px",
2363
+ "token:spacing-sm": "8px",
2364
+ "token:spacing-md": "16px",
2365
+ "token:spacing-lg": "24px",
2366
+ "token:spacing-xl": "32px",
2367
+ // Radius
2368
+ "token:radius-sm": "4px",
2369
+ "token:radius": "6px",
2370
+ "token:radius-md": "8px",
2371
+ "token:radius-lg": "12px",
2372
+ "token:radius-full": "9999px"
2373
+ };
2374
+
2375
+ // src/player/PlayerProvider.tsx
2376
+ var import_jsx_runtime10 = require("react/jsx-runtime");
2377
+ var PlayerContext = (0, import_react11.createContext)(null);
2378
+ function usePlayerContext() {
2379
+ return (0, import_react11.useContext)(PlayerContext);
2380
+ }
2381
+ var ThemeContext = (0, import_react11.createContext)(DEFAULT_DESIGN_TOKENS);
2382
+ function useTheme() {
2383
+ return (0, import_react11.useContext)(ThemeContext);
2384
+ }
2385
+ var PlayerProvider = ({
2386
+ resolver,
2387
+ atomRegistry: userAtomRegistry,
2388
+ auth,
2389
+ router,
2390
+ toast,
2391
+ onEvent,
2392
+ theme: userTheme,
2393
+ children
2394
+ }) => {
2395
+ const atomRegistry = (0, import_react11.useMemo)(
2396
+ () => userAtomRegistry ?? createCoreAtomRegistry(),
2397
+ [userAtomRegistry]
2398
+ );
2399
+ const mergedTheme = (0, import_react11.useMemo)(
2400
+ () => userTheme ? { ...DEFAULT_DESIGN_TOKENS, ...userTheme } : DEFAULT_DESIGN_TOKENS,
2401
+ [userTheme]
2402
+ );
2403
+ const resolverRef = (0, import_react11.useRef)(resolver);
2404
+ resolverRef.current = resolver;
2405
+ (0, import_react11.useEffect)(() => {
2406
+ if (!resolver) return;
2407
+ setQueryResolver({
2408
+ query: async (_slug, params) => {
2409
+ const r = resolverRef.current;
2410
+ if (!r) return { data: [] };
2411
+ const result = await r.query(_slug, {
2412
+ state: params.state,
2413
+ filter: params.filter,
2414
+ limit: params.limit,
2415
+ offset: params.offset,
2416
+ search: params.search,
2417
+ searchFields: params.searchFields,
2418
+ sort: params.sort
2419
+ });
2420
+ return { data: result.data, total: result.total };
2421
+ }
2422
+ });
2423
+ setMutationResolver({
2424
+ create: async (_slug, input) => {
2425
+ const r = resolverRef.current;
2426
+ if (!r) throw new Error("No resolver");
2427
+ return r.create(_slug, input);
2428
+ },
2429
+ update: async (_slug, instanceId, fields) => {
2430
+ const r = resolverRef.current;
2431
+ if (!r) throw new Error("No resolver");
2432
+ await r.update(instanceId, fields);
2433
+ },
2434
+ transition: async (_slug, instanceId, transitionName, input) => {
2435
+ const r = resolverRef.current;
2436
+ if (!r) throw new Error("No resolver");
2437
+ await r.transition(instanceId, transitionName, input);
2438
+ },
2439
+ remove: async (_slug, instanceId) => {
2440
+ const r = resolverRef.current;
2441
+ if (!r) throw new Error("No resolver");
2442
+ await r.remove(instanceId);
2443
+ }
2444
+ });
2445
+ return () => {
2446
+ setQueryResolver(null);
2447
+ setMutationResolver(null);
2448
+ };
2449
+ }, [resolver]);
2450
+ const value = (0, import_react11.useMemo)(() => ({
2451
+ resolver: resolver ?? null,
2452
+ atomRegistry,
2453
+ auth,
2454
+ router,
2455
+ toast,
2456
+ onEvent
2457
+ }), [resolver, atomRegistry, auth, router, toast, onEvent]);
2458
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(PlayerContext.Provider, { value, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ThemeContext.Provider, { value: mergedTheme, children }) });
2459
+ };
2460
+
2461
+ // src/player/ExperienceRenderer.tsx
2462
+ var import_jsx_runtime11 = require("react/jsx-runtime");
2463
+ var NodeErrorBoundary = class extends import_react12.default.Component {
2464
+ constructor(props) {
2465
+ super(props);
2466
+ this.state = { hasError: false };
2467
+ }
2468
+ static getDerivedStateFromError(error) {
2469
+ return { hasError: true, error };
2470
+ }
2471
+ componentDidCatch(error, info) {
2472
+ console.error(`[ExperienceRenderer] Error in node ${this.props.nodeId}:`, error, info);
2473
+ }
2474
+ render() {
2475
+ if (this.state.hasError) {
2476
+ return this.props.fallback ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { padding: 8, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 6, fontSize: 12, color: "#c53030" }, children: [
2477
+ "Error: ",
2478
+ this.state.error?.message ?? "Render failed"
2479
+ ] });
2480
+ }
2481
+ return this.props.children;
2482
+ }
2483
+ };
2484
+ function useDataSources(dataSources, resolver, scope) {
2485
+ const [results, setResults] = (0, import_react12.useState)({});
2486
+ const mountedRef = (0, import_react12.useRef)(true);
2487
+ (0, import_react12.useEffect)(() => {
2488
+ mountedRef.current = true;
2489
+ return () => {
2490
+ mountedRef.current = false;
2491
+ };
2492
+ }, []);
2493
+ (0, import_react12.useEffect)(() => {
2494
+ if (!dataSources?.length || !resolver) return;
2495
+ const loading = {};
2496
+ for (const ds of dataSources) {
2497
+ loading[ds.name] = { loading: true, error: null };
2498
+ }
2499
+ setResults(loading);
2500
+ const fetchAll = async () => {
2501
+ const entries = await Promise.all(
2502
+ dataSources.map(async (ds) => {
2503
+ try {
2504
+ const result = await fetchDataSource(ds, resolver, scope);
2505
+ return [ds.name, result];
2506
+ } catch (err) {
2507
+ return [ds.name, { loading: false, error: err instanceof Error ? err : new Error(String(err)) }];
2508
+ }
2509
+ })
2510
+ );
2511
+ if (mountedRef.current) {
2512
+ setResults(Object.fromEntries(entries));
2513
+ }
2514
+ };
2515
+ fetchAll();
2516
+ }, [dataSources, resolver]);
2517
+ return results;
2518
+ }
2519
+ async function fetchDataSource(ds, resolver, scope) {
2520
+ switch (ds.type) {
2521
+ case "workflow": {
2522
+ const slug = ds.slug ?? "";
2523
+ if (!slug) return { loading: false, error: new Error("workflow dataSource missing slug") };
2524
+ const queryResult = await resolver.query(slug, {
2525
+ state: ds.filter?.current_state,
2526
+ filter: ds.filter,
2527
+ limit: ds.pageSize ?? 20,
2528
+ page: scope.$local?.[ds.pageKey ?? "page"] ?? 1,
2529
+ search: ds.search ? interpolateTemplate(ds.search, scope) : void 0,
2530
+ searchFields: ds.searchFields,
2531
+ sort: ds.sort,
2532
+ facets: ds.facets,
2533
+ entity: ds.entity,
2534
+ includeDefinition: ds.includeDefinition,
2535
+ parentInstanceId: ds.parentInstanceId ? interpolateTemplate(ds.parentInstanceId, scope) : void 0
2536
+ });
2537
+ const result = {
2538
+ instances: queryResult.data,
2539
+ loading: false,
2540
+ error: null
2541
+ };
2542
+ if (queryResult.data.length === 1 && ds.query !== "list") {
2543
+ result.instance = queryResult.data[0];
2544
+ }
2545
+ if (queryResult.definition) result.definition = queryResult.definition;
2546
+ if (queryResult.total != null) {
2547
+ result.pagination = {
2548
+ total: queryResult.total,
2549
+ page: queryResult.page,
2550
+ pageSize: queryResult.pageSize
2551
+ };
2552
+ }
2553
+ if (queryResult.facets) result.facets = queryResult.facets;
2554
+ if (queryResult.aggregates) result.aggregates = queryResult.aggregates;
2555
+ if (ds.autoStart && queryResult.data.length === 0) {
2556
+ try {
2557
+ const id = await resolver.create(slug, ds.initialData);
2558
+ const instance = await resolver.getInstance(id);
2559
+ result.instance = instance;
2560
+ result.instances = [instance];
2561
+ } catch {
2562
+ }
2563
+ }
2564
+ return result;
2565
+ }
2566
+ case "api": {
2567
+ if (!resolver.fetch) return { loading: false, error: new Error("API datasource: resolver.fetch not implemented") };
2568
+ const endpoint = interpolateTemplate(ds.endpoint, scope);
2569
+ const raw = await resolver.fetch(endpoint, {
2570
+ method: ds.method,
2571
+ body: ds.body,
2572
+ headers: ds.headers
2573
+ });
2574
+ const mapped = mapApiResponse(raw, ds.mapping);
2575
+ return { instances: mapped.items, loading: false, error: null, pagination: mapped.pagination };
2576
+ }
2577
+ case "static": {
2578
+ const data = ds.data;
2579
+ if (Array.isArray(data)) {
2580
+ return {
2581
+ instances: data.map((d, i) => ({
2582
+ id: String(d.id ?? i),
2583
+ state: "static",
2584
+ fields: d
2585
+ })),
2586
+ loading: false,
2587
+ error: null
2588
+ };
2589
+ }
2590
+ return {
2591
+ instance: { id: "static", state: "static", fields: data },
2592
+ loading: false,
2593
+ error: null
2594
+ };
2595
+ }
2596
+ case "ref": {
2597
+ const ctx = buildEvalContext(scope);
2598
+ const resolved = evaluateExpression(ds.expression, ctx);
2599
+ if (Array.isArray(resolved)) {
2600
+ return {
2601
+ instances: resolved.map((item, i) => ({
2602
+ id: String(item?.id ?? i),
2603
+ state: String(item?.state ?? "ref"),
2604
+ fields: item && typeof item === "object" ? item : { value: item }
2605
+ })),
2606
+ loading: false,
2607
+ error: null
2608
+ };
2609
+ }
2610
+ if (resolved != null && typeof resolved === "object") {
2611
+ const obj = resolved;
2612
+ return {
2613
+ instance: {
2614
+ id: String(obj.id ?? "ref"),
2615
+ state: String(obj.state ?? "ref"),
2616
+ fields: obj
2617
+ },
2618
+ loading: false,
2619
+ error: null
2620
+ };
2621
+ }
2622
+ return { loading: false, error: null };
2623
+ }
2624
+ default:
2625
+ return { loading: false, error: new Error(`Unknown dataSource type: ${ds.type}`) };
2626
+ }
2627
+ }
2628
+ function interpolateTemplate(template, scope) {
2629
+ return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
2630
+ const val = resolveBinding(`$${path}`, scope) ?? resolveBinding(path, scope);
2631
+ return val != null ? String(val) : "";
2632
+ });
2633
+ }
2634
+ function mapApiResponse(raw, mapping) {
2635
+ if (!raw || typeof raw !== "object") return { items: [] };
2636
+ const obj = raw;
2637
+ let items;
2638
+ if (mapping?.items || mapping?.data) {
2639
+ items = obj[mapping.items ?? mapping.data ?? "data"] ?? [];
2640
+ } else if (Array.isArray(raw)) {
2641
+ items = raw;
2642
+ } else if (Array.isArray(obj.data)) {
2643
+ items = obj.data;
2644
+ } else if (Array.isArray(obj.items)) {
2645
+ items = obj.items;
2646
+ } else {
2647
+ items = [raw];
2648
+ }
2649
+ const result = items.map((item, i) => ({
2650
+ id: String(item?.id ?? i),
2651
+ state: String(item?.state ?? "unknown"),
2652
+ fields: item ?? {}
2653
+ }));
2654
+ let pagination;
2655
+ const total = mapping?.total ? obj[mapping.total] : obj.total;
2656
+ if (total != null) {
2657
+ pagination = { total: Number(total), page: Number(obj.page ?? 1), pageSize: Number(obj.pageSize ?? items.length) };
2658
+ }
2659
+ return { items: result, pagination };
2660
+ }
2661
+ function resolveTokens(value, tokens) {
2662
+ if (typeof value === "string" && value.startsWith("token:")) {
2663
+ return tokens[value] ?? value;
2664
+ }
2665
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2666
+ const resolved = {};
2667
+ for (const [k, v] of Object.entries(value)) {
2668
+ resolved[k] = resolveTokens(v, tokens);
2669
+ }
2670
+ return resolved;
2671
+ }
2672
+ return value;
2673
+ }
2674
+ var NodeRenderer = ({ node, fallback }) => {
2675
+ const parentScope = useScope();
2676
+ const playerCtx = usePlayerContext();
2677
+ const resolver = playerCtx?.resolver ?? null;
2678
+ const atomRegistry = playerCtx?.atomRegistry;
2679
+ const themeTokens = useTheme();
2680
+ const localDefaults = node.config?.localDefaults ?? {};
2681
+ const [localState, setLocalState] = (0, import_react12.useState)(() => ({
2682
+ ...localDefaults
2683
+ }));
2684
+ const handleSetLocal = (0, import_react12.useCallback)((key, value) => {
2685
+ setLocalState((prev) => ({ ...prev, [key]: value }));
2686
+ }, []);
2687
+ const [, setFetchVersion] = (0, import_react12.useState)(0);
2688
+ const handleRefreshQuery = (0, import_react12.useCallback)(() => {
2689
+ setFetchVersion((v) => v + 1);
2690
+ }, []);
2691
+ const dsResults = useDataSources(node.dataSources, resolver, parentScope);
2692
+ const primaryInstance = Object.values(dsResults).find((r) => r.instance)?.instance;
2693
+ const primarySlug = node.dataSources?.find((ds) => ds.type === "workflow")?.slug;
2694
+ const actionScope = (0, import_react12.useMemo)(() => {
2695
+ if (!resolver) {
2696
+ return {
2697
+ transition: async () => {
2698
+ },
2699
+ create: async () => "",
2700
+ update: async () => {
2701
+ },
2702
+ remove: async () => {
2703
+ },
2704
+ setLocal: handleSetLocal,
2705
+ navigate: () => {
2706
+ },
2707
+ toast: () => {
2708
+ },
2709
+ refreshQuery: handleRefreshQuery,
2710
+ scrollTo: () => {
2711
+ },
2712
+ openModal: () => {
2713
+ },
2714
+ closeModal: () => {
2715
+ },
2716
+ emit: () => {
2717
+ }
2718
+ };
2719
+ }
2720
+ return buildActionScope({
2721
+ resolver,
2722
+ instanceId: primaryInstance?.id,
2723
+ slug: primarySlug,
2724
+ setLocal: handleSetLocal,
2725
+ router: playerCtx?.router,
2726
+ toast: playerCtx?.toast,
2727
+ refreshQuery: handleRefreshQuery,
2728
+ onEvent: playerCtx?.onEvent
2729
+ });
2730
+ }, [resolver, primaryInstance?.id, primarySlug, handleSetLocal, handleRefreshQuery, playerCtx]);
2731
+ const scope = (0, import_react12.useMemo)(() => buildScope({
2732
+ dataSources: dsResults,
2733
+ localState,
2734
+ auth: playerCtx?.auth,
2735
+ entity: node.dataSources?.find((ds) => ds.type === "workflow")?.entity,
2736
+ parentScope,
2737
+ actionScope
2738
+ }), [dsResults, localState, parentScope, actionScope, playerCtx?.auth]);
2739
+ const enrichedScope = (0, import_react12.useMemo)(() => {
2740
+ const handleCreate = () => {
2741
+ if (primarySlug && resolver) {
2742
+ resolver.create(primarySlug).then(() => handleRefreshQuery());
2743
+ }
2744
+ };
2745
+ const setSearch = (e) => {
2746
+ const val = typeof e === "object" && e !== null && "target" in e ? e.target.value : String(e ?? "");
2747
+ handleSetLocal("search", val);
2748
+ };
2749
+ const enrichedAction = {
2750
+ ...scope.$action,
2751
+ handleCreate,
2752
+ setSearch
2753
+ };
2754
+ const enrichedInstance = scope.$instance ? { ...scope.$instance, handleCreate, setSearch } : void 0;
2755
+ return {
2756
+ ...scope,
2757
+ $action: enrichedAction,
2758
+ $instance: enrichedInstance,
2759
+ // Also add at top-level for direct access
2760
+ handleCreate,
2761
+ setSearch
2762
+ };
2763
+ }, [scope, primarySlug, resolver, handleRefreshQuery, handleSetLocal]);
2764
+ if (node.visible_when) {
2765
+ const ctx = buildEvalContext(enrichedScope);
2766
+ const visible = evaluateExpression(node.visible_when, ctx);
2767
+ if (!visible) return null;
63
2768
  }
64
- if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
65
- return Number(trimmed);
2769
+ if (node.$if) {
2770
+ const ctx = buildEvalContext(enrichedScope);
2771
+ const visible = evaluateExpression(node.$if, ctx);
2772
+ if (!visible) return null;
2773
+ }
2774
+ const resolvedBindings = node.bindings ? resolveAllBindings(node.bindings, enrichedScope) : {};
2775
+ const config = node.config ?? node.props ?? {};
2776
+ const rawMerged = { ...config, ...resolvedBindings };
2777
+ const mergedProps = {};
2778
+ for (const [k, v] of Object.entries(rawMerged)) {
2779
+ mergedProps[k] = resolveTokens(v, themeTokens);
2780
+ }
2781
+ if (node.className) mergedProps.className = node.className;
2782
+ if (node.id) mergedProps["data-node-id"] = node.id;
2783
+ const loadingAny = Object.values(dsResults).some((r) => r.loading);
2784
+ if (Object.keys(dsResults).length > 0) {
2785
+ mergedProps.loading = loadingAny;
2786
+ const firstResult = Object.values(dsResults)[0];
2787
+ if (firstResult?.instances) mergedProps.data = firstResult.instances;
2788
+ if (firstResult?.instance) mergedProps.instance = firstResult.instance;
2789
+ if (firstResult?.pagination) mergedProps.pagination = firstResult.pagination;
2790
+ if (firstResult?.definition) mergedProps.definition = firstResult.definition;
2791
+ }
2792
+ const componentName = node.component ?? node.type ?? "";
2793
+ let AtomComponent = null;
2794
+ if (atomRegistry) {
2795
+ const lazy = atomRegistry.resolve(componentName);
2796
+ if (lazy) AtomComponent = lazy;
2797
+ }
2798
+ if (!AtomComponent) {
2799
+ if (!componentName && node.children?.length) {
2800
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: node.className, style: node.style, children: node.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeRenderer, { node: child, fallback }) }, child.id ?? i)) }) });
2801
+ }
2802
+ if (componentName) {
2803
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
2804
+ "Unknown: ",
2805
+ componentName
2806
+ ] });
2807
+ }
2808
+ return null;
66
2809
  }
67
- if (trimmed === "true") return true;
68
- if (trimmed === "false") return false;
69
- if (trimmed === "null" || trimmed === "undefined") return void 0;
70
- const flatScope = { ...scopes };
71
- if (scopes.state_data && typeof scopes.state_data === "object") {
72
- Object.assign(flatScope, scopes.state_data);
2810
+ let children = null;
2811
+ if (node.children?.length) {
2812
+ children = node.children.map((child, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeErrorBoundary, { nodeId: child.id, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeRenderer, { node: child, fallback }) }, child.id ?? i));
2813
+ }
2814
+ if (!children && mergedProps.children != null) {
2815
+ children = mergedProps.children;
2816
+ delete mergedProps.children;
73
2817
  }
74
- if (scopes.context && typeof scopes.context === "object") {
75
- Object.assign(flatScope, scopes.context);
2818
+ delete mergedProps.localDefaults;
2819
+ delete mergedProps.dataSources;
2820
+ delete mergedProps.bindings;
2821
+ delete mergedProps.visible_when;
2822
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopeContext.Provider, { value: enrichedScope, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeErrorBoundary, { nodeId: node.id, fallback, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react12.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { padding: 8, color: "#a0aec0", fontSize: 13 }, children: [
2823
+ "Loading ",
2824
+ componentName,
2825
+ "..."
2826
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AtomComponent, { ...mergedProps, children }) }) }) });
2827
+ };
2828
+ var ExperienceRenderer = ({
2829
+ tree,
2830
+ initialScope,
2831
+ entity,
2832
+ fallback,
2833
+ className
2834
+ }) => {
2835
+ const playerCtx = usePlayerContext();
2836
+ const nodes = Array.isArray(tree) ? tree : [tree];
2837
+ const rootScope = (0, import_react12.useMemo)(() => buildScope({
2838
+ auth: playerCtx?.auth ?? initialScope?.auth,
2839
+ entity,
2840
+ localState: initialScope?.$local ?? {},
2841
+ actionScope: initialScope?.$action ?? {
2842
+ transition: async () => {
2843
+ },
2844
+ create: async () => "",
2845
+ update: async () => {
2846
+ },
2847
+ remove: async () => {
2848
+ },
2849
+ setLocal: () => {
2850
+ },
2851
+ navigate: () => {
2852
+ },
2853
+ toast: () => {
2854
+ },
2855
+ refreshQuery: () => {
2856
+ },
2857
+ scrollTo: () => {
2858
+ },
2859
+ openModal: () => {
2860
+ },
2861
+ closeModal: () => {
2862
+ },
2863
+ emit: () => {
2864
+ }
2865
+ }
2866
+ }), [playerCtx?.auth, entity, initialScope]);
2867
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ScopeContext.Provider, { value: rootScope, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className, children: nodes.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeErrorBoundary, { nodeId: node.id, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(NodeRenderer, { node, fallback }) }, node.id ?? i)) }) });
2868
+ };
2869
+
2870
+ // src/player/resolver.ts
2871
+ function getToken(token) {
2872
+ if (!token) return null;
2873
+ if (typeof token === "function") return token();
2874
+ return token;
2875
+ }
2876
+ function normalizeInstance(raw) {
2877
+ return {
2878
+ id: String(raw.id ?? ""),
2879
+ state: String(raw.current_state ?? raw.state ?? "unknown"),
2880
+ fields: raw.state_data ?? raw.fields ?? {},
2881
+ slug: raw.definition_slug,
2882
+ created_at: raw.created_at,
2883
+ updated_at: raw.updated_at,
2884
+ ...raw
2885
+ };
2886
+ }
2887
+ function createApiResolver(config) {
2888
+ const { baseUrl, defaults } = config;
2889
+ const fetchFn = config.fetch ?? globalThis.fetch.bind(globalThis);
2890
+ const defCache = /* @__PURE__ */ new Map();
2891
+ async function apiRequest(path, options = {}) {
2892
+ const tok = getToken(config.token);
2893
+ const headers = {
2894
+ "Content-Type": "application/json",
2895
+ ...options.headers ?? {}
2896
+ };
2897
+ if (tok) headers["Authorization"] = `Bearer ${tok}`;
2898
+ const response = await fetchFn(`${baseUrl}${path}`, {
2899
+ ...options,
2900
+ headers
2901
+ });
2902
+ if (!response.ok) {
2903
+ const body = await response.text().catch(() => "");
2904
+ let message = `API error ${response.status}: ${response.statusText}`;
2905
+ try {
2906
+ const parsed = JSON.parse(body);
2907
+ if (parsed.message) message = parsed.message;
2908
+ if (parsed.error) message = `${parsed.error}: ${parsed.message || ""}`;
2909
+ } catch {
2910
+ }
2911
+ throw new Error(message);
2912
+ }
2913
+ return response.json();
76
2914
  }
77
- return resolvePath(trimmed, flatScope);
2915
+ const resolver = {
2916
+ async query(slug, params) {
2917
+ const searchParams = new URLSearchParams();
2918
+ searchParams.set("definition", slug);
2919
+ if (params.state) {
2920
+ const states = Array.isArray(params.state) ? params.state : [params.state];
2921
+ states.forEach((s) => searchParams.append("state", s));
2922
+ }
2923
+ if (params.status) searchParams.set("status", params.status);
2924
+ if (params.limit ?? defaults?.limit) searchParams.set("limit", String(params.limit ?? defaults?.limit ?? 20));
2925
+ if (params.page) searchParams.set("page", String(params.page));
2926
+ if (params.offset) searchParams.set("offset", String(params.offset));
2927
+ if (params.search) searchParams.set("search", params.search);
2928
+ if (params.searchFields?.length) searchParams.set("search_fields", params.searchFields.join(","));
2929
+ if (params.sort) {
2930
+ if (typeof params.sort === "string") {
2931
+ searchParams.set("sort", params.sort);
2932
+ } else if (Array.isArray(params.sort)) {
2933
+ const sortStr = params.sort.map((s) => `${s.direction === "desc" ? "-" : ""}${s.field}`).join(",");
2934
+ searchParams.set("sort", sortStr);
2935
+ }
2936
+ }
2937
+ if (params.filter) {
2938
+ searchParams.set("state_filter", JSON.stringify(params.filter));
2939
+ }
2940
+ if (params.facets?.length) {
2941
+ searchParams.set("facets", params.facets.join(","));
2942
+ }
2943
+ if (params.entity) {
2944
+ searchParams.set("entity_type", params.entity.type);
2945
+ searchParams.set("entity_id", params.entity.id);
2946
+ }
2947
+ if (params.parentInstanceId) {
2948
+ searchParams.set("spawned_by_instance_id", params.parentInstanceId);
2949
+ }
2950
+ if (params.includeDefinition) {
2951
+ searchParams.set("include_definition", "true");
2952
+ }
2953
+ const raw = await apiRequest(
2954
+ `/workflow/instances?${searchParams.toString()}`
2955
+ );
2956
+ const items = raw.items ?? raw.data ?? [];
2957
+ const total = Number(raw.total ?? raw.count ?? items.length);
2958
+ const page = Number(raw.page ?? params.page ?? 1);
2959
+ const pageSize = Number(raw.page_size ?? raw.pageSize ?? params.limit ?? defaults?.limit ?? 20);
2960
+ const result = {
2961
+ data: items.map(normalizeInstance),
2962
+ total,
2963
+ page,
2964
+ pageSize
2965
+ };
2966
+ if (raw.definition) result.definition = raw.definition;
2967
+ if (raw.facets) result.facets = raw.facets;
2968
+ if (raw.aggregates) result.aggregates = raw.aggregates;
2969
+ if (raw.grouped) result.grouped = raw.grouped;
2970
+ return result;
2971
+ },
2972
+ async getInstance(id) {
2973
+ const raw = await apiRequest(`/workflow/instances/${id}`);
2974
+ return normalizeInstance(raw);
2975
+ },
2976
+ async getDefinition(slug) {
2977
+ const cached = defCache.get(slug);
2978
+ if (cached && cached.expires > Date.now()) return cached.data;
2979
+ const raw = await apiRequest(`/workflow/definitions/slug/${slug}`);
2980
+ defCache.set(slug, { data: raw, expires: Date.now() + 5 * 60 * 1e3 });
2981
+ return raw;
2982
+ },
2983
+ async create(slug, data) {
2984
+ const raw = await apiRequest("/workflow/instances", {
2985
+ method: "POST",
2986
+ body: JSON.stringify({
2987
+ definition_slug: slug,
2988
+ state_data: data ?? {}
2989
+ })
2990
+ });
2991
+ return String(raw.id);
2992
+ },
2993
+ async update(id, fields) {
2994
+ await apiRequest(`/workflow/instances/${id}/state-data`, {
2995
+ method: "PATCH",
2996
+ body: JSON.stringify(fields)
2997
+ });
2998
+ },
2999
+ async transition(id, name, data) {
3000
+ const raw = await apiRequest(
3001
+ `/workflow/instances/${id}/transitions/${name}`,
3002
+ {
3003
+ method: "POST",
3004
+ body: JSON.stringify({ data: data ?? {} })
3005
+ }
3006
+ );
3007
+ return raw;
3008
+ },
3009
+ async remove(id) {
3010
+ await apiRequest(`/workflow/instances/${id}`, { method: "DELETE" });
3011
+ },
3012
+ async availableTransitions(id) {
3013
+ const raw = await apiRequest(`/workflow/instances/${id}/transitions`);
3014
+ return Array.isArray(raw) ? raw : [];
3015
+ },
3016
+ async fetch(endpoint, fetchConfig) {
3017
+ return apiRequest(endpoint, {
3018
+ method: fetchConfig.method ?? "GET",
3019
+ body: fetchConfig.body ? JSON.stringify(fetchConfig.body) : void 0,
3020
+ headers: fetchConfig.headers
3021
+ });
3022
+ }
3023
+ };
3024
+ return resolver;
3025
+ }
3026
+
3027
+ // src/player/index.ts
3028
+ init_expression_engine();
3029
+ init_scope_builder();
3030
+ init_composition();
3031
+ init_navigation();
3032
+
3033
+ // src/player/ComponentTreeRenderer.tsx
3034
+ var import_react13 = __toESM(require("react"));
3035
+ init_expression_engine();
3036
+ var import_jsx_runtime12 = require("react/jsx-runtime");
3037
+ var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
3038
+ function containsExpression(value) {
3039
+ return typeof value === "string" && EXPR_PATTERN.test(value);
78
3040
  }
79
3041
  function evaluateProp(value, scopes) {
80
3042
  if (typeof value !== "string") return value;
81
3043
  const fullMatch = value.match(/^\{\{(.+)\}\}$/s);
82
- if (fullMatch) {
83
- return evaluateExpression(fullMatch[1], scopes);
84
- }
3044
+ if (fullMatch) return evaluateExpression(fullMatch[1], scopes);
85
3045
  if (containsExpression(value)) {
86
3046
  return value.replace(EXPR_PATTERN, (_, expr) => {
87
3047
  const result = evaluateExpression(expr, scopes);
@@ -90,17 +3050,16 @@ function evaluateProp(value, scopes) {
90
3050
  }
91
3051
  return value;
92
3052
  }
93
-
94
- // src/player/ComponentTreeRenderer.tsx
95
- var import_jsx_runtime = require("react/jsx-runtime");
96
- var UnknownAtom = ({ type, children }) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
97
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontWeight: 600 }, children: [
3053
+ var UnknownAtom = ({ type, children }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { border: "1px dashed #e53e3e", borderRadius: 6, padding: "8px 12px", margin: 4, fontSize: 13, color: "#e53e3e", background: "#fff5f5" }, children: [
3054
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("span", { style: { fontWeight: 600 }, children: [
98
3055
  "Unknown: ",
99
3056
  type
100
3057
  ] }),
101
- children && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 4 }, children })
3058
+ children && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { marginTop: 4 }, children })
102
3059
  ] });
103
3060
  var RenderNode = ({ node, scopes, atoms, onEvent }) => {
3061
+ const nodeType = node.type || node.component || "";
3062
+ const nodeProps = node.props || node.config || {};
104
3063
  if (node.$if) {
105
3064
  const condition = evaluateProp(node.$if, scopes);
106
3065
  if (!condition) return null;
@@ -109,7 +3068,7 @@ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
109
3068
  const { each, as, key: keyField } = node.$for;
110
3069
  const items = evaluateProp(each, scopes);
111
3070
  if (!Array.isArray(items)) return null;
112
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: items.map((item, index) => {
3071
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: items.map((item, index) => {
113
3072
  const loopScopes = {
114
3073
  ...scopes,
115
3074
  state_data: {
@@ -120,27 +3079,27 @@ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
120
3079
  };
121
3080
  const nodeWithoutFor = { ...node, $for: void 0 };
122
3081
  const itemKey = keyField ? String(item[keyField] ?? index) : String(index);
123
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RenderNode, { node: nodeWithoutFor, scopes: loopScopes, atoms, onEvent }, itemKey);
3082
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RenderNode, { node: nodeWithoutFor, scopes: loopScopes, atoms, onEvent }, itemKey);
124
3083
  }) });
125
3084
  }
126
- const Component = atoms[node.type];
3085
+ const Component = atoms[nodeType];
127
3086
  if (!Component) {
128
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnknownAtom, { type: node.type });
3087
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(UnknownAtom, { type: nodeType });
129
3088
  }
130
3089
  const evaluatedProps = {};
131
- if (node.props) {
132
- for (const [key, value] of Object.entries(node.props)) {
133
- if (key.startsWith("on") && typeof value === "string") {
134
- evaluatedProps[key] = (...args) => {
135
- if (containsExpression(value)) {
136
- evaluateExpression(value.replace(/^\{\{|\}\}$/g, ""), scopes);
137
- } else {
138
- onEvent(value, args[0]);
139
- }
140
- };
141
- } else {
142
- evaluatedProps[key] = evaluateProp(value, scopes);
143
- }
3090
+ if (node.className) evaluatedProps.className = node.className;
3091
+ if (node.id) evaluatedProps["data-node-id"] = node.id;
3092
+ for (const [key, value] of Object.entries(nodeProps)) {
3093
+ if (key.startsWith("on") && typeof value === "string") {
3094
+ evaluatedProps[key] = (...args) => {
3095
+ if (containsExpression(value)) {
3096
+ evaluateExpression(value.replace(/^\{\{|\}\}$/g, ""), scopes);
3097
+ } else {
3098
+ onEvent(value, args[0]);
3099
+ }
3100
+ };
3101
+ } else {
3102
+ evaluatedProps[key] = evaluateProp(value, scopes);
144
3103
  }
145
3104
  }
146
3105
  let children = null;
@@ -148,12 +3107,12 @@ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
148
3107
  if (typeof node.children === "string") {
149
3108
  children = evaluateProp(node.children, scopes);
150
3109
  } else if (Array.isArray(node.children)) {
151
- children = node.children.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RenderNode, { node: child, scopes, atoms, onEvent }, index));
3110
+ children = node.children.map((child, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RenderNode, { node: child, scopes, atoms, onEvent }, child.id || index));
152
3111
  }
153
3112
  }
154
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...evaluatedProps, children });
3113
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(Component, { ...evaluatedProps, children });
155
3114
  };
156
- var CTRErrorBoundary = class extends import_react.default.Component {
3115
+ var CTRErrorBoundary = class extends import_react13.default.Component {
157
3116
  constructor(props) {
158
3117
  super(props);
159
3118
  this.state = { hasError: false };
@@ -166,9 +3125,9 @@ var CTRErrorBoundary = class extends import_react.default.Component {
166
3125
  }
167
3126
  render() {
168
3127
  if (this.state.hasError) {
169
- return this.props.fallback || /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: 16, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 8 }, children: [
170
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { style: { color: "#c53030" }, children: "Rendering Error" }),
171
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { color: "#e53e3e", fontSize: 14, marginTop: 4 }, children: this.state.error?.message || "An error occurred while rendering" })
3128
+ return this.props.fallback || /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { padding: 16, background: "#fff5f5", border: "1px solid #fed7d7", borderRadius: 8 }, children: [
3129
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("strong", { style: { color: "#c53030" }, children: "Rendering Error" }),
3130
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { style: { color: "#e53e3e", fontSize: 14, marginTop: 4 }, children: this.state.error?.message || "An error occurred while rendering" })
172
3131
  ] });
173
3132
  }
174
3133
  return this.props.children;
@@ -182,43 +3141,44 @@ var ComponentTreeRenderer = ({
182
3141
  },
183
3142
  fallback
184
3143
  }) => {
185
- const allAtoms = (0, import_react.useMemo)(() => ({ ...atoms }), [atoms]);
186
- const handleEvent = (0, import_react.useCallback)(
3144
+ const allAtoms = (0, import_react13.useMemo)(() => ({ ...atoms }), [atoms]);
3145
+ const handleEvent = (0, import_react13.useCallback)(
187
3146
  (eventName, payload) => onEvent(eventName, payload),
188
3147
  [onEvent]
189
3148
  );
190
3149
  const nodes = Array.isArray(tree) ? tree : [tree];
191
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(CTRErrorBoundary, { fallback, children: nodes.map((node, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(RenderNode, { node, scopes, atoms: allAtoms, onEvent: handleEvent }, index)) });
3150
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(CTRErrorBoundary, { fallback, children: nodes.map((node, index) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RenderNode, { node, scopes, atoms: allAtoms, onEvent: handleEvent }, index)) });
192
3151
  };
193
3152
 
194
3153
  // src/player/DevPlayer.tsx
195
- var import_react2 = require("react");
3154
+ var import_react15 = require("react");
196
3155
 
197
3156
  // src/player/builtin-atoms.tsx
198
- var import_jsx_runtime2 = require("react/jsx-runtime");
199
- var Stack = ({ children, gap = 8, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, ...rest, children });
200
- var Row = ({ children, gap = 8, align, justify, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", flexDirection: "row", gap, alignItems: align, justifyContent: justify, ...style }, ...rest, children });
201
- var Column = ({ children, span, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { flex: span ? `0 0 ${Number(span) / 12 * 100}%` : 1, ...style }, ...rest, children });
202
- var Grid = ({ children, columns = 2, gap = 8, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap, ...style }, ...rest, children });
203
- var Divider = ({ style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "8px 0", ...style } });
204
- var Spacer = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { height: size, flexShrink: 0 } });
205
- var Text = ({ children, size, weight, color, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontSize: size, fontWeight: weight, color, ...style }, ...rest, children });
206
- var Heading = ({ children, level = 2, style, ...rest }) => {
3157
+ var import_react14 = __toESM(require("react"));
3158
+ var import_jsx_runtime13 = require("react/jsx-runtime");
3159
+ var Stack2 = ({ children, gap = 8, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", flexDirection: "column", gap, ...style }, ...rest, children });
3160
+ var Row2 = ({ children, gap = 8, align, justify, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", flexDirection: "row", gap, alignItems: align, justifyContent: justify, ...style }, ...rest, children });
3161
+ var Column2 = ({ children, span, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flex: span ? `0 0 ${Number(span) / 12 * 100}%` : 1, ...style }, ...rest, children });
3162
+ var Grid2 = ({ children, columns = 2, gap = 8, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "grid", gridTemplateColumns: `repeat(${columns}, 1fr)`, gap, ...style }, ...rest, children });
3163
+ var Divider2 = ({ style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("hr", { style: { border: "none", borderTop: "1px solid #e2e8f0", margin: "8px 0", ...style } });
3164
+ var Spacer2 = ({ size = 16 }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { height: size, flexShrink: 0 } });
3165
+ var Text2 = ({ children, size, weight, color, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { fontSize: size, fontWeight: weight, color, ...style }, ...rest, children });
3166
+ var Heading2 = ({ children, level = 2, style, ...rest }) => {
207
3167
  const lvl = Math.min(Math.max(Number(level), 1), 6);
208
3168
  const s = { margin: "0 0 8px", ...style };
209
3169
  const c = children;
210
- if (lvl === 1) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h1", { style: s, ...rest, children: c });
211
- if (lvl === 2) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: s, ...rest, children: c });
212
- if (lvl === 3) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: s, ...rest, children: c });
213
- if (lvl === 4) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h4", { style: s, ...rest, children: c });
214
- if (lvl === 5) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h5", { style: s, ...rest, children: c });
215
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h6", { style: s, ...rest, children: c });
3170
+ if (lvl === 1) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h1", { style: s, ...rest, children: c });
3171
+ if (lvl === 2) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h2", { style: s, ...rest, children: c });
3172
+ if (lvl === 3) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { style: s, ...rest, children: c });
3173
+ if (lvl === 4) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h4", { style: s, ...rest, children: c });
3174
+ if (lvl === 5) return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h5", { style: s, ...rest, children: c });
3175
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h6", { style: s, ...rest, children: c });
216
3176
  };
217
- var Field = ({ label, value, children, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 8, ...style }, children: [
218
- label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
219
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 14 }, children: children ?? value ?? "\u2014" })
3177
+ var Field2 = ({ label, value, children, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginBottom: 8, ...style }, children: [
3178
+ label ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
3179
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontSize: 14 }, children: children ?? value ?? "\u2014" })
220
3180
  ] });
221
- var Badge = ({ children, variant = "default", style }) => {
3181
+ var Badge2 = ({ children, variant = "default", style }) => {
222
3182
  const colors = {
223
3183
  default: { bg: "#edf2f7", fg: "#4a5568" },
224
3184
  success: { bg: "#c6f6d5", fg: "#276749" },
@@ -227,10 +3187,10 @@ var Badge = ({ children, variant = "default", style }) => {
227
3187
  info: { bg: "#bee3f8", fg: "#2a4365" }
228
3188
  };
229
3189
  const c = colors[variant] ?? colors.default;
230
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { display: "inline-block", padding: "2px 8px", borderRadius: 9999, fontSize: 12, fontWeight: 500, background: c.bg, color: c.fg, ...style }, children });
3190
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { display: "inline-block", padding: "2px 8px", borderRadius: 9999, fontSize: 12, fontWeight: 500, background: c.bg, color: c.fg, ...style }, children });
231
3191
  };
232
- var ImageAtom = ({ src, alt, width, height, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("img", { src, alt: alt ?? "", width, height, style: { maxWidth: "100%", ...style }, ...rest });
233
- var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest }) => {
3192
+ var ImageAtom = ({ src, alt, width, height, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("img", { src, alt: alt ?? "", width, height, style: { maxWidth: "100%", ...style }, ...rest });
3193
+ var Button2 = ({ children, onClick, variant = "primary", disabled, style, ...rest }) => {
234
3194
  const styles = {
235
3195
  primary: { background: "#3182ce", color: "#fff", border: "none" },
236
3196
  secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
@@ -238,7 +3198,7 @@ var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest
238
3198
  ghost: { background: "transparent", color: "#4a5568", border: "none" }
239
3199
  };
240
3200
  const base = styles[variant] ?? styles.primary;
241
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
3201
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
242
3202
  "button",
243
3203
  {
244
3204
  onClick,
@@ -249,78 +3209,202 @@ var Button = ({ children, onClick, variant = "primary", disabled, style, ...rest
249
3209
  }
250
3210
  );
251
3211
  };
252
- var LinkAtom = ({ children, href, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("a", { href, style: { color: "#3182ce", textDecoration: "underline", ...style }, ...rest, children });
253
- var TextInput = ({ value, onChange, placeholder, label, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 8 }, children: [
254
- label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
255
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
256
- "input",
257
- {
258
- type: "text",
259
- value: value ?? "",
260
- onChange,
261
- placeholder,
262
- style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
263
- ...rest
264
- }
265
- )
266
- ] });
267
- var SelectAtom = ({ value, onChange, options, label, placeholder, style }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: 8 }, children: [
268
- label ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
269
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
3212
+ var LinkAtom = ({ children, href, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("a", { href, style: { color: "#3182ce", textDecoration: "underline", ...style }, ...rest, children });
3213
+ var TextInput2 = ({ value, onChange, placeholder, label, bind: _bind, style }) => {
3214
+ const isControlled = typeof onChange === "function";
3215
+ const [localValue, setLocalValue] = import_react14.default.useState(value ?? "");
3216
+ const handleChange = (e) => {
3217
+ setLocalValue(e.target.value);
3218
+ if (typeof onChange === "function") onChange(e);
3219
+ };
3220
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginBottom: 8 }, children: [
3221
+ label ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
3222
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3223
+ "input",
3224
+ {
3225
+ type: "text",
3226
+ value: isControlled ? value ?? "" : localValue,
3227
+ onChange: handleChange,
3228
+ placeholder,
3229
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style }
3230
+ }
3231
+ )
3232
+ ] });
3233
+ };
3234
+ var SelectAtom = ({ value, onChange, options, label, placeholder, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { marginBottom: 8 }, children: [
3235
+ label ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("label", { style: { display: "block", fontSize: 12, color: "#718096", marginBottom: 2 }, children: label }) : null,
3236
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
270
3237
  "select",
271
3238
  {
272
3239
  value: value ?? "",
273
3240
  onChange,
274
3241
  style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
275
3242
  children: [
276
- placeholder ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: placeholder }) : null,
3243
+ placeholder ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: "", children: placeholder }) : null,
277
3244
  Array.isArray(options) && options.map((opt) => {
278
3245
  const v = typeof opt === "string" ? opt : opt.value;
279
3246
  const l = typeof opt === "string" ? opt : opt.label;
280
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: v, children: l }, v);
3247
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("option", { value: v, children: l }, v);
281
3248
  })
282
3249
  ]
283
3250
  }
284
3251
  )
285
3252
  ] });
286
- var Card = ({ children, title, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { border: "1px solid #e2e8f0", borderRadius: 8, padding: 16, background: "#fff", ...style }, ...rest, children: [
287
- title ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: 12 }, children: title }) : null,
3253
+ var Card2 = ({ children, title, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { border: "1px solid #e2e8f0", borderRadius: 8, padding: 16, background: "#fff", ...style }, ...rest, children: [
3254
+ title ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, fontSize: 16, marginBottom: 12 }, children: title }) : null,
288
3255
  children
289
3256
  ] });
290
- var Section = ({ children, title, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { style: { marginBottom: 24, ...style }, ...rest, children: [
291
- title ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { style: { fontSize: 18, fontWeight: 600, marginBottom: 8 }, children: title }) : null,
3257
+ var Section2 = ({ children, title, style, ...rest }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("section", { style: { marginBottom: 24, ...style }, ...rest, children: [
3258
+ title ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("h3", { style: { fontSize: 18, fontWeight: 600, marginBottom: 8 }, children: title }) : null,
292
3259
  children
293
3260
  ] });
294
- var Show = ({ when, children, fallback }) => when ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: fallback ?? null });
295
- var Each = ({ items, children, renderItem }) => {
3261
+ var Show2 = ({ when, children, fallback }) => when ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children }) : /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: fallback ?? null });
3262
+ var Each2 = ({ items, children, renderItem }) => {
296
3263
  if (!Array.isArray(items)) return null;
297
- if (typeof renderItem === "function") return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: items.map((item, i) => renderItem(item, i)) });
298
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children });
3264
+ if (typeof renderItem === "function") return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: items.map((item, i) => renderItem(item, i)) });
3265
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children });
3266
+ };
3267
+ var RouterContext = import_react14.default.createContext({ path: "/", navigate: () => {
3268
+ } });
3269
+ var Router2 = ({ children, basePath, className, style, ...rest }) => {
3270
+ const [path, setPath] = import_react14.default.useState("/");
3271
+ const navigate = import_react14.default.useCallback((to) => setPath(to), []);
3272
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RouterContext.Provider, { value: { path, navigate }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className, style, ...rest, children }) });
3273
+ };
3274
+ var Route2 = ({ children, path, exact, fallback: _fallback, className, style }) => {
3275
+ const { path: currentPath } = import_react14.default.useContext(RouterContext);
3276
+ const routePath = path || "/";
3277
+ const isExact = exact !== false;
3278
+ const matches = isExact ? currentPath === routePath || routePath === "/" && currentPath === "/" : currentPath.startsWith(routePath);
3279
+ if (!matches) return null;
3280
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className, style, children });
3281
+ };
3282
+ var NavLink2 = ({ children, to, label, icon, className, style, ...rest }) => {
3283
+ const { path, navigate } = import_react14.default.useContext(RouterContext);
3284
+ const target = to || "/";
3285
+ const isActive = path === target;
3286
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3287
+ "button",
3288
+ {
3289
+ onClick: () => navigate(target),
3290
+ className,
3291
+ style: {
3292
+ background: isActive ? "#edf2f7" : "transparent",
3293
+ border: "none",
3294
+ borderRadius: 4,
3295
+ padding: "4px 12px",
3296
+ fontSize: 13,
3297
+ cursor: "pointer",
3298
+ fontWeight: isActive ? 600 : 400,
3299
+ color: isActive ? "#2d3748" : "#718096",
3300
+ ...style
3301
+ },
3302
+ ...rest,
3303
+ children: children || label || target
3304
+ }
3305
+ );
3306
+ };
3307
+ var RoleGuard2 = ({ children, role: _role, fallback: _fallback }) => {
3308
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children });
3309
+ };
3310
+ var Icon2 = ({ name, size = 16, color, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("span", { style: { display: "inline-flex", alignItems: "center", justifyContent: "center", width: size, height: size, fontSize: size, color, ...style }, title: name, children: iconGlyphs[name] || "\u25A1" });
3311
+ var iconGlyphs = {
3312
+ home: "\u2302",
3313
+ settings: "\u2699",
3314
+ plus: "+",
3315
+ search: "\u{1F50D}",
3316
+ box: "\u25A1",
3317
+ inbox: "\u2709",
3318
+ chevronRight: "\u203A",
3319
+ chevronLeft: "\u2039",
3320
+ x: "\u2715",
3321
+ check: "\u2713",
3322
+ edit: "\u270E",
3323
+ trash: "\u{1F5D1}",
3324
+ star: "\u2605",
3325
+ heart: "\u2665",
3326
+ user: "\u{1F464}",
3327
+ menu: "\u2630",
3328
+ close: "\u2715",
3329
+ arrow_right: "\u2192",
3330
+ arrow_left: "\u2190"
3331
+ };
3332
+ var Tabs2 = ({ children, tabs, defaultTab, style }) => {
3333
+ const tabList = tabs || [];
3334
+ const [active, setActive] = import_react14.default.useState(defaultTab || tabList[0]?.id || "");
3335
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style, children: [
3336
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { display: "flex", borderBottom: "1px solid #e2e8f0", marginBottom: 12 }, children: tabList.map((t) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
3337
+ "button",
3338
+ {
3339
+ onClick: () => setActive(t.id),
3340
+ 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" },
3341
+ children: t.label
3342
+ },
3343
+ t.id
3344
+ )) }),
3345
+ children
3346
+ ] });
3347
+ };
3348
+ var Accordion2 = ({ children, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style, children });
3349
+ var Modal2 = ({ children, open, title, onClose: _onClose, style }) => {
3350
+ if (!open) return null;
3351
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { position: "fixed", inset: 0, background: "rgba(0,0,0,0.5)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1e3 }, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { style: { background: "#fff", borderRadius: 12, padding: 24, maxWidth: 480, width: "100%", ...style }, children: [
3352
+ title ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { fontWeight: 600, fontSize: 18, marginBottom: 16 }, children: String(title) }) : null,
3353
+ children
3354
+ ] }) });
299
3355
  };
3356
+ var Markdown2 = ({ content, children, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { lineHeight: 1.6, ...style }, children: content || children });
3357
+ var ScrollArea2 = ({ children, maxHeight = 400, style }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { overflow: "auto", maxHeight, ...style }, children });
3358
+ var Slot2 = ({ children, fallback }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_jsx_runtime13.Fragment, { children: children || fallback || null });
3359
+ var ModuleOutlet2 = ({ children, module: moduleName, fallback }) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { "data-module": moduleName, children: children || fallback || /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { style: { color: "#a0aec0", fontSize: 13 }, children: [
3360
+ "Module: ",
3361
+ moduleName
3362
+ ] }) });
300
3363
  var builtinAtoms = {
301
- Stack,
302
- Row,
303
- Column,
304
- Grid,
305
- Divider,
306
- Spacer,
307
- Text,
308
- Heading,
309
- Field,
310
- Badge,
3364
+ // Layout
3365
+ Stack: Stack2,
3366
+ Row: Row2,
3367
+ Column: Column2,
3368
+ Grid: Grid2,
3369
+ Divider: Divider2,
3370
+ Spacer: Spacer2,
3371
+ // Typography
3372
+ Text: Text2,
3373
+ Heading: Heading2,
3374
+ Field: Field2,
3375
+ Badge: Badge2,
311
3376
  Image: ImageAtom,
312
- Button,
3377
+ Icon: Icon2,
3378
+ // Interactive
3379
+ Button: Button2,
313
3380
  Link: LinkAtom,
314
- TextInput,
3381
+ // Form
3382
+ TextInput: TextInput2,
315
3383
  Select: SelectAtom,
316
- Card,
317
- Section,
318
- Show,
319
- Each
3384
+ // Containers
3385
+ Card: Card2,
3386
+ Section: Section2,
3387
+ Tabs: Tabs2,
3388
+ Accordion: Accordion2,
3389
+ Modal: Modal2,
3390
+ // Content
3391
+ Markdown: Markdown2,
3392
+ ScrollArea: ScrollArea2,
3393
+ // Control Flow
3394
+ Show: Show2,
3395
+ Each: Each2,
3396
+ // Routing
3397
+ Router: Router2,
3398
+ Route: Route2,
3399
+ NavLink: NavLink2,
3400
+ RoleGuard: RoleGuard2,
3401
+ // Composition
3402
+ Slot: Slot2,
3403
+ ModuleOutlet: ModuleOutlet2
320
3404
  };
321
3405
 
322
3406
  // src/player/DevPlayer.tsx
323
- var import_jsx_runtime3 = require("react/jsx-runtime");
3407
+ var import_jsx_runtime14 = require("react/jsx-runtime");
324
3408
  var S = {
325
3409
  shell: {
326
3410
  display: "flex",
@@ -415,9 +3499,9 @@ var S = {
415
3499
  })
416
3500
  };
417
3501
  function useDevSocket(wsUrl, onReload) {
418
- const [connected, setConnected] = (0, import_react2.useState)(false);
419
- const wsRef = (0, import_react2.useRef)(null);
420
- (0, import_react2.useEffect)(() => {
3502
+ const [connected, setConnected] = (0, import_react15.useState)(false);
3503
+ const wsRef = (0, import_react15.useRef)(null);
3504
+ (0, import_react15.useEffect)(() => {
421
3505
  if (typeof window === "undefined") return;
422
3506
  const url = wsUrl ?? `ws://${window.location.host}/__mm_dev`;
423
3507
  let ws;
@@ -463,15 +3547,15 @@ var DevPlayer = ({
463
3547
  onReload,
464
3548
  onEvent: externalOnEvent
465
3549
  }) => {
466
- const [showSidebar, setShowSidebar] = (0, import_react2.useState)(true);
467
- const [events, setEvents] = (0, import_react2.useState)([]);
468
- const nextId = (0, import_react2.useRef)(0);
3550
+ const [showSidebar, setShowSidebar] = (0, import_react15.useState)(true);
3551
+ const [events, setEvents] = (0, import_react15.useState)([]);
3552
+ const nextId = (0, import_react15.useRef)(0);
469
3553
  const connected = useDevSocket(wsUrl, onReload);
470
- const mergedAtoms = (0, import_react2.useMemo)(
3554
+ const mergedAtoms = (0, import_react15.useMemo)(
471
3555
  () => ({ ...builtinAtoms, ...userAtoms }),
472
3556
  [userAtoms]
473
3557
  );
474
- const handleEvent = (0, import_react2.useCallback)(
3558
+ const handleEvent = (0, import_react15.useCallback)(
475
3559
  (name, payload) => {
476
3560
  setEvents((prev) => {
477
3561
  const entry = {
@@ -488,7 +3572,7 @@ var DevPlayer = ({
488
3572
  [externalOnEvent]
489
3573
  );
490
3574
  if (bare) {
491
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3575
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
492
3576
  ComponentTreeRenderer,
493
3577
  {
494
3578
  tree,
@@ -498,21 +3582,21 @@ var DevPlayer = ({
498
3582
  }
499
3583
  );
500
3584
  }
501
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.shell, children: [
502
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.toolbar, children: [
503
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.dot(connected), title: connected ? "HMR connected" : "HMR disconnected" }),
504
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.toolbarTitle, children: title }),
505
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: S.toolbarBadge, children: [
3585
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.shell, children: [
3586
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.toolbar, children: [
3587
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.dot(connected), title: connected ? "HMR connected" : "HMR disconnected" }),
3588
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.toolbarTitle, children: title }),
3589
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { style: S.toolbarBadge, children: [
506
3590
  Array.isArray(tree) ? tree.length : 1,
507
3591
  " node",
508
3592
  Array.isArray(tree) && tree.length !== 1 ? "s" : ""
509
3593
  ] }),
510
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: S.toolbarBadge, children: [
3594
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("span", { style: S.toolbarBadge, children: [
511
3595
  Object.keys(mergedAtoms).length,
512
3596
  " atoms"
513
3597
  ] }),
514
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 } }),
515
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3598
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { flex: 1 } }),
3599
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
516
3600
  "button",
517
3601
  {
518
3602
  style: { ...S.toolbarBtn, ...showSidebar ? S.toolbarBtnActive : {} },
@@ -521,8 +3605,8 @@ var DevPlayer = ({
521
3605
  }
522
3606
  )
523
3607
  ] }),
524
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.body, children: [
525
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.preview, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3608
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.body, children: [
3609
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.preview, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
526
3610
  ComponentTreeRenderer,
527
3611
  {
528
3612
  tree,
@@ -531,18 +3615,18 @@ var DevPlayer = ({
531
3615
  onEvent: handleEvent
532
3616
  }
533
3617
  ) }),
534
- showSidebar && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebar, children: [
535
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarSection, children: [
536
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.sidebarHeading, children: "Scopes" }),
537
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { style: S.pre, children: JSON.stringify(scopes, null, 2) })
3618
+ showSidebar && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebar, children: [
3619
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarSection, children: [
3620
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.sidebarHeading, children: "Scopes" }),
3621
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { style: S.pre, children: JSON.stringify(scopes, null, 2) })
538
3622
  ] }),
539
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarSection, children: [
540
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarHeading, children: [
3623
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarSection, children: [
3624
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarHeading, children: [
541
3625
  "Atoms (",
542
3626
  Object.keys(mergedAtoms).length,
543
3627
  ")"
544
3628
  ] }),
545
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(mergedAtoms).sort().map((name) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3629
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 4 }, children: Object.keys(mergedAtoms).sort().map((name) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
546
3630
  "span",
547
3631
  {
548
3632
  style: {
@@ -560,14 +3644,14 @@ var DevPlayer = ({
560
3644
  name
561
3645
  )) })
562
3646
  ] }),
563
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarSection, children: [
564
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
565
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarHeading, children: [
3647
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarSection, children: [
3648
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 8 }, children: [
3649
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarHeading, children: [
566
3650
  "Events (",
567
3651
  events.length,
568
3652
  ")"
569
3653
  ] }),
570
- events.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
3654
+ events.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
571
3655
  "button",
572
3656
  {
573
3657
  style: { background: "none", border: "none", color: "#a0aec0", fontSize: 11, cursor: "pointer" },
@@ -576,16 +3660,16 @@ var DevPlayer = ({
576
3660
  }
577
3661
  )
578
3662
  ] }),
579
- events.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { color: "#a0aec0", fontSize: 12, fontStyle: "italic" }, children: "No events yet" }),
580
- events.slice(0, 50).map((e) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.eventRow, children: [
581
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.eventTime, children: e.time }),
582
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: S.eventName, children: e.name }),
583
- e.payload !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#718096", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: JSON.stringify(e.payload) })
3663
+ events.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { color: "#a0aec0", fontSize: 12, fontStyle: "italic" }, children: "No events yet" }),
3664
+ events.slice(0, 50).map((e) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.eventRow, children: [
3665
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.eventTime, children: e.time }),
3666
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: S.eventName, children: e.name }),
3667
+ e.payload !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { style: { color: "#718096", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: JSON.stringify(e.payload) })
584
3668
  ] }, e.id))
585
3669
  ] }),
586
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarSection, children: [
587
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: S.sidebarHeading, children: "Tree (JSON)" }),
588
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { style: { ...S.pre, maxHeight: 400 }, children: JSON.stringify(tree, null, 2) })
3670
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { style: S.sidebarSection, children: [
3671
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: S.sidebarHeading, children: "Tree (JSON)" }),
3672
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("pre", { style: { ...S.pre, maxHeight: 400 }, children: JSON.stringify(tree, null, 2) })
589
3673
  ] })
590
3674
  ] })
591
3675
  ] })
@@ -593,10 +3677,32 @@ var DevPlayer = ({
593
3677
  };
594
3678
  // Annotate the CommonJS export names for ESM import in node:
595
3679
  0 && (module.exports = {
3680
+ AtomRegistryImpl,
596
3681
  ComponentTreeRenderer,
3682
+ DEFAULT_DESIGN_TOKENS,
597
3683
  DevPlayer,
3684
+ ExperienceRenderer,
3685
+ PlayerProvider,
3686
+ ScopeContext,
3687
+ SlotRegistryProvider,
3688
+ buildActionScope,
3689
+ buildEvalContext,
3690
+ buildLoopScope,
3691
+ buildScope,
598
3692
  builtinAtoms,
599
- containsExpression,
3693
+ builtinFunctions,
3694
+ classifyBinding,
3695
+ createApiResolver,
3696
+ createCoreAtomRegistry,
600
3697
  evaluateExpression,
601
- evaluateProp
3698
+ mergeRegistries,
3699
+ mergeScope,
3700
+ resolveAllBindings,
3701
+ resolveBinding,
3702
+ setWasmModule,
3703
+ usePlayerContext,
3704
+ usePlayerRouter,
3705
+ useScope,
3706
+ useSlotContributions,
3707
+ useTheme
602
3708
  });