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

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.
package/dist/index.js CHANGED
@@ -995,7 +995,7 @@ var init_actions = __esm({
995
995
  },
996
996
  children: [
997
997
  isLoading || loadingProp ? "\u23F3" : icon ? String(icon) : null,
998
- text != null ? String(text) : null,
998
+ text != null ? typeof text === "string" || typeof text === "number" ? String(text) : text : null,
999
999
  iconRight ? String(iconRight) : null
1000
1000
  ]
1001
1001
  }
@@ -1123,9 +1123,10 @@ var init_input = __esm({
1123
1123
  }
1124
1124
  }, [value]);
1125
1125
  const handleChange = (0, import_react37.useCallback)((e) => {
1126
- setLocalValue(e.target.value);
1126
+ const val = e.target.value;
1127
+ setLocalValue(val);
1127
1128
  if (typeof onChange === "function") {
1128
- onChange(e);
1129
+ onChange(val);
1129
1130
  }
1130
1131
  }, [onChange]);
1131
1132
  const displayValue = isControlled ? value ?? "" : localValue;
@@ -1191,8 +1192,9 @@ var init_input = __esm({
1191
1192
  if (value != null && String(value) !== localValue) setLocalValue(String(value));
1192
1193
  }, [value]);
1193
1194
  const handleChange = (0, import_react37.useCallback)((e) => {
1194
- setLocalValue(e.target.value);
1195
- if (typeof onChange === "function") onChange(e);
1195
+ const val = e.target.value;
1196
+ setLocalValue(val);
1197
+ if (typeof onChange === "function") onChange(val);
1196
1198
  }, [onChange]);
1197
1199
  const displayValue = isControlled ? value ?? "" : localValue;
1198
1200
  const opts = Array.isArray(options) ? options : [];
