@waypointjs/builder 0.1.4 → 0.1.5

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.cjs CHANGED
@@ -197,6 +197,44 @@ var useBuilderStore = zustand.create((set, _get) => ({
197
197
  selectedFieldId: s.selectedStepId === stepId ? null : s.selectedFieldId,
198
198
  isDirty: true
199
199
  })),
200
+ duplicateStep: (stepId) => {
201
+ const state = _get();
202
+ const step = state.schema.steps.find((s) => s.id === stepId);
203
+ if (!step) return;
204
+ const newStepId = generateId("step");
205
+ const fieldIdMap = {};
206
+ for (const f of step.fields) {
207
+ fieldIdMap[f.id] = generateId("field");
208
+ }
209
+ const newFields = step.fields.map((f) => ({
210
+ ...f,
211
+ id: fieldIdMap[f.id],
212
+ dependsOn: f.dependsOn?.map((dep) => {
213
+ if (dep.startsWith(`${stepId}.`)) {
214
+ const oldFieldId = dep.slice(stepId.length + 1);
215
+ const newFieldId = fieldIdMap[oldFieldId];
216
+ return newFieldId ? `${newStepId}.${newFieldId}` : dep;
217
+ }
218
+ return dep;
219
+ })
220
+ }));
221
+ const newStep = {
222
+ ...step,
223
+ id: newStepId,
224
+ title: `${step.title} (copy)`,
225
+ url: `${step.url}-copy`,
226
+ fields: newFields
227
+ };
228
+ const stepIndex = state.schema.steps.findIndex((s) => s.id === stepId);
229
+ const newSteps = [...state.schema.steps];
230
+ newSteps.splice(stepIndex + 1, 0, newStep);
231
+ set({
232
+ schema: { ...state.schema, steps: newSteps },
233
+ selectedStepId: newStepId,
234
+ selectedFieldId: null,
235
+ isDirty: true
236
+ });
237
+ },
200
238
  reorderSteps: (fromIndex, toIndex) => set((s) => {
201
239
  const steps = [...s.schema.steps];
202
240
  const [moved] = steps.splice(fromIndex, 1);
@@ -249,6 +287,32 @@ var useBuilderStore = zustand.create((set, _get) => ({
249
287
  selectedFieldId: s.selectedFieldId === fieldId ? null : s.selectedFieldId,
250
288
  isDirty: true
251
289
  })),
290
+ duplicateField: (stepId, fieldId) => {
291
+ const state = _get();
292
+ const step = state.schema.steps.find((s) => s.id === stepId);
293
+ if (!step) return;
294
+ const field = step.fields.find((f) => f.id === fieldId);
295
+ if (!field) return;
296
+ const newFieldId = generateId("field");
297
+ const newField = {
298
+ ...field,
299
+ id: newFieldId,
300
+ label: `${field.label} (copy)`
301
+ };
302
+ const fieldIndex = step.fields.findIndex((f) => f.id === fieldId);
303
+ const newFields = [...step.fields];
304
+ newFields.splice(fieldIndex + 1, 0, newField);
305
+ set((s) => ({
306
+ schema: {
307
+ ...s.schema,
308
+ steps: s.schema.steps.map(
309
+ (st) => st.id === stepId ? { ...st, fields: newFields } : st
310
+ )
311
+ },
312
+ selectedFieldId: newFieldId,
313
+ isDirty: true
314
+ }));
315
+ },
252
316
  reorderFields: (stepId, fromIndex, toIndex) => set((s) => ({
253
317
  schema: {
254
318
  ...s.schema,
@@ -347,6 +411,18 @@ var useBuilderStore = zustand.create((set, _get) => ({
347
411
  isDirty: true
348
412
  }))
349
413
  }));
414
+ var BuilderReadOnlyContext = react.createContext(false);
415
+ function useBuilderReadOnly() {
416
+ return react.useContext(BuilderReadOnlyContext);
417
+ }
418
+ var BuilderCustomTypesContext = react.createContext([]);
419
+ function useBuilderCustomTypes() {
420
+ return react.useContext(BuilderCustomTypesContext);
421
+ }
422
+ var BuilderExternalEnumsContext = react.createContext([]);
423
+ function useBuilderExternalEnums() {
424
+ return react.useContext(BuilderExternalEnumsContext);
425
+ }
350
426
  var BLANK_FORM = {
351
427
  id: "",
352
428
  label: "",
@@ -360,6 +436,7 @@ function ExternalVariablePanel() {
360
436
  updateExternalVariable,
361
437
  removeExternalVariable
362
438
  } = useBuilderStore();
439
+ const readOnly = useBuilderReadOnly();
363
440
  const variables = schema.externalVariables ?? [];
364
441
  const [isAdding, setIsAdding] = react.useState(false);
365
442
  const [editingId, setEditingId] = react.useState(null);
@@ -433,7 +510,7 @@ function ExternalVariablePanel() {
433
510
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle, children: [
434
511
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
435
512
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: titleStyle, children: "External Variables" }),
436
- !isAdding && /* @__PURE__ */ jsxRuntime.jsx(
513
+ !readOnly && !isAdding && /* @__PURE__ */ jsxRuntime.jsx(
437
514
  "button",
438
515
  {
439
516
  style: addBtnStyle,
@@ -488,7 +565,7 @@ function ExternalVariablePanel() {
488
565
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: varLabelStyle, children: v.label }),
489
566
  refs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: refsStyle, children: refs.map((ref, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: refChipStyle, children: ref }, i)) })
490
567
  ] }),
491
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: varActionsStyle, children: [
568
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: varActionsStyle, children: [
492
569
  /* @__PURE__ */ jsxRuntime.jsx("button", { style: actionBtnStyle, onClick: () => startEdit(v), children: "Edit" }),
493
570
  /* @__PURE__ */ jsxRuntime.jsx(
494
571
  "button",
@@ -815,15 +892,23 @@ var submitBtnStyle = {
815
892
  // src/hooks/useAllFieldPaths.ts
816
893
  function useAllFieldPaths(excludeStepId, excludeFieldId) {
817
894
  const { schema } = useBuilderStore();
895
+ const externalEnums = useBuilderExternalEnums();
818
896
  const paths = [];
819
897
  for (const step of schema.steps) {
820
898
  for (const field of step.fields) {
821
899
  if (step.id === excludeStepId && field.id === excludeFieldId) continue;
900
+ let options;
901
+ if (field.externalEnumId) {
902
+ options = externalEnums.find((e) => e.id === field.externalEnumId)?.values;
903
+ } else if (field.options?.length) {
904
+ options = field.options;
905
+ }
822
906
  paths.push({
823
907
  path: `${step.id}.${field.id}`,
824
908
  label: `${step.title} \u2192 ${field.label}`,
825
909
  stepId: step.id,
826
- fieldId: field.id
910
+ fieldId: field.id,
911
+ options
827
912
  });
828
913
  }
829
914
  }
@@ -849,7 +934,9 @@ var OPERATORS = [
849
934
  { value: "notIn", label: "not in (comma list)", hasValue: true },
850
935
  { value: "matches", label: "matches regex", hasValue: true },
851
936
  { value: "exists", label: "exists", hasValue: false },
852
- { value: "notExists", label: "not exists", hasValue: false }
937
+ { value: "notExists", label: "not exists", hasValue: false },
938
+ { value: "inEnum", label: "is in enum", hasValue: true, isEnum: true },
939
+ { value: "notInEnum", label: "not in enum", hasValue: true, isEnum: true }
853
940
  ];
854
941
  function ConditionBuilder({
855
942
  value,
@@ -858,6 +945,7 @@ function ConditionBuilder({
858
945
  excludeFieldId
859
946
  }) {
860
947
  const allPaths = useAllFieldPaths(excludeStepId, excludeFieldId);
948
+ const externalEnums = useBuilderExternalEnums();
861
949
  const group = value ?? { combinator: "and", rules: [] };
862
950
  const updateRule = (index, updates) => {
863
951
  const rules = group.rules.map((r, i) => i === index ? { ...r, ...updates } : r);
@@ -920,15 +1008,48 @@ function ConditionBuilder({
920
1008
  children: OPERATORS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
921
1009
  }
922
1010
  ),
923
- opDef?.hasValue && /* @__PURE__ */ jsxRuntime.jsx(
924
- "input",
1011
+ opDef?.hasValue && (opDef.isEnum ? /* @__PURE__ */ jsxRuntime.jsxs(
1012
+ "select",
925
1013
  {
926
- style: styles.valueInput,
927
- placeholder: "value",
1014
+ style: { ...styles.select, width: 140 },
928
1015
  value: rule.value != null ? String(rule.value) : "",
929
- onChange: (e) => updateRule(index, { value: e.target.value })
1016
+ onChange: (e) => updateRule(index, { value: e.target.value }),
1017
+ children: [
1018
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014 pick enum \u2014" }),
1019
+ externalEnums.map((en) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: en.id, children: en.label }, en.id))
1020
+ ]
930
1021
  }
931
- ),
1022
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.valueGroup, children: [
1023
+ /* @__PURE__ */ jsxRuntime.jsx(
1024
+ "input",
1025
+ {
1026
+ style: styles.valueInput,
1027
+ placeholder: "value",
1028
+ value: rule.value != null ? String(rule.value) : "",
1029
+ onChange: (e) => updateRule(index, { value: e.target.value })
1030
+ }
1031
+ ),
1032
+ externalEnums.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
1033
+ "select",
1034
+ {
1035
+ style: styles.enumPicker,
1036
+ title: "Pick a value from an enum",
1037
+ value: "",
1038
+ onChange: (e) => {
1039
+ if (e.target.value) updateRule(index, { value: e.target.value });
1040
+ },
1041
+ children: [
1042
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u229E" }),
1043
+ externalEnums.map((en) => /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: en.label, children: en.values.map((v) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: String(v.value), children: [
1044
+ v.label,
1045
+ " (",
1046
+ v.value,
1047
+ ")"
1048
+ ] }, String(v.value))) }, en.id))
1049
+ ]
1050
+ }
1051
+ )
1052
+ ] })),
932
1053
  /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles.removeBtn, onClick: () => removeRule(index), children: "\u2715" })
933
1054
  ] }, index);
934
1055
  }),
@@ -1006,6 +1127,17 @@ var styles = {
1006
1127
  alignSelf: "flex-start",
1007
1128
  color: "var(--wp-text-secondary)"
1008
1129
  },
1130
+ valueGroup: { display: "flex", alignItems: "center", gap: 4 },
1131
+ enumPicker: {
1132
+ fontSize: 11,
1133
+ padding: "4px 4px",
1134
+ border: "1px solid var(--wp-border-muted)",
1135
+ borderRadius: "var(--wp-radius)",
1136
+ background: "var(--wp-canvas)",
1137
+ color: "var(--wp-primary)",
1138
+ cursor: "pointer",
1139
+ flexShrink: 0
1140
+ },
1009
1141
  preview: { marginTop: 4 },
1010
1142
  previewLabel: {
1011
1143
  fontSize: 10,
@@ -1027,6 +1159,190 @@ var styles = {
1027
1159
  color: "var(--wp-text-mono)"
1028
1160
  }
1029
1161
  };
