@mmapp/react 0.1.0-alpha.15 → 0.1.0-alpha.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,602 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/player/index.ts
31
+ var player_exports = {};
32
+ __export(player_exports, {
33
+ ComponentTreeRenderer: () => ComponentTreeRenderer,
34
+ DevPlayer: () => DevPlayer,
35
+ builtinAtoms: () => builtinAtoms,
36
+ containsExpression: () => containsExpression,
37
+ evaluateExpression: () => evaluateExpression,
38
+ evaluateProp: () => evaluateProp
39
+ });
40
+ module.exports = __toCommonJS(player_exports);
41
+
42
+ // src/player/ComponentTreeRenderer.tsx
43
+ var import_react = __toESM(require("react"));
44
+
45
+ // src/player/evaluator.ts
46
+ var EXPR_PATTERN = /\{\{(.+?)\}\}/g;
47
+ function containsExpression(value) {
48
+ return typeof value === "string" && EXPR_PATTERN.test(value);
49
+ }
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];
56
+ }
57
+ return current;
58
+ }
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);
63
+ }
64
+ if (/^-?\d+(\.\d+)?$/.test(trimmed)) {
65
+ return Number(trimmed);
66
+ }
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);
73
+ }
74
+ if (scopes.context && typeof scopes.context === "object") {
75
+ Object.assign(flatScope, scopes.context);
76
+ }
77
+ return resolvePath(trimmed, flatScope);
78
+ }
79
+ function evaluateProp(value, scopes) {
80
+ if (typeof value !== "string") return value;
81
+ const fullMatch = value.match(/^\{\{(.+)\}\}$/s);
82
+ if (fullMatch) {
83
+ return evaluateExpression(fullMatch[1], scopes);
84
+ }
85
+ if (containsExpression(value)) {
86
+ return value.replace(EXPR_PATTERN, (_, expr) => {
87
+ const result = evaluateExpression(expr, scopes);
88
+ return result == null ? "" : String(result);
89
+ });
90
+ }
91
+ return value;
92
+ }
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: [
98
+ "Unknown: ",
99
+ type
100
+ ] }),
101
+ children && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 4 }, children })
102
+ ] });
103
+ var RenderNode = ({ node, scopes, atoms, onEvent }) => {
104
+ if (node.$if) {
105
+ const condition = evaluateProp(node.$if, scopes);
106
+ if (!condition) return null;
107
+ }
108
+ if (node.$for) {
109
+ const { each, as, key: keyField } = node.$for;
110
+ const items = evaluateProp(each, scopes);
111
+ if (!Array.isArray(items)) return null;
112
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: items.map((item, index) => {
113
+ const loopScopes = {
114
+ ...scopes,
115
+ state_data: {
116
+ ...scopes.state_data ?? {},
117
+ [as]: item,
118
+ [`${as}Index`]: index
119
+ }
120
+ };
121
+ const nodeWithoutFor = { ...node, $for: void 0 };
122
+ 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);
124
+ }) });
125
+ }
126
+ const Component = atoms[node.type];
127
+ if (!Component) {
128
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(UnknownAtom, { type: node.type });
129
+ }
130
+ 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
+ }
144
+ }
145
+ }
146
+ let children = null;
147
+ if (node.children) {
148
+ if (typeof node.children === "string") {
149
+ children = evaluateProp(node.children, scopes);
150
+ } 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));
152
+ }
153
+ }
154
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Component, { ...evaluatedProps, children });
155
+ };
156
+ var CTRErrorBoundary = class extends import_react.default.Component {
157
+ constructor(props) {
158
+ super(props);
159
+ this.state = { hasError: false };
160
+ }
161
+ static getDerivedStateFromError(error) {
162
+ return { hasError: true, error };
163
+ }
164
+ componentDidCatch(error, errorInfo) {
165
+ console.error("CTR rendering error:", error, errorInfo);
166
+ }
167
+ render() {
168
+ 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" })
172
+ ] });
173
+ }
174
+ return this.props.children;
175
+ }
176
+ };
177
+ var ComponentTreeRenderer = ({
178
+ tree,
179
+ scopes,
180
+ atoms = {},
181
+ onEvent = () => {
182
+ },
183
+ fallback
184
+ }) => {
185
+ const allAtoms = (0, import_react.useMemo)(() => ({ ...atoms }), [atoms]);
186
+ const handleEvent = (0, import_react.useCallback)(
187
+ (eventName, payload) => onEvent(eventName, payload),
188
+ [onEvent]
189
+ );
190
+ 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)) });
192
+ };
193
+
194
+ // src/player/DevPlayer.tsx
195
+ var import_react2 = require("react");
196
+
197
+ // 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 }) => {
207
+ const lvl = Math.min(Math.max(Number(level), 1), 6);
208
+ const s = { margin: "0 0 8px", ...style };
209
+ 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 });
216
+ };
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" })
220
+ ] });
221
+ var Badge = ({ children, variant = "default", style }) => {
222
+ const colors = {
223
+ default: { bg: "#edf2f7", fg: "#4a5568" },
224
+ success: { bg: "#c6f6d5", fg: "#276749" },
225
+ warning: { bg: "#fefcbf", fg: "#975a16" },
226
+ error: { bg: "#fed7d7", fg: "#9b2c2c" },
227
+ info: { bg: "#bee3f8", fg: "#2a4365" }
228
+ };
229
+ 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 });
231
+ };
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 }) => {
234
+ const styles = {
235
+ primary: { background: "#3182ce", color: "#fff", border: "none" },
236
+ secondary: { background: "#edf2f7", color: "#4a5568", border: "1px solid #e2e8f0" },
237
+ danger: { background: "#e53e3e", color: "#fff", border: "none" },
238
+ ghost: { background: "transparent", color: "#4a5568", border: "none" }
239
+ };
240
+ const base = styles[variant] ?? styles.primary;
241
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
242
+ "button",
243
+ {
244
+ onClick,
245
+ disabled,
246
+ style: { padding: "6px 16px", borderRadius: 6, fontSize: 14, fontWeight: 500, cursor: disabled ? "not-allowed" : "pointer", opacity: disabled ? 0.5 : 1, ...base, ...style },
247
+ ...rest,
248
+ children
249
+ }
250
+ );
251
+ };
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)(
270
+ "select",
271
+ {
272
+ value: value ?? "",
273
+ onChange,
274
+ style: { width: "100%", padding: "6px 10px", border: "1px solid #e2e8f0", borderRadius: 6, fontSize: 14, ...style },
275
+ children: [
276
+ placeholder ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "", children: placeholder }) : null,
277
+ Array.isArray(options) && options.map((opt) => {
278
+ const v = typeof opt === "string" ? opt : opt.value;
279
+ const l = typeof opt === "string" ? opt : opt.label;
280
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: v, children: l }, v);
281
+ })
282
+ ]
283
+ }
284
+ )
285
+ ] });
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,
288
+ children
289
+ ] });
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,
292
+ children
293
+ ] });
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 }) => {
296
+ 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 });
299
+ };
300
+ var builtinAtoms = {
301
+ Stack,
302
+ Row,
303
+ Column,
304
+ Grid,
305
+ Divider,
306
+ Spacer,
307
+ Text,
308
+ Heading,
309
+ Field,
310
+ Badge,
311
+ Image: ImageAtom,
312
+ Button,
313
+ Link: LinkAtom,
314
+ TextInput,
315
+ Select: SelectAtom,
316
+ Card,
317
+ Section,
318
+ Show,
319
+ Each
320
+ };
321
+
322
+ // src/player/DevPlayer.tsx
323
+ var import_jsx_runtime3 = require("react/jsx-runtime");
324
+ var S = {
325
+ shell: {
326
+ display: "flex",
327
+ flexDirection: "column",
328
+ height: "100%",
329
+ minHeight: "100vh",
330
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
331
+ background: "#f7fafc",
332
+ color: "#1a202c"
333
+ },
334
+ toolbar: {
335
+ display: "flex",
336
+ alignItems: "center",
337
+ gap: 12,
338
+ padding: "8px 16px",
339
+ background: "#1a202c",
340
+ color: "#e2e8f0",
341
+ fontSize: 13,
342
+ flexShrink: 0
343
+ },
344
+ toolbarTitle: { fontWeight: 600, fontSize: 14 },
345
+ toolbarBadge: {
346
+ display: "inline-block",
347
+ padding: "1px 8px",
348
+ borderRadius: 4,
349
+ background: "#2d3748",
350
+ color: "#a0aec0",
351
+ fontSize: 11,
352
+ fontFamily: "monospace"
353
+ },
354
+ toolbarBtn: {
355
+ background: "none",
356
+ border: "1px solid #4a5568",
357
+ borderRadius: 4,
358
+ color: "#a0aec0",
359
+ padding: "2px 10px",
360
+ fontSize: 12,
361
+ cursor: "pointer"
362
+ },
363
+ toolbarBtnActive: {
364
+ background: "#2b6cb0",
365
+ borderColor: "#2b6cb0",
366
+ color: "#fff"
367
+ },
368
+ body: { display: "flex", flex: 1, overflow: "hidden" },
369
+ preview: { flex: 1, overflow: "auto", padding: 24 },
370
+ sidebar: {
371
+ width: 340,
372
+ flexShrink: 0,
373
+ borderLeft: "1px solid #e2e8f0",
374
+ background: "#fff",
375
+ overflow: "auto",
376
+ fontSize: 13
377
+ },
378
+ sidebarSection: { padding: "12px 16px", borderBottom: "1px solid #f0f0f0" },
379
+ sidebarHeading: {
380
+ fontSize: 11,
381
+ fontWeight: 700,
382
+ textTransform: "uppercase",
383
+ color: "#a0aec0",
384
+ letterSpacing: "0.05em",
385
+ marginBottom: 8
386
+ },
387
+ pre: {
388
+ background: "#f7fafc",
389
+ border: "1px solid #e2e8f0",
390
+ borderRadius: 6,
391
+ padding: "8px 12px",
392
+ fontSize: 12,
393
+ fontFamily: "monospace",
394
+ whiteSpace: "pre-wrap",
395
+ wordBreak: "break-word",
396
+ maxHeight: 260,
397
+ overflow: "auto"
398
+ },
399
+ eventRow: {
400
+ display: "flex",
401
+ gap: 8,
402
+ padding: "4px 0",
403
+ borderBottom: "1px solid #f7fafc",
404
+ fontSize: 12,
405
+ fontFamily: "monospace"
406
+ },
407
+ eventTime: { color: "#a0aec0", flexShrink: 0 },
408
+ eventName: { color: "#3182ce", fontWeight: 500 },
409
+ dot: (connected) => ({
410
+ width: 8,
411
+ height: 8,
412
+ borderRadius: "50%",
413
+ background: connected ? "#48bb78" : "#e53e3e",
414
+ flexShrink: 0
415
+ })
416
+ };
417
+ 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)(() => {
421
+ if (typeof window === "undefined") return;
422
+ const url = wsUrl ?? `ws://${window.location.host}/__mm_dev`;
423
+ let ws;
424
+ let reconnectTimer;
425
+ function connect() {
426
+ try {
427
+ ws = new WebSocket(url);
428
+ wsRef.current = ws;
429
+ ws.onopen = () => setConnected(true);
430
+ ws.onclose = () => {
431
+ setConnected(false);
432
+ reconnectTimer = setTimeout(connect, 3e3);
433
+ };
434
+ ws.onmessage = (ev) => {
435
+ try {
436
+ const msg = JSON.parse(ev.data);
437
+ if (msg.type === "workflow:compiled" || msg.type === "workflow:rebuild") {
438
+ onReload?.();
439
+ }
440
+ } catch {
441
+ }
442
+ };
443
+ } catch {
444
+ reconnectTimer = setTimeout(connect, 3e3);
445
+ }
446
+ }
447
+ connect();
448
+ return () => {
449
+ clearTimeout(reconnectTimer);
450
+ wsRef.current?.close();
451
+ wsRef.current = null;
452
+ };
453
+ }, [wsUrl, onReload]);
454
+ return connected;
455
+ }
456
+ var DevPlayer = ({
457
+ tree,
458
+ scopes = {},
459
+ atoms: userAtoms,
460
+ title = "DevPlayer",
461
+ bare = false,
462
+ wsUrl,
463
+ onReload,
464
+ onEvent: externalOnEvent
465
+ }) => {
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);
469
+ const connected = useDevSocket(wsUrl, onReload);
470
+ const mergedAtoms = (0, import_react2.useMemo)(
471
+ () => ({ ...builtinAtoms, ...userAtoms }),
472
+ [userAtoms]
473
+ );
474
+ const handleEvent = (0, import_react2.useCallback)(
475
+ (name, payload) => {
476
+ setEvents((prev) => {
477
+ const entry = {
478
+ id: nextId.current++,
479
+ time: (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false }),
480
+ name,
481
+ payload
482
+ };
483
+ const next = [entry, ...prev];
484
+ return next.length > 100 ? next.slice(0, 100) : next;
485
+ });
486
+ externalOnEvent?.(name, payload);
487
+ },
488
+ [externalOnEvent]
489
+ );
490
+ if (bare) {
491
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
492
+ ComponentTreeRenderer,
493
+ {
494
+ tree,
495
+ scopes,
496
+ atoms: mergedAtoms,
497
+ onEvent: handleEvent
498
+ }
499
+ );
500
+ }
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: [
506
+ Array.isArray(tree) ? tree.length : 1,
507
+ " node",
508
+ Array.isArray(tree) && tree.length !== 1 ? "s" : ""
509
+ ] }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("span", { style: S.toolbarBadge, children: [
511
+ Object.keys(mergedAtoms).length,
512
+ " atoms"
513
+ ] }),
514
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { flex: 1 } }),
515
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
516
+ "button",
517
+ {
518
+ style: { ...S.toolbarBtn, ...showSidebar ? S.toolbarBtnActive : {} },
519
+ onClick: () => setShowSidebar((v) => !v),
520
+ children: "Inspector"
521
+ }
522
+ )
523
+ ] }),
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)(
526
+ ComponentTreeRenderer,
527
+ {
528
+ tree,
529
+ scopes,
530
+ atoms: mergedAtoms,
531
+ onEvent: handleEvent
532
+ }
533
+ ) }),
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) })
538
+ ] }),
539
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarSection, children: [
540
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: S.sidebarHeading, children: [
541
+ "Atoms (",
542
+ Object.keys(mergedAtoms).length,
543
+ ")"
544
+ ] }),
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)(
546
+ "span",
547
+ {
548
+ style: {
549
+ display: "inline-block",
550
+ padding: "1px 6px",
551
+ borderRadius: 3,
552
+ background: userAtoms?.[name] ? "#ebf8ff" : "#f7fafc",
553
+ border: `1px solid ${userAtoms?.[name] ? "#90cdf4" : "#e2e8f0"}`,
554
+ fontSize: 11,
555
+ fontFamily: "monospace",
556
+ color: userAtoms?.[name] ? "#2b6cb0" : "#718096"
557
+ },
558
+ children: name
559
+ },
560
+ name
561
+ )) })
562
+ ] }),
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: [
566
+ "Events (",
567
+ events.length,
568
+ ")"
569
+ ] }),
570
+ events.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
571
+ "button",
572
+ {
573
+ style: { background: "none", border: "none", color: "#a0aec0", fontSize: 11, cursor: "pointer" },
574
+ onClick: () => setEvents([]),
575
+ children: "Clear"
576
+ }
577
+ )
578
+ ] }),
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) })
584
+ ] }, e.id))
585
+ ] }),
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) })
589
+ ] })
590
+ ] })
591
+ ] })
592
+ ] });
593
+ };
594
+ // Annotate the CommonJS export names for ESM import in node:
595
+ 0 && (module.exports = {
596
+ ComponentTreeRenderer,
597
+ DevPlayer,
598
+ builtinAtoms,
599
+ containsExpression,
600
+ evaluateExpression,
601
+ evaluateProp
602
+ });
@@ -0,0 +1,16 @@
1
+ import {
2
+ ComponentTreeRenderer,
3
+ DevPlayer,
4
+ builtinAtoms,
5
+ containsExpression,
6
+ evaluateExpression,
7
+ evaluateProp
8
+ } from "../chunk-PSL4FCGG.mjs";
9
+ export {
10
+ ComponentTreeRenderer,
11
+ DevPlayer,
12
+ builtinAtoms,
13
+ containsExpression,
14
+ evaluateExpression,
15
+ evaluateProp
16
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmapp/react",
3
- "version": "0.1.0-alpha.15",
3
+ "version": "0.1.0-alpha.17",
4
4
  "description": "React integration for the MindMatrix Player — hooks, components, and WebSocket bridge for browser-side workflow engines",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -35,7 +35,7 @@
35
35
  "@tanstack/react-query": ">=5.0.0"
36
36
  },
37
37
  "dependencies": {
38
- "@mmapp/player-core": "^0.1.0-alpha.15"
38
+ "@mmapp/player-core": "^0.1.0-alpha.17"
39
39
  },
40
40
  "publishConfig": {
41
41
  "access": "public"