@@ -5915,6 +5917,14 @@ function resolveFunction(name, rawArgs, scope) {
5915
5917
  function resolveAction(name, rawArgs, scope) {
5916
5918
  const actions = scope.$action;
5917
5919
  if (!actions) return void 0;
5920
+ if (name === "seq") {
5921
+ return () => {
5922
+ for (const arg of rawArgs) {
5923
+ const resolved = resolveBinding(arg.trim(), scope);
5924
+ if (typeof resolved === "function") resolved();
5925
+ }
5926
+ };
5927
+ }
5918
5928
  if (rawArgs.length === 0) {
5919
5929
  const actionFn2 = actions[name];
5920
5930
  if (typeof actionFn2 === "function") return actionFn2;
@@ -5928,6 +5938,24 @@ function resolveAction(name, rawArgs, scope) {
5928
5938
  };
5929
5939
  }
5930
5940
  function resolveCondition(expression, scope) {
5941
+ const arrowMatch = expression.match(/^\(\)\s*=>\s*(.+)$/s);
5942
+ if (arrowMatch) {
5943
+ const body = arrowMatch[1].trim();
5944
+ const actionCallMatch = body.match(/^\(?(\$action)\)?\.(\w+)\((.*)?\)$/s);
5945
+ if (actionCallMatch) {
5946
+ const [, , method, argsStr] = actionCallMatch;
5947
+ return () => {
5948
+ const actionFn = scope.$action?.[method];
5949
+ if (typeof actionFn !== "function") return;
5950
+ const args = argsStr ? splitArgs(argsStr.trim()).map((a) => resolveBinding(a.trim(), scope)) : [];
5951
+ return actionFn(...args);
5952
+ };
5953
+ }
5954
+ return () => {
5955
+ const context2 = buildEvalContext(scope);
5956
+ return evaluateExpression(body, context2);
5957
+ };
5958
+ }
5931
5959
  const context = buildEvalContext(scope);
5932
5960
  return evaluateExpression(expression, context);
5933
5961
  }
@@ -5951,6 +5979,11 @@ function buildEvalContext(scope) {
5951
5979
  }
5952
5980
  if (scope.$item) ctx.item = scope.$item;
5953
5981
  if (scope.$index != null) ctx.index = scope.$index;
5982
+ for (const [key, value] of Object.entries(scope)) {
5983
+ if (!key.startsWith("$") && !(key in ctx) && value !== void 0) {
5984
+ ctx[key] = value;
5985
+ }
5986
+ }
5954
5987
  if (scope.state_data) ctx.state_data = scope.state_data;
5955
5988
  if (scope.memory) ctx.memory = scope.memory;
5956
5989
  if (scope.context) ctx.context = scope.context;
@@ -5959,17 +5992,34 @@ function buildEvalContext(scope) {
5959
5992
  function buildActionScope(opts) {
5960
5993
  const { resolver, instanceId, slug, setLocal, router, toast, refreshQuery, onEvent } = opts;
5961
5994
  return {
5962
- transition: async (name, id, data) => {
5963
- const targetId = id ?? instanceId;
5995
+ transition: async (idOrName, nameOrId, data) => {
5996
+ let targetId;
5997
+ let transitionName;
5998
+ if (nameOrId) {
5999
+ targetId = idOrName;
6000
+ transitionName = nameOrId;
6001
+ } else {
6002
+ transitionName = idOrName;
6003
+ targetId = instanceId;
6004
+ }
5964
6005
  if (!targetId) {
5965
6006
  console.warn("[action] transition called without instanceId");
5966
6007
  return;
5967
6008
  }
5968
- await resolver.transition(targetId, name, data);
6009
+ await resolver.transition(targetId, transitionName, data);
5969
6010
  refreshQuery?.();
5970
6011
  },
5971
- create: async (targetSlug, data) => {
5972
- const id = await resolver.create(targetSlug || slug || "", data);
6012
+ create: async (slugOrData, data) => {
6013
+ let targetSlug;
6014
+ let fields;
6015
+ if (typeof slugOrData === "object") {
6016
+ targetSlug = slug || "";
6017
+ fields = slugOrData;
6018
+ } else {
6019
+ targetSlug = slugOrData || slug || "";
6020
+ fields = data;
6021
+ }
6022
+ const id = await resolver.create(targetSlug, fields);
5973
6023
  refreshQuery?.();
5974
6024
  return id;
5975
6025
  },
@@ -6278,6 +6328,14 @@ var PlayerProvider = ({
6278
6328
 
6279
6329
  // src/player/ExperienceRenderer.tsx
6280
6330
  var import_jsx_runtime12 = require("react/jsx-runtime");
6331
+ var SharedLocalContext = import_react44.default.createContext({
6332
+ state: {},
6333
+ setLocal: () => {
6334
+ }
6335
+ });
6336
+ function useSharedLocal() {
6337
+ return import_react44.default.useContext(SharedLocalContext);
6338
+ }
6281
6339
  var NodeErrorBoundary = class extends import_react44.default.Component {
6282
6340
  constructor(props) {
6283
6341
  super(props);
@@ -6495,13 +6553,19 @@ var NodeRenderer = ({ node, fallback }) => {
6495
6553
  const resolver = playerCtx?.resolver ?? null;
6496
6554
  const atomRegistry = playerCtx?.atomRegistry;
6497
6555
  const themeTokens = useTheme();
6556
+ const sharedLocal = useSharedLocal();
6498
6557
  const localDefaults = node.config?.localDefaults ?? {};
6499
- const [localState, setLocalState] = (0, import_react44.useState)(() => ({
6500
- ...localDefaults
6501
- }));
6502
- const handleSetLocal = (0, import_react44.useCallback)((key, value) => {
6503
- setLocalState((prev) => ({ ...prev, [key]: value }));
6558
+ (0, import_react44.useEffect)(() => {
6559
+ if (Object.keys(localDefaults).length > 0) {
6560
+ for (const [key, value] of Object.entries(localDefaults)) {
6561
+ if (sharedLocal.state[key] === void 0) {
6562
+ sharedLocal.setLocal(key, value);
6563
+ }
6564
+ }
6565
+ }
6504
6566
  }, []);
6567
+ const localState = sharedLocal.state;
6568
+ const handleSetLocal = sharedLocal.setLocal;
6505
6569
  const [, setFetchVersion] = (0, import_react44.useState)(0);
6506
6570
  const handleRefreshQuery = (0, import_react44.useCallback)(() => {
6507
6571
  setFetchVersion((v) => v + 1);
@@ -6557,7 +6621,35 @@ var NodeRenderer = ({ node, fallback }) => {
6557
6621
  const enrichedScope = (0, import_react44.useMemo)(() => {
6558
6622
  const handleCreate = () => {
6559
6623
  if (primarySlug && resolver) {
6560
- resolver.create(primarySlug).then(() => handleRefreshQuery());
6624
+ const fields = {};
6625
+ for (const [key, val] of Object.entries(localState)) {
6626
+ if (key.startsWith("new_") && val != null && val !== "") {
6627
+ fields[key.slice(4)] = val;
6628
+ }
6629
+ }
6630
+ resolver.create(primarySlug, Object.keys(fields).length > 0 ? fields : void 0).then(() => {
6631
+ for (const key of Object.keys(localState)) {
6632
+ if (key.startsWith("new_")) handleSetLocal(key, "");
6633
+ }
6634
+ handleSetLocal("show_create", false);
6635
+ handleRefreshQuery();
6636
+ });
6637
+ }
6638
+ };
6639
+ const handleUpdate = (id) => {
6640
+ if (primarySlug && resolver) {
6641
+ const fields = {};
6642
+ for (const [key, val] of Object.entries(localState)) {
6643
+ if (key.startsWith("edit_") && val != null && val !== "") {
6644
+ fields[key.slice(5)] = val;
6645
+ }
6646
+ }
6647
+ if (Object.keys(fields).length > 0) {
6648
+ resolver.update(id, fields).then(() => {
6649
+ handleSetLocal("editing_id", null);
6650
+ handleRefreshQuery();
6651
+ });
6652
+ }
6561
6653
  }
6562
6654
  };
6563
6655
  const setSearch = (e) => {
@@ -6567,15 +6659,18 @@ var NodeRenderer = ({ node, fallback }) => {
6567
6659
  const enrichedAction = {
6568
6660
  ...scope.$action,
6569
6661
  handleCreate,
6662
+ handleUpdate,
6570
6663
  setSearch
6571
6664
  };
6572
- const enrichedInstance = scope.$instance ? { ...scope.$instance, handleCreate, setSearch } : void 0;
6665
+ const baseInstance = scope.$instance ?? { id: "", state: "", fields: {} };
6666
+ const enrichedInstance = { ...baseInstance, handleCreate, handleUpdate, setSearch };
6573
6667
  return {
6574
6668
  ...scope,
6575
6669
  $action: enrichedAction,
6576
6670
  $instance: enrichedInstance,
6577
6671
  // Also add at top-level for direct access
6578
6672
  handleCreate,
6673
+ handleUpdate,
6579
6674
  setSearch
6580
6675
  };
6581
6676
  }, [scope, primarySlug, resolver, handleRefreshQuery, handleSetLocal]);
@@ -6652,6 +6747,14 @@ var ExperienceRenderer = ({
6652
6747
  }) => {
6653
6748
  const playerCtx = usePlayerContext();
6654
6749
  const nodes = Array.isArray(tree) ? tree : [tree];
6750
+ const [sharedLocalState, setSharedLocalState] = (0, import_react44.useState)({});
6751
+ const handleSharedSetLocal = (0, import_react44.useCallback)((key, value) => {
6752
+ setSharedLocalState((prev) => ({ ...prev, [key]: value }));
6753
+ }, []);
6754
+ const sharedLocal = (0, import_react44.useMemo)(() => ({
6755
+ state: sharedLocalState,
6756
+ setLocal: handleSharedSetLocal
6757
+ }), [sharedLocalState, handleSharedSetLocal]);
6655
6758
  const rootScope = (0, import_react44.useMemo)(() => buildScope({
6656
6759
  auth: playerCtx?.auth ?? initialScope?.auth,
6657
6760
  entity,
@@ -6682,7 +6785,7 @@ var ExperienceRenderer = ({
6682
6785
  }
6683
6786
  }
6684
6787
  }), [playerCtx?.auth, entity, initialScope]);
6685
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScopeContext.Provider, { value: rootScope, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className, children: nodes.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeErrorBoundary, { nodeId: node.id, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeRenderer, { node, fallback }) }, node.id ?? i)) }) });
6788
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(SharedLocalContext.Provider, { value: sharedLocal, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(ScopeContext.Provider, { value: rootScope, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className, children: nodes.map((node, i) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeErrorBoundary, { nodeId: node.id, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(NodeRenderer, { node, fallback }) }, node.id ?? i)) }) }) });
6686
6789
  };
6687
6790
 
6688
6791
  // src/player/resolver.ts
package/dist/index.mjs CHANGED
@@ -55,7 +55,7 @@ import {
55
55
  useMutation,
56
56
  usePlayerContext,
57
57
  useQuery
58
- } from "./chunk-J5MW6CRU.mjs";
58
+ } from "./chunk-XWBUADY2.mjs";
59
59
  import {
60
60
  ScopeContext,
61
61
  buildLoopScope,
@@ -0,0 +1,224 @@
1
+ // src/player/atoms/input.tsx
2
+ import { useState, useCallback, useEffect } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var inputBase = {
5
+ padding: "6px 12px",
6
+ border: "1px solid #e2e8f0",
7
+ borderRadius: 6,
8
+ fontSize: 14,
9
+ outline: "none",
10
+ width: "100%",
11
+ boxSizing: "border-box",
12
+ background: "#fff",
13
+ color: "#1a202c",
14
+ transition: "border-color 0.15s"
15
+ };
16
+ var TextInput = ({
17
+ value,
18
+ onChange,
19
+ onBlur,
20
+ placeholder,
21
+ label,
22
+ type,
23
+ name,
24
+ disabled,
25
+ required,
26
+ error,
27
+ helperText,
28
+ multiline,
29
+ rows,
30
+ maxLength,
31
+ className,
32
+ style,
33
+ bind: _bind
34
+ }) => {
35
+ const isControlled = typeof onChange === "function";
36
+ const [localValue, setLocalValue] = useState(value ?? "");
37
+ useEffect(() => {
38
+ if (value != null && String(value) !== localValue) {
39
+ setLocalValue(String(value));
40
+ }
41
+ }, [value]);
42
+ const handleChange = useCallback((e) => {
43
+ const val = e.target.value;
44
+ setLocalValue(val);
45
+ if (typeof onChange === "function") {
46
+ onChange(val);
47
+ }
48
+ }, [onChange]);
49
+ const displayValue = isControlled ? value ?? "" : localValue;
50
+ const hasError = Boolean(error);
51
+ const inputStyle = {
52
+ ...inputBase,
53
+ borderColor: hasError ? "#e53e3e" : "#e2e8f0",
54
+ ...style
55
+ };
56
+ return /* @__PURE__ */ jsxs("div", { className, style: { width: "100%" }, children: [
57
+ label ? /* @__PURE__ */ jsxs("label", { style: { display: "block", fontSize: 13, fontWeight: 500, marginBottom: 4, color: "#4a5568" }, children: [
58
+ String(label),
59
+ required ? /* @__PURE__ */ jsx("span", { style: { color: "#e53e3e" }, children: " *" }) : null
60
+ ] }) : null,
61
+ multiline ? /* @__PURE__ */ jsx(
62
+ "textarea",
63
+ {
64
+ value: displayValue,
65
+ onChange: handleChange,
66
+ onBlur,
67
+ placeholder,
68
+ name,
69
+ disabled: Boolean(disabled),
70
+ required: Boolean(required),
71
+ rows: Number(rows) || 3,
72
+ maxLength: maxLength ? Number(maxLength) : void 0,
73
+ style: inputStyle
74
+ }
75
+ ) : /* @__PURE__ */ jsx(
76
+ "input",
77
+ {
78
+ type: type ?? "text",
79
+ value: displayValue,
80
+ onChange: handleChange,
81
+ onBlur,
82
+ placeholder,
83
+ name,
84
+ disabled: Boolean(disabled),
85
+ required: Boolean(required),
86
+ maxLength: maxLength ? Number(maxLength) : void 0,
87
+ style: inputStyle
88
+ }
89
+ ),
90
+ error || helperText ? /* @__PURE__ */ jsx("div", { style: { fontSize: 12, marginTop: 2, color: hasError ? "#e53e3e" : "#a0aec0" }, children: String(error || helperText) }) : null
91
+ ] });
92
+ };
93
+ var Select = ({
94
+ value,
95
+ onChange,
96
+ options,
97
+ placeholder,
98
+ label,
99
+ disabled,
100
+ required,
101
+ error,
102
+ name,
103
+ className,
104
+ style
105
+ }) => {
106
+ const [localValue, setLocalValue] = useState(value ?? "");
107
+ const isControlled = typeof onChange === "function";
108
+ useEffect(() => {
109
+ if (value != null && String(value) !== localValue) setLocalValue(String(value));
110
+ }, [value]);
111
+ const handleChange = useCallback((e) => {
112
+ const val = e.target.value;
113
+ setLocalValue(val);
114
+ if (typeof onChange === "function") onChange(val);
115
+ }, [onChange]);
116
+ const displayValue = isControlled ? value ?? "" : localValue;
117
+ const opts = Array.isArray(options) ? options : [];
118
+ return /* @__PURE__ */ jsxs("div", { className, children: [
119
+ label ? /* @__PURE__ */ jsxs("label", { style: { display: "block", fontSize: 13, fontWeight: 500, marginBottom: 4, color: "#4a5568" }, children: [
120
+ String(label),
121
+ required ? /* @__PURE__ */ jsx("span", { style: { color: "#e53e3e" }, children: " *" }) : null
122
+ ] }) : null,
123
+ /* @__PURE__ */ jsxs(
124
+ "select",
125
+ {
126
+ value: displayValue,
127
+ onChange: handleChange,
128
+ disabled: Boolean(disabled),
129
+ name,
130
+ style: {
131
+ ...inputBase,
132
+ borderColor: error ? "#e53e3e" : "#e2e8f0",
133
+ ...style
134
+ },
135
+ children: [
136
+ placeholder ? /* @__PURE__ */ jsx("option", { value: "", children: String(placeholder) }) : null,
137
+ opts.map((opt, i) => {
138
+ const val = typeof opt === "object" ? opt.value : opt;
139
+ const lbl = typeof opt === "object" ? opt.label ?? val : opt;
140
+ return /* @__PURE__ */ jsx("option", { value: String(val), children: String(lbl) }, String(val) ?? i);
141
+ })
142
+ ]
143
+ }
144
+ )
145
+ ] });
146
+ };
147
+ var Toggle = ({ value, checked, onChange, label, disabled, className, style }) => {
148
+ const isOn = Boolean(value ?? checked);
149
+ const handleClick = useCallback(() => {
150
+ if (disabled) return;
151
+ if (typeof onChange === "function") onChange(!isOn);
152
+ }, [onChange, isOn, disabled]);
153
+ return /* @__PURE__ */ jsxs(
154
+ "div",
155
+ {
156
+ className,
157
+ style: { display: "flex", alignItems: "center", gap: 8, ...style },
158
+ children: [
159
+ /* @__PURE__ */ jsx(
160
+ "button",
161
+ {
162
+ role: "switch",
163
+ "aria-checked": isOn,
164
+ disabled: Boolean(disabled),
165
+ onClick: handleClick,
166
+ style: {
167
+ width: 40,
168
+ height: 22,
169
+ borderRadius: 11,
170
+ border: "none",
171
+ cursor: disabled ? "not-allowed" : "pointer",
172
+ background: isOn ? "#3182ce" : "#cbd5e0",
173
+ padding: 2,
174
+ transition: "background 0.2s",
175
+ display: "flex",
176
+ alignItems: "center"
177
+ },
178
+ children: /* @__PURE__ */ jsx("div", { style: {
179
+ width: 18,
180
+ height: 18,
181
+ borderRadius: "50%",
182
+ background: "#fff",
183
+ transform: isOn ? "translateX(18px)" : "translateX(0)",
184
+ transition: "transform 0.2s",
185
+ boxShadow: "0 1px 3px rgba(0,0,0,0.2)"
186
+ } })
187
+ }
188
+ ),
189
+ label ? /* @__PURE__ */ jsx("span", { style: { fontSize: 14 }, children: String(label) }) : null
190
+ ]
191
+ }
192
+ );
193
+ };
194
+ var Slider = ({ value, onChange, min, max, step, label, disabled, className, style }) => {
195
+ const numVal = Number(value) || Number(min) || 0;
196
+ const handleChange = useCallback((e) => {
197
+ if (typeof onChange === "function") onChange(Number(e.target.value));
198
+ }, [onChange]);
199
+ return /* @__PURE__ */ jsxs("div", { className, style: { ...style }, children: [
200
+ label ? /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", fontSize: 13, marginBottom: 4 }, children: [
201
+ /* @__PURE__ */ jsx("span", { style: { color: "#4a5568", fontWeight: 500 }, children: String(label) }),
202
+ /* @__PURE__ */ jsx("span", { style: { color: "#718096" }, children: numVal })
203
+ ] }) : null,
204
+ /* @__PURE__ */ jsx(
205
+ "input",
206
+ {
207
+ type: "range",
208
+ value: numVal,
209
+ onChange: handleChange,
210
+ min: Number(min) ?? 0,
211
+ max: Number(max) ?? 100,
212
+ step: Number(step) ?? 1,
213
+ disabled: Boolean(disabled),
214
+ style: { width: "100%" }
215
+ }
216
+ )
217
+ ] });
218
+ };
219
+ export {
220
+ Select,
221
+ Slider,
222
+ TextInput,
223
+ Toggle
224
+ };