1162
+ var VALIDATION_RULES = [
1163
+ { type: "required", label: "Required", hasValue: false },
1164
+ { type: "min", label: "Min value", hasValue: true },
1165
+ { type: "max", label: "Max value", hasValue: true },
1166
+ { type: "minLength", label: "Min length", hasValue: true },
1167
+ { type: "maxLength", label: "Max length", hasValue: true },
1168
+ { type: "email", label: "Email format", hasValue: false },
1169
+ { type: "url", label: "URL format", hasValue: false },
1170
+ { type: "regex", label: "Matches regex", hasValue: true },
1171
+ { type: "equals", label: "equals", hasValue: true },
1172
+ { type: "notEquals", label: "not equals", hasValue: true },
1173
+ { type: "greaterThan", label: ">", hasValue: true },
1174
+ { type: "greaterThanOrEqual", label: ">=", hasValue: true },
1175
+ { type: "lessThan", label: "<", hasValue: true },
1176
+ { type: "lessThanOrEqual", label: "<=", hasValue: true },
1177
+ { type: "contains", label: "contains", hasValue: true },
1178
+ { type: "notContains", label: "not contains", hasValue: true },
1179
+ { type: "matches", label: "matches regex", hasValue: true },
1180
+ { type: "inEnum", label: "is in enum", hasValue: true, isEnum: true },
1181
+ { type: "notInEnum", label: "not in enum", hasValue: true, isEnum: true },
1182
+ { type: "custom", label: "Custom validator", hasValue: false }
1183
+ ];
1184
+ function ValidationBuilder({ value, onChange }) {
1185
+ const externalEnums = useBuilderExternalEnums();
1186
+ const updateRule = (index, updates) => {
1187
+ onChange(value.map((r, i) => i === index ? { ...r, ...updates } : r));
1188
+ };
1189
+ const addRule = () => {
1190
+ onChange([...value, { type: "required", message: "This field is required" }]);
1191
+ };
1192
+ const removeRule = (index) => {
1193
+ onChange(value.filter((_, i) => i !== index));
1194
+ };
1195
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.container, children: [
1196
+ value.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles2.empty, children: "No rules \u2014 field is optional by default." }),
1197
+ value.map((rule, index) => {
1198
+ const def = VALIDATION_RULES.find((r) => r.type === rule.type);
1199
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.rule, children: [
1200
+ /* @__PURE__ */ jsxRuntime.jsx(
1201
+ "select",
1202
+ {
1203
+ style: styles2.typeSelect,
1204
+ value: rule.type,
1205
+ onChange: (e) => updateRule(index, { type: e.target.value }),
1206
+ children: VALIDATION_RULES.map((r) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: r.type, children: r.label }, r.type))
1207
+ }
1208
+ ),
1209
+ def?.hasValue && (def.isEnum ? /* @__PURE__ */ jsxRuntime.jsxs(
1210
+ "select",
1211
+ {
1212
+ style: { ...styles2.typeSelect, flex: "0 0 140px" },
1213
+ value: rule.value != null ? String(rule.value) : "",
1214
+ onChange: (e) => updateRule(index, { value: e.target.value }),
1215
+ children: [
1216
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014 pick enum \u2014" }),
1217
+ externalEnums.map((en) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: en.id, children: en.label }, en.id))
1218
+ ]
1219
+ }
1220
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.valueGroup, children: [
1221
+ /* @__PURE__ */ jsxRuntime.jsx(
1222
+ "input",
1223
+ {
1224
+ style: styles2.valueInput,
1225
+ placeholder: "value",
1226
+ value: rule.value != null ? String(rule.value) : "",
1227
+ onChange: (e) => updateRule(index, { value: e.target.value })
1228
+ }
1229
+ ),
1230
+ externalEnums.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
1231
+ "select",
1232
+ {
1233
+ style: styles2.enumPicker,
1234
+ title: "Pick a value from an enum",
1235
+ value: "",
1236
+ onChange: (e) => {
1237
+ if (e.target.value) updateRule(index, { value: e.target.value });
1238
+ },
1239
+ children: [
1240
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u229E" }),
1241
+ externalEnums.map((en) => /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: en.label, children: en.values.map((v) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: String(v.value), children: [
1242
+ v.label,
1243
+ " (",
1244
+ v.value,
1245
+ ")"
1246
+ ] }, String(v.value))) }, en.id))
1247
+ ]
1248
+ }
1249
+ )
1250
+ ] })),
1251
+ rule.type === "custom" && /* @__PURE__ */ jsxRuntime.jsx(
1252
+ "input",
1253
+ {
1254
+ style: styles2.valueInput,
1255
+ placeholder: "validatorId",
1256
+ value: rule.customValidatorId ?? "",
1257
+ onChange: (e) => updateRule(index, { customValidatorId: e.target.value })
1258
+ }
1259
+ ),
1260
+ /* @__PURE__ */ jsxRuntime.jsx(
1261
+ "input",
1262
+ {
1263
+ style: styles2.messageInput,
1264
+ placeholder: "error message",
1265
+ value: rule.message,
1266
+ onChange: (e) => updateRule(index, { message: e.target.value })
1267
+ }
1268
+ ),
1269
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles2.removeBtn, onClick: () => removeRule(index), children: "\u2715" })
1270
+ ] }, index);
1271
+ }),
1272
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles2.addBtn, onClick: addRule, children: "+ Add rule" })
1273
+ ] });
1274
+ }
1275
+ var styles2 = {
1276
+ container: { display: "flex", flexDirection: "column", gap: 10 },
1277
+ empty: { fontSize: 13, color: "var(--wp-text-subtle)", textAlign: "center", padding: "12px 0" },
1278
+ rule: {
1279
+ display: "flex",
1280
+ alignItems: "center",
1281
+ gap: 8,
1282
+ background: "var(--wp-surface)",
1283
+ border: "1px solid var(--wp-border)",
1284
+ borderRadius: "var(--wp-radius-lg)",
1285
+ padding: "8px 10px"
1286
+ },
1287
+ typeSelect: {
1288
+ flex: "0 0 150px",
1289
+ fontSize: 12,
1290
+ padding: "5px 6px",
1291
+ border: "1px solid var(--wp-border-muted)",
1292
+ borderRadius: "var(--wp-radius)",
1293
+ background: "var(--wp-canvas)",
1294
+ color: "var(--wp-text)"
1295
+ },
1296
+ valueGroup: { display: "flex", alignItems: "center", gap: 4 },
1297
+ valueInput: {
1298
+ width: 90,
1299
+ fontSize: 12,
1300
+ padding: "5px 6px",
1301
+ border: "1px solid var(--wp-border-muted)",
1302
+ borderRadius: "var(--wp-radius)",
1303
+ background: "var(--wp-canvas)",
1304
+ color: "var(--wp-text)"
1305
+ },
1306
+ enumPicker: {
1307
+ fontSize: 11,
1308
+ padding: "4px 4px",
1309
+ border: "1px solid var(--wp-border-muted)",
1310
+ borderRadius: "var(--wp-radius)",
1311
+ background: "var(--wp-canvas)",
1312
+ color: "var(--wp-primary)",
1313
+ cursor: "pointer",
1314
+ flexShrink: 0
1315
+ },
1316
+ messageInput: {
1317
+ flex: 1,
1318
+ fontSize: 12,
1319
+ padding: "5px 6px",
1320
+ border: "1px solid var(--wp-border-muted)",
1321
+ borderRadius: "var(--wp-radius)",
1322
+ background: "var(--wp-canvas)",
1323
+ color: "var(--wp-text)",
1324
+ minWidth: 0
1325
+ },
1326
+ removeBtn: {
1327
+ border: "none",
1328
+ background: "transparent",
1329
+ color: "var(--wp-danger)",
1330
+ cursor: "pointer",
1331
+ fontSize: 13,
1332
+ flexShrink: 0
1333
+ },
1334
+ addBtn: {
1335
+ fontSize: 12,
1336
+ padding: "6px 12px",
1337
+ background: "var(--wp-surface-muted)",
1338
+ border: "1px solid var(--wp-border-muted)",
1339
+ borderRadius: "var(--wp-radius)",
1340
+ cursor: "pointer",
1341
+ fontWeight: 500,
1342
+ alignSelf: "flex-start",
1343
+ color: "var(--wp-text-secondary)"
1344
+ }
1345
+ };
1030
1346
  function DependsOnInput({
1031
1347
  value,
1032
1348
  onChange,
@@ -1059,17 +1375,17 @@ function DependsOnInput({
1059
1375
  }, []);
1060
1376
  const getLabel = (path) => allPaths.find((p) => p.path === path)?.label ?? path;
1061
1377
  const isExternal = (path) => path.startsWith("$ext.");
1062
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: styles2.container, children: [
1063
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.tags, children: [
1064
- value.map((path) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...styles2.tag, ...isExternal(path) ? styles2.tagExt : {} }, children: [
1378
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: styles3.container, children: [
1379
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.tags, children: [
1380
+ value.map((path) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...styles3.tag, ...isExternal(path) ? styles3.tagExt : {} }, children: [
1065
1381
  getLabel(path),
1066
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles2.tagRemove, onClick: () => remove(path), children: "\u2715" })
1382
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles3.tagRemove, onClick: () => remove(path), children: "\u2715" })
1067
1383
  ] }, path)),
1068
1384
  /* @__PURE__ */ jsxRuntime.jsx(
1069
1385
  "input",
1070
1386
  {
1071
1387
  ref: inputRef,
1072
- style: styles2.input,
1388
+ style: styles3.input,
1073
1389
  placeholder: value.length === 0 ? "Search fields or $ext vars\u2026" : "Add more\u2026",
1074
1390
  value: query,
1075
1391
  onChange: (e) => {
@@ -1080,28 +1396,28 @@ function DependsOnInput({
1080
1396
  }
1081
1397
  )
1082
1398
  ] }),
1083
- open && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.dropdown, children: [
1084
- available.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles2.noResults, children: allPaths.length === 0 ? "No fields available in the tree yet." : "No matching fields." }),
1399
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.dropdown, children: [
1400
+ available.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.noResults, children: allPaths.length === 0 ? "No fields available in the tree yet." : "No matching fields." }),
1085
1401
  available.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
1086
1402
  "button",
1087
1403
  {
1088
- style: styles2.option,
1404
+ style: styles3.option,
1089
1405
  onMouseDown: (e) => {
1090
1406
  e.preventDefault();
1091
1407
  add(p.path);
1092
1408
  },
1093
1409
  children: [
1094
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles2.optionLabel, children: p.label }),
1095
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles2.optionPath, children: p.path })
1410
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles3.optionLabel, children: p.label }),
1411
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles3.optionPath, children: p.path })
1096
1412
  ]
1097
1413
  },
1098
1414
  p.path
1099
1415
  ))
1100
1416
  ] }),
1101
- value.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles2.hint, children: "This field will be blocked until all dependencies have a value." })
1417
+ value.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.hint, children: "This field will be blocked until all dependencies have a value." })
1102
1418
  ] });
1103
1419
  }
1104
- var styles2 = {
1420
+ var styles3 = {
1105
1421
  container: { position: "relative" },
1106
1422
  tags: {
1107
1423
  display: "flex",
@@ -1183,15 +1499,15 @@ function Modal({ title, onClose, children, width = 560 }) {
1183
1499
  document.addEventListener("keydown", handler);
1184
1500
  return () => document.removeEventListener("keydown", handler);
1185
1501
  }, [onClose]);
1186
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles3.panel, width }, onClick: (e) => e.stopPropagation(), children: [
1187
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.header, children: [
1188
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles3.title, children: title }),
1189
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles3.closeBtn, onClick: onClose, children: "\u2715" })
1502
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.overlay, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles4.panel, width }, onClick: (e) => e.stopPropagation(), children: [
1503
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.header, children: [
1504
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.title, children: title }),
1505
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.closeBtn, onClick: onClose, children: "\u2715" })
1190
1506
  ] }),
1191
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.body, children })
1507
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.body, children })
1192
1508
  ] }) });
1193
1509
  }
1194
- var styles3 = {
1510
+ var styles4 = {
1195
1511
  overlay: {
1196
1512
  position: "fixed",
1197
1513
  inset: 0,
@@ -1228,16 +1544,7 @@ var styles3 = {
1228
1544
  },
1229
1545
  body: { overflowY: "auto", padding: 20, color: "var(--wp-text)" }
1230
1546
  };
1231
- var VALIDATION_TYPES = [
1232
- { type: "required", label: "Required", hasValue: false },
1233
- { type: "min", label: "Min value", hasValue: true },
1234
- { type: "max", label: "Max value", hasValue: true },
1235
- { type: "minLength", label: "Min length", hasValue: true },
1236
- { type: "maxLength", label: "Max length", hasValue: true },
1237
- { type: "email", label: "Email format", hasValue: false },
1238
- { type: "url", label: "URL format", hasValue: false },
1239
- { type: "regex", label: "Regex pattern", hasValue: true }
1240
- ];
1547
+ var ENUM_FIELD_TYPES = ["select", "multiselect", "radio"];
1241
1548
  function FieldEditor() {
1242
1549
  const {
1243
1550
  schema,
@@ -1246,85 +1553,117 @@ function FieldEditor() {
1246
1553
  updateField,
1247
1554
  setFieldCondition
1248
1555
  } = useBuilderStore();
1249
- const [newValidationType, setNewValidationType] = react.useState("required");
1556
+ const readOnly = useBuilderReadOnly();
1557
+ const externalEnums = useBuilderExternalEnums();
1250
1558
  const [conditionModalOpen, setConditionModalOpen] = react.useState(false);
1559
+ const [validationModalOpen, setValidationModalOpen] = react.useState(false);
1251
1560
  const step = schema.steps.find((s) => s.id === selectedStepId);
1252
1561
  const field = step?.fields.find((f) => f.id === selectedFieldId);
1253
1562
  if (!field || !step) {
1254
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.empty, children: "Select a field in the middle panel to edit its properties." });
1563
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.empty, children: "Select a field in the middle panel to edit its properties." });
1255
1564
  }
1256
1565
  const validation = field.validation ?? [];
1257
1566
  const isRequired = validation.some((v) => v.type === "required");
1258
1567
  const hasCondition = !!field.visibleWhen;
1259
1568
  const ruleCount = field.visibleWhen?.rules.length ?? 0;
1260
- const updateValidationRule = (index, updates) => {
1261
- const updated = validation.map((v, i) => i === index ? { ...v, ...updates } : v);
1262
- updateField(step.id, field.id, { validation: updated });
1263
- };
1264
- const removeValidationRule = (index) => {
1265
- const updated = validation.filter((_, i) => i !== index);
1266
- updateField(step.id, field.id, { validation: updated.length ? updated : void 0 });
1267
- };
1268
- const addValidationRule = () => {
1269
- const newRule = {
1270
- type: newValidationType,
1271
- message: `${newValidationType} error`
1272
- };
1273
- updateField(step.id, field.id, { validation: [...validation, newRule] });
1569
+ const handleValidationChange = (rules) => {
1570
+ updateField(step.id, field.id, { validation: rules.length ? rules : void 0 });
1274
1571
  };
1275
1572
  const handleDependsOnChange = (paths) => {
1276
1573
  updateField(step.id, field.id, { dependsOn: paths.length ? paths : void 0 });
1277
1574
  };
1278
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.container, children: [
1279
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.header, children: [
1280
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.headerLeft, children: [
1281
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.headerTitle, children: "Field Editor" }),
1282
- !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.optionalBadge, children: "optional" }),
1283
- isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.requiredBadge, children: "required" })
1575
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.container, children: [
1576
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.header, children: [
1577
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.headerLeft, children: [
1578
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.headerTitle, children: "Field Editor" }),
1579
+ !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.optionalBadge, children: "optional" }),
1580
+ isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.requiredBadge, children: "required" })
1284
1581
  ] }),
1285
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.fieldId, children: [
1582
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.fieldId, children: [
1286
1583
  "id: ",
1287
1584
  field.id
1288
1585
  ] })
1289
1586
  ] }),
1290
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.body, children: [
1291
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1292
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Label" }),
1587
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.body, children: [
1588
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.group, children: [
1589
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Label" }),
1293
1590
  /* @__PURE__ */ jsxRuntime.jsx(
1294
1591
  "input",
1295
1592
  {
1296
- style: styles4.input,
1593
+ style: styles5.input,
1297
1594
  value: field.label,
1298
1595
  onChange: (e) => updateField(step.id, field.id, { label: e.target.value })
1299
1596
  }
1300
1597
  )
1301
1598
  ] }),
1302
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1303
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Placeholder" }),
1599
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.group, children: [
1600
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Placeholder" }),
1304
1601
  /* @__PURE__ */ jsxRuntime.jsx(
1305
1602
  "input",
1306
1603
  {
1307
- style: styles4.input,
1604
+ style: styles5.input,
1308
1605
  value: field.placeholder ?? "",
1309
1606
  placeholder: "Optional",
1310
1607
  onChange: (e) => updateField(step.id, field.id, { placeholder: e.target.value || void 0 })
1311
1608
  }
1312
1609
  )
1313
1610
  ] }),
1314
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1315
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Default value" }),
1611
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.group, children: [
1612
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Default value" }),
1316
1613
  /* @__PURE__ */ jsxRuntime.jsx(
1317
1614
  "input",
1318
1615
  {
1319
- style: styles4.input,
1616
+ style: styles5.input,
1320
1617
  value: field.defaultValue != null ? String(field.defaultValue) : "",
1321
1618
  placeholder: "Optional",
1322
1619
  onChange: (e) => updateField(step.id, field.id, { defaultValue: e.target.value || void 0 })
1323
1620
  }
1324
1621
  )
1325
1622
  ] }),
1326
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1327
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Depends on" }),
1623
+ ENUM_FIELD_TYPES.includes(field.type) && externalEnums.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.group, children: [
1624
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Options source" }),
1625
+ /* @__PURE__ */ jsxRuntime.jsxs(
1626
+ "select",
1627
+ {
1628
+ style: styles5.input,
1629
+ disabled: readOnly,
1630
+ value: field.externalEnumId ?? "",
1631
+ onChange: (e) => {
1632
+ const enumId = e.target.value || void 0;
1633
+ updateField(step.id, field.id, {
1634
+ externalEnumId: enumId,
1635
+ // Clear hardcoded options when switching to an enum
1636
+ options: enumId ? void 0 : field.options
1637
+ });
1638
+ },
1639
+ children: [
1640
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014 Hardcoded options \u2014" }),
1641
+ externalEnums.map((en) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: en.id, children: [
1642
+ en.label,
1643
+ " (",
1644
+ en.values.length,
1645
+ " items)"
1646
+ ] }, en.id))
1647
+ ]
1648
+ }
1649
+ ),
1650
+ field.externalEnumId && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.enumInfo, children: (() => {
1651
+ const en = externalEnums.find((e) => e.id === field.externalEnumId);
1652
+ return en ? /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.enumBadge, children: [
1653
+ "\u229E ",
1654
+ en.label,
1655
+ " \xB7 ",
1656
+ en.values.length,
1657
+ " options"
1658
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.enumMissing, children: [
1659
+ '\u26A0 Enum "',
1660
+ field.externalEnumId,
1661
+ '" not found'
1662
+ ] });
1663
+ })() })
1664
+ ] }),
1665
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.group, children: [
1666
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles5.label, children: "Depends on" }),
1328
1667
  /* @__PURE__ */ jsxRuntime.jsx(
1329
1668
  DependsOnInput,
1330
1669
  {
@@ -1335,92 +1674,79 @@ function FieldEditor() {
1335
1674
  }
1336
1675
  )
1337
1676
  ] }),
1338
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
1339
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionRow, children: [
1340
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionInfo, children: [
1341
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.label, children: "Visibility condition" }),
1342
- hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionSummary, children: [
1343
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles4.conditionBadge, children: [
1677
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.divider }),
1678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionRow, children: [
1679
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionInfo, children: [
1680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.label, children: "Visibility condition" }),
1681
+ hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionSummary, children: [
1682
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.conditionBadge, children: [
1344
1683
  ruleCount,
1345
1684
  " rule",
1346
1685
  ruleCount !== 1 ? "s" : "",
1347
1686
  " \xB7 ",
1348
1687
  field.visibleWhen.combinator.toUpperCase()
1349
1688
  ] }),
1350
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.conditionDesc, children: "Field is conditional" })
1351
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.conditionNone, children: "Always visible" })
1689
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.conditionDesc, children: "Field is conditional" })
1690
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.conditionNone, children: "Always visible" })
1352
1691
  ] }),
1353
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionActions, children: [
1354
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.editConditionBtn, onClick: () => setConditionModalOpen(true), children: hasCondition ? "Edit" : "Add" }),
1692
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionActions, children: [
1693
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.editConditionBtn, onClick: () => setConditionModalOpen(true), children: hasCondition ? "Edit" : "Add" }),
1355
1694
  hasCondition && /* @__PURE__ */ jsxRuntime.jsx(
1356
1695
  "button",
1357
1696
  {
1358
- style: styles4.clearConditionBtn,
1697
+ style: styles5.clearConditionBtn,
1359
1698
  onClick: () => setFieldCondition(step.id, field.id, void 0),
1360
1699
  children: "Clear"
1361
1700
  }
1362
1701
  )
1363
1702
  ] })
1364
1703
  ] }),
1365
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
1366
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.sectionTitle, children: [
1367
- "Validation",
1368
- !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.optionalHint, children: '\u2014 no "required" rule \u2192 field is optional' })
1369
- ] }),
1370
- validation.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.noRules, children: "No rules \xB7 field is optional by default." }),
1371
- validation.map((rule, index) => {
1372
- const def = VALIDATION_TYPES.find((vt) => vt.type === rule.type);
1373
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleCard, children: [
1374
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleHeader, children: [
1375
- /* @__PURE__ */ jsxRuntime.jsx(
1376
- "span",
1377
- {
1378
- style: {
1379
- ...styles4.ruleBadge,
1380
- ...rule.type === "required" ? styles4.requiredRuleBadge : {}
1381
- },
1382
- children: rule.type
1383
- }
1384
- ),
1385
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.removeRuleBtn, onClick: () => removeValidationRule(index), children: "\u2715" })
1386
- ] }),
1387
- def?.hasValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleRow, children: [
1388
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.ruleLabel, children: "Value" }),
1389
- /* @__PURE__ */ jsxRuntime.jsx(
1390
- "input",
1391
- {
1392
- style: styles4.ruleInput,
1393
- value: rule.value != null ? String(rule.value) : "",
1394
- onChange: (e) => updateValidationRule(index, { value: e.target.value })
1395
- }
1396
- )
1397
- ] }),
1398
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleRow, children: [
1399
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.ruleLabel, children: "Error message" }),
1400
- /* @__PURE__ */ jsxRuntime.jsx(
1401
- "input",
1402
- {
1403
- style: styles4.ruleInput,
1404
- value: rule.message,
1405
- onChange: (e) => updateValidationRule(index, { message: e.target.value })
1406
- }
1407
- )
1408
- ] })
1409
- ] }, index);
1410
- }),
1411
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.addRule, children: [
1412
- /* @__PURE__ */ jsxRuntime.jsx(
1413
- "select",
1414
- {
1415
- style: styles4.ruleSelect,
1416
- value: newValidationType,
1417
- onChange: (e) => setNewValidationType(e.target.value),
1418
- children: VALIDATION_TYPES.map((vt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: vt.type, children: vt.label }, vt.type))
1419
- }
1420
- ),
1421
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.addRuleBtn, onClick: addValidationRule, children: "+ Add rule" })
1704
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.divider }),
1705
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionRow, children: [
1706
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionInfo, children: [
1707
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.label, children: "Validation" }),
1708
+ validation.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionSummary, children: [
1709
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.validationBadge, children: [
1710
+ validation.length,
1711
+ " rule",
1712
+ validation.length !== 1 ? "s" : "",
1713
+ isRequired ? " \xB7 required" : ""
1714
+ ] }),
1715
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.conditionDesc, children: validation.map((r) => r.type).join(", ") })
1716
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.conditionNone, children: "No rules \xB7 field is optional" })
1717
+ ] }),
1718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.conditionActions, children: [
1719
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.editConditionBtn, onClick: () => setValidationModalOpen(true), children: validation.length > 0 ? "Edit" : "Add" }),
1720
+ validation.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1721
+ "button",
1722
+ {
1723
+ style: styles5.clearConditionBtn,
1724
+ onClick: () => updateField(step.id, field.id, { validation: void 0 }),
1725
+ children: "Clear"
1726
+ }
1727
+ )
1728
+ ] })
1422
1729
  ] })
1423
1730
  ] }),
1731
+ validationModalOpen && /* @__PURE__ */ jsxRuntime.jsxs(
1732
+ Modal,
1733
+ {
1734
+ title: `Validation \u2014 "${field.label}"`,
1735
+ onClose: () => setValidationModalOpen(false),
1736
+ width: 680,
1737
+ children: [
1738
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles5.modalHint, children: "Define validation rules for this field. All rules must pass for the field to be valid." }),
1739
+ /* @__PURE__ */ jsxRuntime.jsx(
1740
+ ValidationBuilder,
1741
+ {
1742
+ value: validation,
1743
+ onChange: handleValidationChange
1744
+ }
1745
+ ),
1746
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.modalCloseBtn, onClick: () => setValidationModalOpen(false), children: "Done" }) })
1747
+ ]
1748
+ }
1749
+ ),
1424
1750
  conditionModalOpen && /* @__PURE__ */ jsxRuntime.jsxs(
1425
1751
  Modal,
1426
1752
  {
@@ -1428,7 +1754,7 @@ function FieldEditor() {
1428
1754
  onClose: () => setConditionModalOpen(false),
1429
1755
  width: 620,
1430
1756
  children: [
1431
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles4.modalHint, children: "Define when this field is visible within its step." }),
1757
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles5.modalHint, children: "Define when this field is visible within its step." }),
1432
1758
  /* @__PURE__ */ jsxRuntime.jsx(
1433
1759
  ConditionBuilder,
1434
1760
  {
@@ -1438,13 +1764,13 @@ function FieldEditor() {
1438
1764
  excludeFieldId: field.id
1439
1765
  }
1440
1766
  ),
1441
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.modalCloseBtn, onClick: () => setConditionModalOpen(false), children: "Done" }) })
1767
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.modalCloseBtn, onClick: () => setConditionModalOpen(false), children: "Done" }) })
1442
1768
  ]
1443
1769
  }
1444
1770
  )
1445
1771
  ] });
1446
1772
  }
1447
- var styles4 = {
1773
+ var styles5 = {
1448
1774
  container: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" },
1449
1775
  empty: {
1450
1776
  display: "flex",
@@ -1528,60 +1854,30 @@ var styles4 = {
1528
1854
  borderRadius: "var(--wp-radius)",
1529
1855
  cursor: "pointer"
1530
1856
  },
1531
- sectionTitle: { fontSize: 12, fontWeight: 700, color: "var(--wp-text-secondary)", textTransform: "uppercase", letterSpacing: "0.05em" },
1532
- optionalHint: { fontSize: 10, color: "var(--wp-text-subtle)", fontWeight: 400, textTransform: "none", letterSpacing: 0 },
1533
- noRules: { fontSize: 12, color: "var(--wp-text-subtle)" },
1534
- ruleCard: {
1535
- background: "var(--wp-surface)",
1536
- border: "1px solid var(--wp-border)",
1537
- borderRadius: "var(--wp-radius-lg)",
1538
- padding: 10,
1539
- display: "flex",
1540
- flexDirection: "column",
1541
- gap: 8
1542
- },
1543
- ruleHeader: { display: "flex", justifyContent: "space-between", alignItems: "center" },
1544
- ruleBadge: {
1857
+ validationBadge: {
1545
1858
  fontSize: 11,
1546
1859
  fontWeight: 700,
1547
- color: "var(--wp-primary-dark)",
1548
1860
  background: "var(--wp-primary-bg)",
1861
+ color: "var(--wp-primary-dark)",
1549
1862
  padding: "2px 8px",
1550
1863
  borderRadius: 4
1551
1864
  },
1552
- requiredRuleBadge: { background: "var(--wp-danger-bg-strong)", color: "var(--wp-danger)" },
1553
- removeRuleBtn: { border: "none", background: "transparent", color: "var(--wp-danger)", cursor: "pointer", fontSize: 12 },
1554
- ruleRow: { display: "flex", flexDirection: "column", gap: 3 },
1555
- ruleLabel: { fontSize: 10, fontWeight: 600, color: "var(--wp-text-subtle)", textTransform: "uppercase" },
1556
- ruleInput: {
1557
- fontSize: 12,
1558
- padding: "4px 6px",
1559
- border: "1px solid var(--wp-border-muted)",
1560
- borderRadius: 4,
1561
- outline: "none",
1562
- background: "var(--wp-canvas)",
1563
- color: "var(--wp-text)"
1564
- },
1565
- addRule: { display: "flex", gap: 8, alignItems: "center" },
1566
- ruleSelect: {
1567
- flex: 1,
1568
- fontSize: 12,
1569
- padding: "5px 6px",
1570
- border: "1px solid var(--wp-border-muted)",
1571
- borderRadius: "var(--wp-radius)",
1572
- background: "var(--wp-canvas)",
1573
- color: "var(--wp-text)"
1865
+ enumInfo: { marginTop: 4 },
1866
+ enumBadge: {
1867
+ fontSize: 11,
1868
+ fontWeight: 600,
1869
+ padding: "2px 8px",
1870
+ background: "var(--wp-info-bg)",
1871
+ color: "var(--wp-info-text)",
1872
+ borderRadius: 4
1574
1873
  },
1575
- addRuleBtn: {
1576
- fontSize: 12,
1577
- padding: "5px 10px",
1578
- background: "var(--wp-surface-muted)",
1579
- border: "1px solid var(--wp-border-muted)",
1580
- borderRadius: "var(--wp-radius)",
1581
- cursor: "pointer",
1582
- fontWeight: 500,
1583
- whiteSpace: "nowrap",
1584
- color: "var(--wp-text-secondary)"
1874
+ enumMissing: {
1875
+ fontSize: 11,
1876
+ fontWeight: 600,
1877
+ padding: "2px 8px",
1878
+ background: "var(--wp-warning-bg)",
1879
+ color: "var(--wp-warning)",
1880
+ borderRadius: 4
1585
1881
  },
1586
1882
  modalHint: { fontSize: 13, color: "var(--wp-text-muted)", marginBottom: 16, marginTop: 0 },
1587
1883
  modalFooter: { marginTop: 20, display: "flex", justifyContent: "flex-end" },
@@ -1715,10 +2011,14 @@ function FieldList() {
1715
2011
  selectedFieldId,
1716
2012
  addField,
1717
2013
  removeField,
2014
+ duplicateField,
1718
2015
  updateField,
1719
2016
  selectField,
1720
2017
  reorderFields
1721
2018
  } = useBuilderStore();
2019
+ const readOnly = useBuilderReadOnly();
2020
+ const appCustomTypes = useBuilderCustomTypes();
2021
+ const externalEnums = useBuilderExternalEnums();
1722
2022
  const [moveError, setMoveError] = react.useState(null);
1723
2023
  const step = schema.steps.find((s) => s.id === selectedStepId);
1724
2024
  const allDependencyTargets = /* @__PURE__ */ new Set();
@@ -1730,7 +2030,7 @@ function FieldList() {
1730
2030
  }
1731
2031
  }
1732
2032
  if (!step) {
1733
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.empty, children: "Select a step on the left to manage its fields." });
2033
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.empty, children: "Select a step on the left to manage its fields." });
1734
2034
  }
1735
2035
  const tryMove = (fromIndex, toIndex) => {
1736
2036
  const check = isFieldMoveValid(step.fields, step.id, fromIndex, toIndex);
@@ -1742,30 +2042,31 @@ function FieldList() {
1742
2042
  setMoveError(null);
1743
2043
  reorderFields(step.id, fromIndex, toIndex);
1744
2044
  };
1745
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.container, children: [
1746
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.header, children: [
2045
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.container, children: [
2046
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.header, children: [
1747
2047
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1748
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.stepTitle, children: step.title }),
1749
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.stepSub, children: [
2048
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.stepTitle, children: step.title }),
2049
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.stepSub, children: [
1750
2050
  step.fields.length,
1751
2051
  " field",
1752
2052
  step.fields.length !== 1 ? "s" : ""
1753
2053
  ] })
1754
2054
  ] }),
1755
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.addBtn, onClick: () => addField(step.id), children: "+ Add field" })
2055
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles6.addBtn, onClick: () => addField(step.id), children: "+ Add field" })
1756
2056
  ] }),
1757
- moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.errorBanner, children: [
2057
+ moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.errorBanner, children: [
1758
2058
  /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u26A0" }),
1759
2059
  " ",
1760
2060
  moveError
1761
2061
  ] }),
1762
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.list, children: [
1763
- step.fields.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.emptyFields, children: 'No fields yet. Click "Add field" to start.' }),
2062
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.list, children: [
2063
+ step.fields.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.emptyFields, children: 'No fields yet. Click "Add field" to start.' }),
1764
2064
  step.fields.map((field, index) => {
1765
2065
  const isSelected = field.id === selectedFieldId;
1766
2066
  const isRequired = field.validation?.some((v) => v.type === "required") ?? false;
1767
2067
  const hasCondition = !!field.visibleWhen;
1768
2068
  const hasDeps = (field.dependsOn?.length ?? 0) > 0;
2069
+ const enumDef = field.externalEnumId ? externalEnums.find((e) => e.id === field.externalEnumId) : void 0;
1769
2070
  const isUsedAsDep = allDependencyTargets.has(`${step.id}.${field.id}`);
1770
2071
  const canMoveUp = index > 0 && isFieldMoveValid(step.fields, step.id, index, index - 1).valid;
1771
2072
  const canMoveDown = index < step.fields.length - 1 && isFieldMoveValid(step.fields, step.id, index, index + 1).valid;
@@ -1779,29 +2080,45 @@ function FieldList() {
1779
2080
  return /* @__PURE__ */ jsxRuntime.jsxs(
1780
2081
  "div",
1781
2082
  {
1782
- style: { ...styles5.card, ...isSelected ? styles5.cardSelected : {} },
2083
+ style: { ...styles6.card, ...isSelected ? styles6.cardSelected : {} },
1783
2084
  onClick: () => selectField(field.id),
1784
2085
  children: [
1785
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardTop, children: [
1786
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardLeft, children: [
1787
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.typeBadge, children: field.type }),
1788
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.fieldLabel, children: field.label })
2086
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.cardTop, children: [
2087
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.cardLeft, children: [
2088
+ (() => {
2089
+ const ct = appCustomTypes.find((c) => c.id === field.type);
2090
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles6.typeBadge, ...ct ? styles6.typeBadgeCustom : {} }, children: ct ? `${ct.icon ? ct.icon + " " : ""}${ct.label}` : field.type });
2091
+ })(),
2092
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.fieldLabel, children: field.label })
1789
2093
  ] }),
1790
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardRight, children: [
1791
- /* @__PURE__ */ jsxRuntime.jsx(
2094
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.cardRight, children: [
2095
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs(
1792
2096
  "select",
1793
2097
  {
1794
- style: styles5.typeSelect,
2098
+ style: styles6.typeSelect,
1795
2099
  value: field.type,
1796
2100
  onClick: (e) => e.stopPropagation(),
1797
- onChange: (e) => updateField(step.id, field.id, { type: e.target.value }),
1798
- children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t))
2101
+ onChange: (e) => {
2102
+ const newType = e.target.value;
2103
+ const customType = appCustomTypes.find((ct) => ct.id === newType);
2104
+ updateField(step.id, field.id, {
2105
+ type: newType,
2106
+ ...customType?.defaultValidation ? { validation: customType.defaultValidation } : {}
2107
+ });
2108
+ },
2109
+ children: [
2110
+ FIELD_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t)),
2111
+ appCustomTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("optgroup", { label: "Custom", children: appCustomTypes.map((ct) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: ct.id, children: [
2112
+ ct.icon ? `${ct.icon} ` : "",
2113
+ ct.label
2114
+ ] }, ct.id)) })
2115
+ ]
1799
2116
  }
1800
2117
  ),
1801
- index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2118
+ !readOnly && index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1802
2119
  "button",
1803
2120
  {
1804
- style: { ...styles5.iconBtn, ...canMoveUp ? {} : styles5.iconBtnBlocked },
2121
+ style: { ...styles6.iconBtn, ...canMoveUp ? {} : styles6.iconBtnBlocked },
1805
2122
  title: canMoveUp ? "Move up" : "Can't move \u2014 dependency order required",
1806
2123
  onClick: (e) => {
1807
2124
  e.stopPropagation();
@@ -1810,10 +2127,10 @@ function FieldList() {
1810
2127
  children: "\u2191"
1811
2128
  }
1812
2129
  ),
1813
- index < step.fields.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
2130
+ !readOnly && index < step.fields.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
1814
2131
  "button",
1815
2132
  {
1816
- style: { ...styles5.iconBtn, ...canMoveDown ? {} : styles5.iconBtnBlocked },
2133
+ style: { ...styles6.iconBtn, ...canMoveDown ? {} : styles6.iconBtnBlocked },
1817
2134
  title: canMoveDown ? "Move down" : "Can't move \u2014 dependency order required",
1818
2135
  onClick: (e) => {
1819
2136
  e.stopPropagation();
@@ -1822,10 +2139,22 @@ function FieldList() {
1822
2139
  children: "\u2193"
1823
2140
  }
1824
2141
  ),
1825
- /* @__PURE__ */ jsxRuntime.jsx(
2142
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
1826
2143
  "button",
1827
2144
  {
1828
- style: { ...styles5.iconBtn, color: "var(--wp-danger)" },
2145
+ style: styles6.iconBtn,
2146
+ title: "Duplicate field",
2147
+ onClick: (e) => {
2148
+ e.stopPropagation();
2149
+ duplicateField(step.id, field.id);
2150
+ },
2151
+ children: "\u29C9"
2152
+ }
2153
+ ),
2154
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
2155
+ "button",
2156
+ {
2157
+ style: { ...styles6.iconBtn, color: "var(--wp-danger)" },
1829
2158
  title: "Remove field",
1830
2159
  onClick: (e) => {
1831
2160
  e.stopPropagation();
@@ -1836,23 +2165,27 @@ function FieldList() {
1836
2165
  )
1837
2166
  ] })
1838
2167
  ] }),
1839
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.badges, children: [
1840
- !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeOptional, children: "optional" }),
1841
- isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeRequired, children: "required" }),
1842
- hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeCondition, children: "conditional" }),
1843
- hasDeps && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.badgeDep, children: [
2168
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.badges, children: [
2169
+ !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.badgeOptional, children: "optional" }),
2170
+ isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.badgeRequired, children: "required" }),
2171
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.badgeCondition, children: "conditional" }),
2172
+ hasDeps && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles6.badgeDep, children: [
1844
2173
  "depends on ",
1845
2174
  field.dependsOn.length
1846
2175
  ] }),
1847
- isUsedAsDep && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeUsed, children: "\u2190 dependency" })
2176
+ isUsedAsDep && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.badgeUsed, children: "\u2190 dependency" }),
2177
+ field.externalEnumId && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles6.badgeEnum, children: [
2178
+ "\u229E ",
2179
+ enumDef ? enumDef.label : field.externalEnumId
2180
+ ] })
1848
2181
  ] }),
1849
- intraStepDeps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.depRow, children: [
1850
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depLabel, children: "needs:" }),
1851
- intraStepDeps.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depBadge, children: label }, label))
2182
+ intraStepDeps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.depRow, children: [
2183
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.depLabel, children: "needs:" }),
2184
+ intraStepDeps.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.depBadge, children: label }, label))
1852
2185
  ] }),
1853
- intraStepDependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.depRow, children: [
1854
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depLabelUsed, children: "used by:" }),
1855
- intraStepDependents.map((f) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depBadgeUsed, children: f.label }, f.id))
2186
+ intraStepDependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.depRow, children: [
2187
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.depLabelUsed, children: "used by:" }),
2188
+ intraStepDependents.map((f) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.depBadgeUsed, children: f.label }, f.id))
1856
2189
  ] })
1857
2190
  ]
1858
2191
  },
@@ -1862,7 +2195,7 @@ function FieldList() {
1862
2195
  ] })
1863
2196
  ] });
1864
2197
  }
1865
- var styles5 = {
2198
+ var styles6 = {
1866
2199
  container: { display: "flex", flexDirection: "column", height: "100%" },
1867
2200
  empty: {
1868
2201
  display: "flex",
@@ -1931,6 +2264,10 @@ var styles5 = {
1931
2264
  fontWeight: 600,
1932
2265
  flexShrink: 0
1933
2266
  },
2267
+ typeBadgeCustom: {
2268
+ background: "var(--wp-success-bg)",
2269
+ color: "var(--wp-success)"
2270
+ },
1934
2271
  fieldLabel: {
1935
2272
  fontSize: 13,
1936
2273
  fontWeight: 600,
@@ -2005,6 +2342,14 @@ var styles5 = {
2005
2342
  borderRadius: 3,
2006
2343
  textTransform: "uppercase"
2007
2344
  },
2345
+ badgeEnum: {
2346
+ fontSize: 9,
2347
+ fontWeight: 600,
2348
+ padding: "1px 6px",
2349
+ background: "var(--wp-info-bg)",
2350
+ color: "var(--wp-info-text)",
2351
+ borderRadius: 3
2352
+ },
2008
2353
  depRow: { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 4 },
2009
2354
  depLabel: { fontSize: 10, fontWeight: 600, color: "var(--wp-text-muted)", textTransform: "uppercase" },
2010
2355
  depLabelUsed: { fontSize: 10, fontWeight: 600, color: "var(--wp-success)", textTransform: "uppercase" },
@@ -2025,12 +2370,28 @@ var styles5 = {
2025
2370
  borderRadius: 4
2026
2371
  }
2027
2372
  };
2028
- function PreviewPanel({ store, schema }) {
2373
+ function PreviewPanel({ store, schema, externalEnums }) {
2029
2374
  const [done, setDone] = react.useState(false);
2030
- const { tree, currentStep, progress } = react$1.useWaypoint(store);
2375
+ const { tree, currentStep, progress } = react$1.useWaypoint(store, externalEnums);
2031
2376
  const stepId = currentStep?.definition.id ?? "";
2032
2377
  const { fields, stepData, setFieldValue } = react$1.useWaypointStep(store, stepId);
2033
2378
  const [errors, setErrors] = react.useState({});
2379
+ const extVarDefs = schema.externalVariables ?? [];
2380
+ const [mockVars, setMockVars] = react.useState(() => {
2381
+ const initial = {};
2382
+ for (const v of extVarDefs) {
2383
+ initial[v.id] = v.type === "boolean" ? false : v.type === "number" ? 0 : "";
2384
+ }
2385
+ return initial;
2386
+ });
2387
+ react.useEffect(() => {
2388
+ for (const [varId, value] of Object.entries(mockVars)) {
2389
+ store.getState().setExternalVar(varId, value);
2390
+ }
2391
+ }, [mockVars]);
2392
+ function handleMockVarChange(varId, value) {
2393
+ setMockVars((prev) => ({ ...prev, [varId]: value }));
2394
+ }
2034
2395
  function handleNext() {
2035
2396
  const newErrors = {};
2036
2397
  for (const field of fields) {
@@ -2051,7 +2412,7 @@ function PreviewPanel({ store, schema }) {
2051
2412
  const oldIds = tree.steps.map((s) => s.definition.id).join(",");
2052
2413
  store.getState().setStepData(stepId, stepData);
2053
2414
  const newData = store.getState().data;
2054
- const newTree = core.resolveTree(schema, newData, {});
2415
+ const newTree = core.resolveTree(schema, newData, store.getState().externalVars, externalEnums);
2055
2416
  const newIds = newTree.steps.map((s) => s.definition.id).join(",");
2056
2417
  if (oldIds !== newIds) {
2057
2418
  store.getState().truncateHistoryAt(stepId);
@@ -2069,6 +2430,9 @@ function PreviewPanel({ store, schema }) {
2069
2430
  }
2070
2431
  function handleRestart() {
2071
2432
  store.getState().init(schema);
2433
+ for (const [varId, value] of Object.entries(mockVars)) {
2434
+ store.getState().setExternalVar(varId, value);
2435
+ }
2072
2436
  setDone(false);
2073
2437
  setErrors({});
2074
2438
  }
@@ -2076,39 +2440,59 @@ function PreviewPanel({ store, schema }) {
2076
2440
  (s) => s.definition.id === currentStep?.definition.id
2077
2441
  );
2078
2442
  if (done) {
2079
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.panel, children: [
2080
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.leftCol, children: /* @__PURE__ */ jsxRuntime.jsx(
2443
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.panel, children: [
2444
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.leftCol, children: [
2445
+ /* @__PURE__ */ jsxRuntime.jsx(
2446
+ StepList,
2447
+ {
2448
+ tree,
2449
+ currentIdx,
2450
+ onSelect: (id) => store.getState().setCurrentStep(id)
2451
+ }
2452
+ ),
2453
+ extVarDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2454
+ MockVarPanel,
2455
+ {
2456
+ extVarDefs,
2457
+ mockVars,
2458
+ onChange: handleMockVarChange
2459
+ }
2460
+ )
2461
+ ] }),
2462
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.divider }),
2463
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.doneScreen, children: [
2464
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.doneIcon, children: "\u2713" }),
2465
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.doneTitle, children: "Parcours termin\xE9 !" }),
2466
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles7.doneText, children: "Toutes les \xE9tapes ont \xE9t\xE9 compl\xE9t\xE9es avec succ\xE8s." }),
2467
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles7.primaryBtn, onClick: handleRestart, children: "Recommencer" })
2468
+ ] }) })
2469
+ ] });
2470
+ }
2471
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.panel, children: [
2472
+ /* @__PURE__ */ jsxRuntime.jsx(devtools.DevPanel, { store }),
2473
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.leftCol, children: [
2474
+ /* @__PURE__ */ jsxRuntime.jsx(
2081
2475
  StepList,
2082
2476
  {
2083
2477
  tree,
2084
2478
  currentIdx,
2085
2479
  onSelect: (id) => store.getState().setCurrentStep(id)
2086
2480
  }
2087
- ) }),
2088
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.divider }),
2089
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.doneScreen, children: [
2090
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.doneIcon, children: "\u2713" }),
2091
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.doneTitle, children: "Parcours termin\xE9 !" }),
2092
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.doneText, children: "Toutes les \xE9tapes ont \xE9t\xE9 compl\xE9t\xE9es avec succ\xE8s." }),
2093
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles6.primaryBtn, onClick: handleRestart, children: "Recommencer" })
2094
- ] }) })
2095
- ] });
2096
- }
2097
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.panel, children: [
2098
- /* @__PURE__ */ jsxRuntime.jsx(devtools.DevPanel, { store }),
2099
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.leftCol, children: /* @__PURE__ */ jsxRuntime.jsx(
2100
- StepList,
2101
- {
2102
- tree,
2103
- currentIdx,
2104
- onSelect: (id) => store.getState().setCurrentStep(id)
2105
- }
2106
- ) }),
2107
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.divider }),
2108
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.stepRenderer, children: [
2109
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.progressTrack, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles6.progressFill, width: `${progress}%` } }) }),
2110
- /* @__PURE__ */ jsxRuntime.jsx("h2", { style: styles6.stepTitle, children: currentStep?.definition.title ?? "" }),
2111
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.fieldsContainer, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
2481
+ ),
2482
+ extVarDefs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2483
+ MockVarPanel,
2484
+ {
2485
+ extVarDefs,
2486
+ mockVars,
2487
+ onChange: handleMockVarChange
2488
+ }
2489
+ )
2490
+ ] }),
2491
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.divider }),
2492
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.stepRenderer, children: [
2493
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.progressTrack, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles7.progressFill, width: `${progress}%` } }) }),
2494
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: styles7.stepTitle, children: currentStep?.definition.title ?? "" }),
2495
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.fieldsContainer, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
2112
2496
  FieldRenderer,
2113
2497
  {
2114
2498
  field,
@@ -2127,9 +2511,9 @@ function PreviewPanel({ store, schema }) {
2127
2511
  },
2128
2512
  field.definition.id
2129
2513
  )) }),
2130
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.navRow, children: [
2131
- currentIdx > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles6.secondaryBtn, onClick: handlePrev, children: "\u2190 Pr\xE9c\xE9dent" }),
2132
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles6.primaryBtn, marginLeft: "auto" }, onClick: handleNext, children: core.getNextStep(tree.steps, stepId) ? "Continuer \u2192" : "Terminer \u2713" })
2514
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.navRow, children: [
2515
+ currentIdx > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles7.secondaryBtn, onClick: handlePrev, children: "\u2190 Pr\xE9c\xE9dent" }),
2516
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles7.primaryBtn, marginLeft: "auto" }, onClick: handleNext, children: core.getNextStep(tree.steps, stepId) ? "Continuer \u2192" : "Terminer \u2713" })
2133
2517
  ] })
2134
2518
  ] }) })
2135
2519
  ] });
@@ -2139,8 +2523,8 @@ function StepList({ tree, currentIdx, onSelect }) {
2139
2523
  ...tree.steps.map((s) => ({ ...s, hidden: false })),
2140
2524
  ...tree.hiddenSteps.map((s) => ({ ...s, hidden: true }))
2141
2525
  ];
2142
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.stepList, children: [
2143
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.stepListTitle, children: "\xC9tapes" }),
2526
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.stepList, children: [
2527
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.stepListTitle, children: "\xC9tapes" }),
2144
2528
  allSteps.map((step) => {
2145
2529
  const isVisible = !step.hidden;
2146
2530
  const visIdx = tree.steps.findIndex((s) => s.definition.id === step.definition.id);
@@ -2154,23 +2538,23 @@ function StepList({ tree, currentIdx, onSelect }) {
2154
2538
  "div",
2155
2539
  {
2156
2540
  style: {
2157
- ...styles6.stepItem,
2158
- ...status === "current" ? styles6.stepItemCurrent : {},
2159
- ...status === "hidden" ? styles6.stepItemHidden : {},
2541
+ ...styles7.stepItem,
2542
+ ...status === "current" ? styles7.stepItemCurrent : {},
2543
+ ...status === "hidden" ? styles7.stepItemHidden : {},
2160
2544
  cursor: status === "done" ? "pointer" : "default"
2161
2545
  },
2162
2546
  onClick: () => {
2163
2547
  if (status === "done") onSelect(step.definition.id);
2164
2548
  },
2165
2549
  children: [
2166
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles6.stepStatus, children: [
2550
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles7.stepStatus, children: [
2167
2551
  status === "done" && "\u2713",
2168
2552
  status === "current" && "\u2192",
2169
2553
  status === "upcoming" && "\u25CB",
2170
2554
  status === "hidden" && "\u2013"
2171
2555
  ] }),
2172
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.stepName, children: step.definition.title }),
2173
- status === "hidden" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.hiddenBadge, children: "hidden" })
2556
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.stepName, children: step.definition.title }),
2557
+ status === "hidden" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.hiddenBadge, children: "hidden" })
2174
2558
  ]
2175
2559
  },
2176
2560
  step.definition.id
@@ -2178,13 +2562,51 @@ function StepList({ tree, currentIdx, onSelect }) {
2178
2562
  })
2179
2563
  ] });
2180
2564
  }
2565
+ function MockVarPanel({ extVarDefs, mockVars, onChange }) {
2566
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.mockPanel, children: [
2567
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.mockPanelTitle, children: [
2568
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u26A1 External Variables" }),
2569
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.mockPanelHint, children: "mock values" })
2570
+ ] }),
2571
+ extVarDefs.map((v) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.mockVarRow, children: [
2572
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.mockVarLabel, children: [
2573
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles7.mockVarId, children: [
2574
+ "$",
2575
+ `ext.${v.id}`
2576
+ ] }),
2577
+ v.blocking && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.mockBlockingBadge, children: "!" })
2578
+ ] }),
2579
+ v.type === "boolean" ? /* @__PURE__ */ jsxRuntime.jsxs("label", { style: styles7.mockCheckRow, children: [
2580
+ /* @__PURE__ */ jsxRuntime.jsx(
2581
+ "input",
2582
+ {
2583
+ type: "checkbox",
2584
+ checked: Boolean(mockVars[v.id]),
2585
+ onChange: (e) => onChange(v.id, e.target.checked)
2586
+ }
2587
+ ),
2588
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 11, color: "var(--wp-text-muted)" }, children: String(mockVars[v.id]) })
2589
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
2590
+ "input",
2591
+ {
2592
+ style: styles7.mockInput,
2593
+ type: v.type === "number" ? "number" : "text",
2594
+ value: String(mockVars[v.id] ?? ""),
2595
+ placeholder: v.label,
2596
+ onChange: (e) => onChange(v.id, v.type === "number" ? Number(e.target.value) : e.target.value)
2597
+ }
2598
+ )
2599
+ ] }, v.id))
2600
+ ] });
2601
+ }
2181
2602
  function FieldRenderer({ field, value, error, onChange }) {
2182
2603
  const { definition } = field;
2183
- const inputStyle2 = { ...styles6.input, ...error ? styles6.inputError : {} };
2184
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.fieldGroup, children: [
2185
- /* @__PURE__ */ jsxRuntime.jsxs("label", { style: styles6.label, children: [
2604
+ const options = field.resolvedOptions ?? definition.options ?? [];
2605
+ const inputStyle2 = { ...styles7.input, ...error ? styles7.inputError : {} };
2606
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.fieldGroup, children: [
2607
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: styles7.label, children: [
2186
2608
  definition.label,
2187
- definition.validation?.some((r) => r.type === "required") && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.required, children: " *" })
2609
+ definition.validation?.some((r) => r.type === "required") && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.required, children: " *" })
2188
2610
  ] }),
2189
2611
  (definition.type === "text" || definition.type === "email" || definition.type === "tel" || definition.type === "password" || definition.type === "url" || definition.type === "number" || definition.type === "date") && /* @__PURE__ */ jsxRuntime.jsx(
2190
2612
  "input",
@@ -2213,7 +2635,7 @@ function FieldRenderer({ field, value, error, onChange }) {
2213
2635
  onChange: (e) => onChange(e.target.value),
2214
2636
  children: [
2215
2637
  /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014 Choisir \u2014" }),
2216
- definition.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2638
+ options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2217
2639
  ]
2218
2640
  }
2219
2641
  ),
@@ -2227,10 +2649,10 @@ function FieldRenderer({ field, value, error, onChange }) {
2227
2649
  const selected = Array.from(e.target.selectedOptions).map((o) => o.value);
2228
2650
  onChange(selected);
2229
2651
  },
2230
- children: definition.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2652
+ children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2231
2653
  }
2232
2654
  ),
2233
- definition.type === "radio" && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: definition.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer", fontSize: 13 }, children: [
2655
+ definition.type === "radio" && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer", fontSize: 13 }, children: [
2234
2656
  /* @__PURE__ */ jsxRuntime.jsx(
2235
2657
  "input",
2236
2658
  {
@@ -2254,10 +2676,10 @@ function FieldRenderer({ field, value, error, onChange }) {
2254
2676
  ),
2255
2677
  definition.placeholder ?? definition.label
2256
2678
  ] }),
2257
- error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.errorMsg, children: error })
2679
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.errorMsg, children: error })
2258
2680
  ] });
2259
2681
  }
2260
- var styles6 = {
2682
+ var styles7 = {
2261
2683
  panel: {
2262
2684
  display: "flex",
2263
2685
  flex: 1,
@@ -2426,6 +2848,80 @@ var styles6 = {
2426
2848
  letterSpacing: "0.3px",
2427
2849
  flexShrink: 0
2428
2850
  },
2851
+ // Mock var panel
2852
+ mockPanel: {
2853
+ borderTop: "1px solid var(--wp-border)",
2854
+ padding: "12px",
2855
+ display: "flex",
2856
+ flexDirection: "column",
2857
+ gap: 8
2858
+ },
2859
+ mockPanelTitle: {
2860
+ display: "flex",
2861
+ alignItems: "center",
2862
+ justifyContent: "space-between",
2863
+ fontSize: 11,
2864
+ fontWeight: 700,
2865
+ color: "var(--wp-text-muted)",
2866
+ textTransform: "uppercase",
2867
+ letterSpacing: "0.5px",
2868
+ marginBottom: 4
2869
+ },
2870
+ mockPanelHint: {
2871
+ fontSize: 9,
2872
+ fontWeight: 500,
2873
+ color: "var(--wp-warning)",
2874
+ textTransform: "none",
2875
+ background: "var(--wp-warning-bg)",
2876
+ padding: "1px 5px",
2877
+ borderRadius: 4
2878
+ },
2879
+ mockVarRow: {
2880
+ display: "flex",
2881
+ flexDirection: "column",
2882
+ gap: 3
2883
+ },
2884
+ mockVarLabel: {
2885
+ display: "flex",
2886
+ alignItems: "center",
2887
+ gap: 4
2888
+ },
2889
+ mockVarId: {
2890
+ fontSize: 10,
2891
+ fontFamily: "monospace",
2892
+ fontWeight: 600,
2893
+ color: "var(--wp-text-secondary)"
2894
+ },
2895
+ mockBlockingBadge: {
2896
+ fontSize: 9,
2897
+ fontWeight: 700,
2898
+ width: 13,
2899
+ height: 13,
2900
+ borderRadius: "50%",
2901
+ background: "var(--wp-danger-bg-strong)",
2902
+ color: "var(--wp-danger)",
2903
+ display: "flex",
2904
+ alignItems: "center",
2905
+ justifyContent: "center",
2906
+ flexShrink: 0
2907
+ },
2908
+ mockInput: {
2909
+ fontSize: 11,
2910
+ padding: "4px 6px",
2911
+ border: "1px solid var(--wp-border-muted)",
2912
+ borderRadius: "var(--wp-radius)",
2913
+ background: "var(--wp-canvas)",
2914
+ color: "var(--wp-text)",
2915
+ outline: "none",
2916
+ width: "100%",
2917
+ boxSizing: "border-box"
2918
+ },
2919
+ mockCheckRow: {
2920
+ display: "flex",
2921
+ alignItems: "center",
2922
+ gap: 6,
2923
+ cursor: "pointer"
2924
+ },
2429
2925
  // Done screen
2430
2926
  doneScreen: {
2431
2927
  display: "flex",
@@ -2462,83 +2958,87 @@ var styles6 = {
2462
2958
  };
2463
2959
  function StepEditor() {
2464
2960
  const { schema, selectedStepId, updateStep, setStepCondition } = useBuilderStore();
2961
+ const readOnly = useBuilderReadOnly();
2465
2962
  const [conditionModalOpen, setConditionModalOpen] = react.useState(false);
2466
2963
  const step = schema.steps.find((s) => s.id === selectedStepId);
2467
2964
  if (!step) {
2468
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.empty, children: "Select a step to configure its properties." });
2965
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.empty, children: "Select a step to configure its properties." });
2469
2966
  }
2470
2967
  const hasCondition = !!step.visibleWhen;
2471
2968
  const ruleCount = step.visibleWhen?.rules.length ?? 0;
2472
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.container, children: [
2473
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.header, children: [
2474
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.headerTitle, children: "Step Config" }),
2475
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.stepId, children: [
2969
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.container, children: [
2970
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.header, children: [
2971
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.headerTitle, children: "Step Config" }),
2972
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.stepId, children: [
2476
2973
  "id: ",
2477
2974
  step.id
2478
2975
  ] })
2479
2976
  ] }),
2480
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.body, children: [
2481
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.group, children: [
2482
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles7.label, children: "Title" }),
2977
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.body, children: [
2978
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.group, children: [
2979
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles8.label, children: "Title" }),
2483
2980
  /* @__PURE__ */ jsxRuntime.jsx(
2484
2981
  "input",
2485
2982
  {
2486
- style: styles7.input,
2983
+ style: styles8.input,
2487
2984
  value: step.title,
2488
2985
  placeholder: "Step title",
2489
- onChange: (e) => updateStep(step.id, { title: e.target.value })
2986
+ readOnly,
2987
+ onChange: readOnly ? void 0 : (e) => updateStep(step.id, { title: e.target.value })
2490
2988
  }
2491
2989
  )
2492
2990
  ] }),
2493
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.group, children: [
2494
- /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles7.label, children: "URL" }),
2991
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.group, children: [
2992
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles8.label, children: "URL" }),
2495
2993
  /* @__PURE__ */ jsxRuntime.jsx(
2496
2994
  "input",
2497
2995
  {
2498
- style: styles7.input,
2996
+ style: styles8.input,
2499
2997
  value: step.url,
2500
2998
  placeholder: "/onboarding/step-name",
2501
- onChange: (e) => updateStep(step.id, { url: e.target.value })
2999
+ readOnly,
3000
+ onChange: readOnly ? void 0 : (e) => updateStep(step.id, { url: e.target.value })
2502
3001
  }
2503
3002
  ),
2504
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.hint, children: [
3003
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.hint, children: [
2505
3004
  "Supports ",
2506
3005
  "{{PARAM}}",
2507
3006
  " placeholders"
2508
3007
  ] })
2509
3008
  ] }),
2510
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.checkRow, children: [
3009
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.checkRow, children: [
2511
3010
  /* @__PURE__ */ jsxRuntime.jsx(
2512
3011
  "input",
2513
3012
  {
2514
3013
  type: "checkbox",
2515
3014
  id: `resume-${step.id}`,
2516
3015
  checked: !!step.enableResumeFromHere,
2517
- onChange: (e) => updateStep(step.id, { enableResumeFromHere: e.target.checked || void 0 })
3016
+ disabled: readOnly,
3017
+ onChange: readOnly ? void 0 : (e) => updateStep(step.id, { enableResumeFromHere: e.target.checked || void 0 })
2518
3018
  }
2519
3019
  ),
2520
- /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `resume-${step.id}`, style: styles7.checkLabel, children: "Resume from this step" })
3020
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `resume-${step.id}`, style: styles8.checkLabel, children: "Resume from this step" })
2521
3021
  ] }),
2522
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.divider }),
2523
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionRow, children: [
2524
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionInfo, children: [
2525
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.label, children: "Visibility condition" }),
2526
- hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionSummary, children: [
2527
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles7.conditionBadge, children: [
3022
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.divider }),
3023
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.conditionRow, children: [
3024
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.conditionInfo, children: [
3025
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.label, children: "Visibility condition" }),
3026
+ hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.conditionSummary, children: [
3027
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles8.conditionBadge, children: [
2528
3028
  ruleCount,
2529
3029
  " rule",
2530
3030
  ruleCount !== 1 ? "s" : "",
2531
3031
  " \xB7 ",
2532
3032
  step.visibleWhen.combinator.toUpperCase()
2533
3033
  ] }),
2534
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.conditionDesc, children: "Step is conditional" })
2535
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.conditionNone, children: "Always visible" })
3034
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.conditionDesc, children: "Step is conditional" })
3035
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.conditionNone, children: "Always visible" })
2536
3036
  ] }),
2537
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionActions, children: [
3037
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.conditionActions, children: [
2538
3038
  /* @__PURE__ */ jsxRuntime.jsx(
2539
3039
  "button",
2540
3040
  {
2541
- style: styles7.editConditionBtn,
3041
+ style: styles8.editConditionBtn,
2542
3042
  onClick: () => setConditionModalOpen(true),
2543
3043
  children: hasCondition ? "Edit" : "Add condition"
2544
3044
  }
@@ -2546,7 +3046,7 @@ function StepEditor() {
2546
3046
  hasCondition && /* @__PURE__ */ jsxRuntime.jsx(
2547
3047
  "button",
2548
3048
  {
2549
- style: styles7.clearConditionBtn,
3049
+ style: styles8.clearConditionBtn,
2550
3050
  onClick: () => setStepCondition(step.id, void 0),
2551
3051
  children: "Clear"
2552
3052
  }
@@ -2561,7 +3061,7 @@ function StepEditor() {
2561
3061
  onClose: () => setConditionModalOpen(false),
2562
3062
  width: 620,
2563
3063
  children: [
2564
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles7.modalHint, children: "Define when this step is visible. Leave empty to always show it." }),
3064
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles8.modalHint, children: "Define when this step is visible. Leave empty to always show it." }),
2565
3065
  /* @__PURE__ */ jsxRuntime.jsx(
2566
3066
  ConditionBuilder,
2567
3067
  {
@@ -2569,10 +3069,10 @@ function StepEditor() {
2569
3069
  onChange: (c) => setStepCondition(step.id, c)
2570
3070
  }
2571
3071
  ),
2572
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx(
3072
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx(
2573
3073
  "button",
2574
3074
  {
2575
- style: styles7.modalCloseBtn,
3075
+ style: styles8.modalCloseBtn,
2576
3076
  onClick: () => setConditionModalOpen(false),
2577
3077
  children: "Done"
2578
3078
  }
@@ -2582,7 +3082,7 @@ function StepEditor() {
2582
3082
  )
2583
3083
  ] });
2584
3084
  }
2585
- var styles7 = {
3085
+ var styles8 = {
2586
3086
  container: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" },
2587
3087
  empty: {
2588
3088
  display: "flex",
@@ -2671,7 +3171,8 @@ var styles7 = {
2671
3171
  }
2672
3172
  };
2673
3173
  function StepList2() {
2674
- const { schema, selectedStepId, addStep, removeStep, selectStep, reorderSteps } = useBuilderStore();
3174
+ const { schema, selectedStepId, addStep, removeStep, duplicateStep, selectStep, reorderSteps } = useBuilderStore();
3175
+ const readOnly = useBuilderReadOnly();
2675
3176
  const [moveError, setMoveError] = react.useState(null);
2676
3177
  const steps = schema.steps;
2677
3178
  const deps = computeStepDependencies(schema);
@@ -2685,21 +3186,21 @@ function StepList2() {
2685
3186
  setMoveError(null);
2686
3187
  reorderSteps(fromIndex, toIndex);
2687
3188
  };
2688
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.container, children: [
2689
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.header, children: [
2690
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles8.title, children: [
3189
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.container, children: [
3190
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.header, children: [
3191
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles9.title, children: [
2691
3192
  "Steps (",
2692
3193
  steps.length,
2693
3194
  ")"
2694
3195
  ] }),
2695
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles8.addBtn, onClick: () => addStep(), children: "+ Add step" })
3196
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles9.addBtn, onClick: () => addStep(), children: "+ Add step" })
2696
3197
  ] }),
2697
- moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.errorBanner, children: [
2698
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.errorIcon, children: "\u26A0" }),
3198
+ moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.errorBanner, children: [
3199
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.errorIcon, children: "\u26A0" }),
2699
3200
  moveError
2700
3201
  ] }),
2701
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.list, children: [
2702
- steps.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.empty, children: 'No steps yet. Click "Add step" to start.' }),
3202
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.list, children: [
3203
+ steps.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles9.empty, children: 'No steps yet. Click "Add step" to start.' }),
2703
3204
  steps.map((step, index) => {
2704
3205
  const isSelected = step.id === selectedStepId;
2705
3206
  const hasCondition = !!step.visibleWhen;
@@ -2713,31 +3214,31 @@ function StepList2() {
2713
3214
  "div",
2714
3215
  {
2715
3216
  style: {
2716
- ...styles8.card,
2717
- ...isSelected ? styles8.cardSelected : {}
3217
+ ...styles9.card,
3218
+ ...isSelected ? styles9.cardSelected : {}
2718
3219
  },
2719
3220
  onClick: () => selectStep(step.id),
2720
3221
  children: [
2721
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardMain, children: [
2722
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardLeft, children: [
2723
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.cardIndex, children: index + 1 }),
3222
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.cardMain, children: [
3223
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.cardLeft, children: [
3224
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles9.cardIndex, children: index + 1 }),
2724
3225
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0 }, children: [
2725
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.cardTitle, children: step.title }),
2726
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardMeta, children: [
3226
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles9.cardTitle, children: step.title }),
3227
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.cardMeta, children: [
2727
3228
  step.fields.length,
2728
3229
  " field",
2729
3230
  step.fields.length !== 1 ? "s" : "",
2730
- hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.conditionBadge, children: "conditional" })
3231
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.conditionBadge, children: "conditional" })
2731
3232
  ] })
2732
3233
  ] })
2733
3234
  ] }),
2734
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardActions, children: [
3235
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.cardActions, children: [
2735
3236
  index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2736
3237
  "button",
2737
3238
  {
2738
3239
  style: {
2739
- ...styles8.iconBtn,
2740
- ...canMoveUp ? {} : styles8.iconBtnBlocked
3240
+ ...styles9.iconBtn,
3241
+ ...canMoveUp ? {} : styles9.iconBtnBlocked
2741
3242
  },
2742
3243
  title: canMoveUp ? "Move up" : `Can't move up \u2014 dependency order required`,
2743
3244
  onClick: (e) => {
@@ -2751,8 +3252,8 @@ function StepList2() {
2751
3252
  "button",
2752
3253
  {
2753
3254
  style: {
2754
- ...styles8.iconBtn,
2755
- ...canMoveDown ? {} : styles8.iconBtnBlocked
3255
+ ...styles9.iconBtn,
3256
+ ...canMoveDown ? {} : styles9.iconBtnBlocked
2756
3257
  },
2757
3258
  title: canMoveDown ? "Move down" : `Can't move down \u2014 dependency order required`,
2758
3259
  onClick: (e) => {
@@ -2765,7 +3266,19 @@ function StepList2() {
2765
3266
  /* @__PURE__ */ jsxRuntime.jsx(
2766
3267
  "button",
2767
3268
  {
2768
- style: { ...styles8.iconBtn, ...styles8.deleteBtn },
3269
+ style: styles9.iconBtn,
3270
+ title: "Duplicate step",
3271
+ onClick: (e) => {
3272
+ e.stopPropagation();
3273
+ duplicateStep(step.id);
3274
+ },
3275
+ children: "\u29C9"
3276
+ }
3277
+ ),
3278
+ /* @__PURE__ */ jsxRuntime.jsx(
3279
+ "button",
3280
+ {
3281
+ style: { ...styles9.iconBtn, ...styles9.deleteBtn },
2769
3282
  title: "Remove step",
2770
3283
  onClick: (e) => {
2771
3284
  e.stopPropagation();
@@ -2776,13 +3289,13 @@ function StepList2() {
2776
3289
  )
2777
3290
  ] })
2778
3291
  ] }),
2779
- depLabels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.depRow, children: [
2780
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depLabel, children: "needs:" }),
2781
- depLabels.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depBadge, children: label }, label))
3292
+ depLabels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.depRow, children: [
3293
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.depLabel, children: "needs:" }),
3294
+ depLabels.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.depBadge, children: label }, label))
2782
3295
  ] }),
2783
- dependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.depRow, children: [
2784
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depLabelUsed, children: "used by:" }),
2785
- dependents.map((s) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depBadgeUsed, children: s.title }, s.id))
3296
+ dependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.depRow, children: [
3297
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.depLabelUsed, children: "used by:" }),
3298
+ dependents.map((s) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.depBadgeUsed, children: s.title }, s.id))
2786
3299
  ] })
2787
3300
  ]
2788
3301
  },
@@ -2792,7 +3305,7 @@ function StepList2() {
2792
3305
  ] })
2793
3306
  ] });
2794
3307
  }
2795
- var styles8 = {
3308
+ var styles9 = {
2796
3309
  container: { display: "flex", flexDirection: "column", height: "100%" },
2797
3310
  header: {
2798
3311
  display: "flex",
@@ -2912,7 +3425,7 @@ var styles8 = {
2912
3425
  borderRadius: 4
2913
3426
  }
2914
3427
  };
2915
- function Toolbar({ onSave, previewMode, onTest, isMobile }) {
3428
+ function Toolbar({ onSave, previewMode, onTest, isMobile, readOnly }) {
2916
3429
  const { schema, isDirty, resetSchema } = useBuilderStore();
2917
3430
  const handleExport = () => {
2918
3431
  const json = JSON.stringify(schema, null, 2);
@@ -2952,31 +3465,31 @@ ${result.errors.map((e2) => `\u2022 ${e2}`).join("\n")}`);
2952
3465
  input.click();
2953
3466
  };
2954
3467
  if (previewMode) {
2955
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.toolbar, children: [
2956
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.left, children: [
2957
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.logo, children: "\u25C8 waypoint" }),
2958
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.separator, children: "/" }),
3468
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles10.toolbar, children: [
3469
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles10.left, children: [
3470
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.logo, children: "\u25C8 waypoint" }),
3471
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.separator, children: "/" }),
2959
3472
  /* @__PURE__ */ jsxRuntime.jsx(
2960
3473
  "button",
2961
3474
  {
2962
- style: { ...styles9.btn, ...styles9.editBtn },
3475
+ style: { ...styles10.btn, ...styles10.editBtn },
2963
3476
  onClick: onTest,
2964
3477
  children: "\u2190 \xC9diter"
2965
3478
  }
2966
3479
  )
2967
3480
  ] }),
2968
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles9.right, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "var(--wp-text-muted)", fontStyle: "italic" }, children: "Mode aper\xE7u" }) })
3481
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles10.right, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: 12, color: "var(--wp-text-muted)", fontStyle: "italic" }, children: "Mode aper\xE7u" }) })
2969
3482
  ] });
2970
3483
  }
2971
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.toolbar, children: [
2972
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.left, children: [
2973
- !isMobile && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.logo, children: "\u25C8 waypoint" }),
2974
- !isMobile && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.separator, children: "/" }),
3484
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles10.toolbar, children: [
3485
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles10.left, children: [
3486
+ !isMobile && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.logo, children: "\u25C8 waypoint" }),
3487
+ !isMobile && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.separator, children: "/" }),
2975
3488
  /* @__PURE__ */ jsxRuntime.jsx(
2976
3489
  "input",
2977
3490
  {
2978
3491
  style: {
2979
- ...styles9.journeyName,
3492
+ ...styles10.journeyName,
2980
3493
  ...isMobile ? { maxWidth: 120, fontSize: 12 } : {}
2981
3494
  },
2982
3495
  value: schema.name,
@@ -2987,25 +3500,26 @@ ${result.errors.map((e2) => `\u2022 ${e2}`).join("\n")}`);
2987
3500
  }))
2988
3501
  }
2989
3502
  ),
2990
- isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.dirtyDot, title: "Unsaved changes" })
3503
+ isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.dirtyDot, title: "Unsaved changes" })
2991
3504
  ] }),
2992
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.right, children: [
2993
- onTest && /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles9.btn, ...styles9.testBtn }, onClick: onTest, title: "Tester", children: isMobile ? "\u25B6" : "\u25B6 Tester" }),
2994
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles9.btn, onClick: handleImport, title: "Import", children: isMobile ? "\u2193" : "Import" }),
2995
- /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles9.btn, onClick: handleExport, title: "Export JSON", children: isMobile ? "\u2191" : "Export JSON" }),
2996
- onSave && /* @__PURE__ */ jsxRuntime.jsx(
3505
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles10.right, children: [
3506
+ readOnly && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles10.readOnlyBadge, children: "View only" }),
3507
+ !readOnly && onTest && /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles10.btn, ...styles10.testBtn }, onClick: onTest, title: "Tester", children: isMobile ? "\u25B6" : "\u25B6 Tester" }),
3508
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles10.btn, onClick: handleImport, title: "Import", children: isMobile ? "\u2193" : "Import" }),
3509
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles10.btn, onClick: handleExport, title: "Export JSON", children: isMobile ? "\u2191" : "Export JSON" }),
3510
+ !readOnly && onSave && /* @__PURE__ */ jsxRuntime.jsx(
2997
3511
  "button",
2998
3512
  {
2999
- style: { ...styles9.btn, ...styles9.saveBtn },
3513
+ style: { ...styles10.btn, ...styles10.saveBtn },
3000
3514
  onClick: () => onSave(schema),
3001
3515
  title: "Save",
3002
3516
  children: isMobile ? "\u2713" : "Save"
3003
3517
  }
3004
3518
  ),
3005
- /* @__PURE__ */ jsxRuntime.jsx(
3519
+ !readOnly && /* @__PURE__ */ jsxRuntime.jsx(
3006
3520
  "button",
3007
3521
  {
3008
- style: { ...styles9.btn, color: "var(--wp-danger)" },
3522
+ style: { ...styles10.btn, color: "var(--wp-danger)" },
3009
3523
  title: "Reset",
3010
3524
  onClick: () => {
3011
3525
  if (confirm("Reset the journey? All changes will be lost.")) resetSchema();
@@ -3016,7 +3530,7 @@ ${result.errors.map((e2) => `\u2022 ${e2}`).join("\n")}`);
3016
3530
  ] })
3017
3531
  ] });
3018
3532
  }
3019
- var styles9 = {
3533
+ var styles10 = {
3020
3534
  toolbar: {
3021
3535
  display: "flex",
3022
3536
  alignItems: "center",
@@ -3058,6 +3572,15 @@ var styles9 = {
3058
3572
  fontWeight: 500
3059
3573
  },
3060
3574
  saveBtn: { background: "var(--wp-primary)", color: "var(--wp-canvas)", border: "1px solid var(--wp-primary)" },
3575
+ readOnlyBadge: {
3576
+ fontSize: 11,
3577
+ fontWeight: 600,
3578
+ color: "var(--wp-text-subtle)",
3579
+ background: "var(--wp-surface)",
3580
+ border: "1px solid var(--wp-border)",
3581
+ borderRadius: "var(--wp-radius)",
3582
+ padding: "3px 8px"
3583
+ },
3061
3584
  testBtn: { background: "var(--wp-success, #22c55e)", color: "#fff", border: "1px solid var(--wp-success, #22c55e)", fontWeight: 600 },
3062
3585
  editBtn: { background: "transparent", color: "var(--wp-toolbar-text)", border: "none", fontWeight: 600, cursor: "pointer", fontSize: 13, padding: "5px 0" }
3063
3586
  };
@@ -3067,7 +3590,10 @@ function WaypointBuilder({
3067
3590
  onSave,
3068
3591
  theme,
3069
3592
  className,
3070
- style
3593
+ style,
3594
+ readOnly = false,
3595
+ appCustomTypes = [],
3596
+ externalEnums = []
3071
3597
  }) {
3072
3598
  const { loadSchema, schema, selectedStepId, selectedFieldId } = useBuilderStore();
3073
3599
  const [previewMode, setPreviewMode] = react.useState(false);
@@ -3100,14 +3626,15 @@ function WaypointBuilder({
3100
3626
  setPreviewMode(true);
3101
3627
  }
3102
3628
  const themeVars = buildThemeVars(theme);
3103
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...rootStyle, ...themeVars, ...style }, children: [
3629
+ return /* @__PURE__ */ jsxRuntime.jsx(BuilderReadOnlyContext.Provider, { value: readOnly, children: /* @__PURE__ */ jsxRuntime.jsx(BuilderCustomTypesContext.Provider, { value: appCustomTypes, children: /* @__PURE__ */ jsxRuntime.jsx(BuilderExternalEnumsContext.Provider, { value: externalEnums, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...rootStyle, ...themeVars, ...style }, children: [
3104
3630
  /* @__PURE__ */ jsxRuntime.jsx(
3105
3631
  Toolbar,
3106
3632
  {
3107
3633
  isMobile,
3108
- onSave: !previewMode && onSave ? () => onSave(schema) : void 0,
3634
+ readOnly,
3635
+ onSave: !previewMode && !readOnly && onSave ? () => onSave(schema) : void 0,
3109
3636
  previewMode,
3110
- onTest: previewMode ? () => setPreviewMode(false) : handleTest
3637
+ onTest: !readOnly ? previewMode ? () => setPreviewMode(false) : handleTest : void 0
3111
3638
  }
3112
3639
  ),
3113
3640
  previewMode ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -3115,6 +3642,7 @@ function WaypointBuilder({
3115
3642
  {
3116
3643
  store: previewStoreRef.current,
3117
3644
  schema,
3645
+ externalEnums,
3118
3646
  onEdit: () => setPreviewMode(false)
3119
3647
  }
3120
3648
  ) : isMobile ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
@@ -3152,7 +3680,7 @@ function WaypointBuilder({
3152
3680
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(FieldEditor, {}) })
3153
3681
  ] })
3154
3682
  ] })
3155
- ] });
3683
+ ] }) }) }) });
3156
3684
  }
3157
3685
  var rootStyle = {
3158
3686
  display: "flex",