@waypointjs/builder 0.1.0

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 ADDED
@@ -0,0 +1,3080 @@
1
+ 'use strict';
2
+
3
+ var core = require('@waypointjs/core');
4
+ var react = require('react');
5
+ var zustand = require('zustand');
6
+ var jsxRuntime = require('react/jsx-runtime');
7
+ var react$1 = require('@waypointjs/react');
8
+
9
+ // src/components/WaypointBuilder.tsx
10
+
11
+ // src/theme.ts
12
+ var DEFAULT_THEME = {
13
+ primary: "#6366f1",
14
+ primaryDark: "#4338ca",
15
+ primaryBg: "#e0e7ff",
16
+ primaryMuted: "#ede9fe",
17
+ primaryBorder: "#a78bfa",
18
+ toolbarBg: "#111827",
19
+ toolbarBorder: "#1f2937",
20
+ toolbarLogo: "#a78bfa",
21
+ toolbarText: "#f9fafb",
22
+ toolbarTextMuted: "#d1d5db",
23
+ toolbarTextSubtle: "#4b5563",
24
+ canvas: "#ffffff",
25
+ surface: "#f9fafb",
26
+ surfaceMuted: "#f3f4f6",
27
+ surfaceAlt: "#f1f5f9",
28
+ border: "#e5e7eb",
29
+ borderMuted: "#d1d5db",
30
+ text: "#111827",
31
+ textSecondary: "#374151",
32
+ textMuted: "#6b7280",
33
+ textSubtle: "#9ca3af",
34
+ textMono: "#475569",
35
+ danger: "#ef4444",
36
+ dangerText: "#dc2626",
37
+ dangerBg: "#fef2f2",
38
+ dangerBgStrong: "#fee2e2",
39
+ dangerBorder: "#fecaca",
40
+ warning: "#d97706",
41
+ warningStrong: "#f59e0b",
42
+ warningBg: "#fef3c7",
43
+ success: "#059669",
44
+ successBg: "#d1fae5",
45
+ info: "#3b82f6",
46
+ infoText: "#3b82f6",
47
+ infoBg: "#eff6ff",
48
+ infoBgStrong: "#eff6ff",
49
+ infoBorder: "#bfdbfe",
50
+ font: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
51
+ radius: "6px",
52
+ radiusLg: "8px"
53
+ };
54
+ var DARK_THEME = {
55
+ primary: "#818cf8",
56
+ primaryDark: "#6366f1",
57
+ primaryBg: "#1e1b4b",
58
+ primaryMuted: "#1e1b4b",
59
+ primaryBorder: "#6366f1",
60
+ toolbarBg: "#0a0a0a",
61
+ toolbarBorder: "#1a1a1a",
62
+ toolbarLogo: "#818cf8",
63
+ toolbarText: "#f1f5f9",
64
+ toolbarTextMuted: "#9ca3af",
65
+ toolbarTextSubtle: "#374151",
66
+ canvas: "#141414",
67
+ surface: "#1e1e1e",
68
+ surfaceMuted: "#2a2a2a",
69
+ surfaceAlt: "#242424",
70
+ border: "#2e2e2e",
71
+ borderMuted: "#404040",
72
+ text: "#f1f5f9",
73
+ textSecondary: "#e2e8f0",
74
+ textMuted: "#94a3b8",
75
+ textSubtle: "#64748b",
76
+ textMono: "#94a3b8",
77
+ danger: "#f87171",
78
+ dangerText: "#fca5a5",
79
+ dangerBg: "#1c0a0a",
80
+ dangerBgStrong: "#2d1515",
81
+ dangerBorder: "#7f1d1d",
82
+ warning: "#fbbf24",
83
+ warningStrong: "#fbbf24",
84
+ warningBg: "#1a1000",
85
+ success: "#34d399",
86
+ successBg: "#052e16",
87
+ info: "#60a5fa",
88
+ infoText: "#93c5fd",
89
+ infoBg: "#0a1628",
90
+ infoBgStrong: "#0f1f3d",
91
+ infoBorder: "#1e3a5f",
92
+ font: "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif",
93
+ radius: "6px",
94
+ radiusLg: "8px"
95
+ };
96
+ function buildThemeVars(theme = {}) {
97
+ const t = { ...DEFAULT_THEME, ...theme };
98
+ return {
99
+ "--wp-primary": t.primary,
100
+ "--wp-primary-dark": t.primaryDark,
101
+ "--wp-primary-bg": t.primaryBg,
102
+ "--wp-primary-muted": t.primaryMuted,
103
+ "--wp-primary-border": t.primaryBorder,
104
+ "--wp-toolbar-bg": t.toolbarBg,
105
+ "--wp-toolbar-border": t.toolbarBorder,
106
+ "--wp-toolbar-logo": t.toolbarLogo,
107
+ "--wp-toolbar-text": t.toolbarText,
108
+ "--wp-toolbar-text-muted": t.toolbarTextMuted,
109
+ "--wp-toolbar-text-subtle": t.toolbarTextSubtle,
110
+ "--wp-canvas": t.canvas,
111
+ "--wp-surface": t.surface,
112
+ "--wp-surface-muted": t.surfaceMuted,
113
+ "--wp-surface-alt": t.surfaceAlt,
114
+ "--wp-border": t.border,
115
+ "--wp-border-muted": t.borderMuted,
116
+ "--wp-text": t.text,
117
+ "--wp-text-secondary": t.textSecondary,
118
+ "--wp-text-muted": t.textMuted,
119
+ "--wp-text-subtle": t.textSubtle,
120
+ "--wp-text-mono": t.textMono,
121
+ "--wp-danger": t.danger,
122
+ "--wp-danger-text": t.dangerText,
123
+ "--wp-danger-bg": t.dangerBg,
124
+ "--wp-danger-bg-strong": t.dangerBgStrong,
125
+ "--wp-danger-border": t.dangerBorder,
126
+ "--wp-warning": t.warning,
127
+ "--wp-warning-strong": t.warningStrong,
128
+ "--wp-warning-bg": t.warningBg,
129
+ "--wp-success": t.success,
130
+ "--wp-success-bg": t.successBg,
131
+ "--wp-info": t.info,
132
+ "--wp-info-text": t.infoText,
133
+ "--wp-info-bg": t.infoBg,
134
+ "--wp-info-bg-strong": t.infoBgStrong,
135
+ "--wp-info-border": t.infoBorder,
136
+ "--wp-font": t.font,
137
+ "--wp-radius": t.radius,
138
+ "--wp-radius-lg": t.radiusLg
139
+ };
140
+ }
141
+ function generateId(prefix) {
142
+ return `${prefix}_${Math.random().toString(36).slice(2, 9)}`;
143
+ }
144
+ function makeDefaultSchema() {
145
+ return {
146
+ version: "1",
147
+ id: generateId("journey"),
148
+ name: "My Journey",
149
+ steps: [],
150
+ externalVariables: [],
151
+ customTypes: [],
152
+ persistenceMode: "zustand"
153
+ };
154
+ }
155
+ var useBuilderStore = zustand.create((set, _get) => ({
156
+ schema: makeDefaultSchema(),
157
+ selectedStepId: null,
158
+ selectedFieldId: null,
159
+ isDirty: false,
160
+ // --- Schema ---
161
+ loadSchema: (schema) => set({ schema, selectedStepId: null, selectedFieldId: null, isDirty: false }),
162
+ resetSchema: () => set({ schema: makeDefaultSchema(), selectedStepId: null, selectedFieldId: null, isDirty: false }),
163
+ // --- Steps ---
164
+ addStep: (partial = {}) => {
165
+ const id = generateId("step");
166
+ const step = {
167
+ id,
168
+ title: partial.title ?? "New Step",
169
+ url: partial.url ?? `/${id}`,
170
+ fields: partial.fields ?? [],
171
+ ...partial
172
+ };
173
+ set((s) => ({
174
+ schema: { ...s.schema, steps: [...s.schema.steps, step] },
175
+ selectedStepId: id,
176
+ selectedFieldId: null,
177
+ isDirty: true
178
+ }));
179
+ return id;
180
+ },
181
+ updateStep: (stepId, updates) => set((s) => ({
182
+ schema: {
183
+ ...s.schema,
184
+ steps: s.schema.steps.map(
185
+ (step) => step.id === stepId ? { ...step, ...updates } : step
186
+ )
187
+ },
188
+ isDirty: true
189
+ })),
190
+ removeStep: (stepId) => set((s) => ({
191
+ schema: {
192
+ ...s.schema,
193
+ steps: s.schema.steps.filter((step) => step.id !== stepId)
194
+ },
195
+ selectedStepId: s.selectedStepId === stepId ? null : s.selectedStepId,
196
+ selectedFieldId: s.selectedStepId === stepId ? null : s.selectedFieldId,
197
+ isDirty: true
198
+ })),
199
+ reorderSteps: (fromIndex, toIndex) => set((s) => {
200
+ const steps = [...s.schema.steps];
201
+ const [moved] = steps.splice(fromIndex, 1);
202
+ steps.splice(toIndex, 0, moved);
203
+ return { schema: { ...s.schema, steps }, isDirty: true };
204
+ }),
205
+ selectStep: (stepId) => set({ selectedStepId: stepId, selectedFieldId: null }),
206
+ // --- Fields ---
207
+ addField: (stepId, partial = {}) => {
208
+ const id = generateId("field");
209
+ const field = {
210
+ id,
211
+ type: partial.type ?? "text",
212
+ label: partial.label ?? "New Field",
213
+ ...partial
214
+ };
215
+ set((s) => ({
216
+ schema: {
217
+ ...s.schema,
218
+ steps: s.schema.steps.map(
219
+ (step) => step.id === stepId ? { ...step, fields: [...step.fields, field] } : step
220
+ )
221
+ },
222
+ selectedFieldId: id,
223
+ isDirty: true
224
+ }));
225
+ return id;
226
+ },
227
+ updateField: (stepId, fieldId, updates) => set((s) => ({
228
+ schema: {
229
+ ...s.schema,
230
+ steps: s.schema.steps.map(
231
+ (step) => step.id === stepId ? {
232
+ ...step,
233
+ fields: step.fields.map(
234
+ (f) => f.id === fieldId ? { ...f, ...updates } : f
235
+ )
236
+ } : step
237
+ )
238
+ },
239
+ isDirty: true
240
+ })),
241
+ removeField: (stepId, fieldId) => set((s) => ({
242
+ schema: {
243
+ ...s.schema,
244
+ steps: s.schema.steps.map(
245
+ (step) => step.id === stepId ? { ...step, fields: step.fields.filter((f) => f.id !== fieldId) } : step
246
+ )
247
+ },
248
+ selectedFieldId: s.selectedFieldId === fieldId ? null : s.selectedFieldId,
249
+ isDirty: true
250
+ })),
251
+ reorderFields: (stepId, fromIndex, toIndex) => set((s) => ({
252
+ schema: {
253
+ ...s.schema,
254
+ steps: s.schema.steps.map((step) => {
255
+ if (step.id !== stepId) return step;
256
+ const fields = [...step.fields];
257
+ const [moved] = fields.splice(fromIndex, 1);
258
+ fields.splice(toIndex, 0, moved);
259
+ return { ...step, fields };
260
+ })
261
+ },
262
+ isDirty: true
263
+ })),
264
+ selectField: (fieldId) => set({ selectedFieldId: fieldId }),
265
+ // --- Step conditions ---
266
+ setStepCondition: (stepId, condition) => set((s) => ({
267
+ schema: {
268
+ ...s.schema,
269
+ steps: s.schema.steps.map(
270
+ (step) => step.id === stepId ? { ...step, visibleWhen: condition } : step
271
+ )
272
+ },
273
+ isDirty: true
274
+ })),
275
+ // --- Field conditions ---
276
+ setFieldCondition: (stepId, fieldId, condition) => set((s) => ({
277
+ schema: {
278
+ ...s.schema,
279
+ steps: s.schema.steps.map(
280
+ (step) => step.id === stepId ? {
281
+ ...step,
282
+ fields: step.fields.map(
283
+ (f) => f.id === fieldId ? { ...f, visibleWhen: condition } : f
284
+ )
285
+ } : step
286
+ )
287
+ },
288
+ isDirty: true
289
+ })),
290
+ // --- External variables ---
291
+ addExternalVariable: (variable) => set((s) => ({
292
+ schema: {
293
+ ...s.schema,
294
+ externalVariables: [
295
+ ...s.schema.externalVariables ?? [],
296
+ { ...variable, usedIn: [] }
297
+ ]
298
+ },
299
+ isDirty: true
300
+ })),
301
+ updateExternalVariable: (varId, updates) => set((s) => ({
302
+ schema: {
303
+ ...s.schema,
304
+ externalVariables: (s.schema.externalVariables ?? []).map(
305
+ (v) => v.id === varId ? { ...v, ...updates } : v
306
+ )
307
+ },
308
+ isDirty: true
309
+ })),
310
+ removeExternalVariable: (varId) => set((s) => ({
311
+ schema: {
312
+ ...s.schema,
313
+ externalVariables: (s.schema.externalVariables ?? []).filter(
314
+ (v) => v.id !== varId
315
+ )
316
+ },
317
+ isDirty: true
318
+ })),
319
+ // --- Custom types ---
320
+ addCustomType: (type) => set((s) => ({
321
+ schema: {
322
+ ...s.schema,
323
+ customTypes: [...s.schema.customTypes ?? [], type]
324
+ },
325
+ isDirty: true
326
+ })),
327
+ updateCustomType: (typeId, updates) => set((s) => ({
328
+ schema: {
329
+ ...s.schema,
330
+ customTypes: (s.schema.customTypes ?? []).map(
331
+ (t) => t.id === typeId ? { ...t, ...updates } : t
332
+ )
333
+ },
334
+ isDirty: true
335
+ })),
336
+ removeCustomType: (typeId) => set((s) => ({
337
+ schema: {
338
+ ...s.schema,
339
+ customTypes: (s.schema.customTypes ?? []).filter((t) => t.id !== typeId)
340
+ },
341
+ isDirty: true
342
+ })),
343
+ // --- Persistence ---
344
+ setPersistenceMode: (mode) => set((s) => ({
345
+ schema: { ...s.schema, persistenceMode: mode },
346
+ isDirty: true
347
+ }))
348
+ }));
349
+ var BLANK_FORM = { id: "", label: "", type: "string", blocking: false };
350
+ function ExternalVariablePanel() {
351
+ const { schema, addExternalVariable, updateExternalVariable, removeExternalVariable } = useBuilderStore();
352
+ const variables = schema.externalVariables ?? [];
353
+ const [isAdding, setIsAdding] = react.useState(false);
354
+ const [editingId, setEditingId] = react.useState(null);
355
+ const [form, setForm] = react.useState(BLANK_FORM);
356
+ const [error, setError] = react.useState(null);
357
+ const usageMap = computeUsageMap(schema.steps ?? []);
358
+ function startAdd() {
359
+ setIsAdding(true);
360
+ setEditingId(null);
361
+ setForm(BLANK_FORM);
362
+ setError(null);
363
+ }
364
+ function startEdit(v) {
365
+ setEditingId(v.id);
366
+ setIsAdding(false);
367
+ setForm({ id: v.id, label: v.label, type: v.type, blocking: v.blocking });
368
+ setError(null);
369
+ }
370
+ function cancelForm() {
371
+ setIsAdding(false);
372
+ setEditingId(null);
373
+ setError(null);
374
+ }
375
+ function validateForm() {
376
+ if (!form.id.trim()) return "ID is required";
377
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(form.id.trim())) return "ID must be alphanumeric (no spaces)";
378
+ if (!form.label.trim()) return "Label is required";
379
+ if (isAdding && variables.some((v) => v.id === form.id.trim())) return `ID "${form.id}" already exists`;
380
+ return null;
381
+ }
382
+ function submitAdd() {
383
+ const err = validateForm();
384
+ if (err) {
385
+ setError(err);
386
+ return;
387
+ }
388
+ addExternalVariable({ id: form.id.trim(), label: form.label.trim(), type: form.type, blocking: form.blocking });
389
+ setIsAdding(false);
390
+ setForm(BLANK_FORM);
391
+ setError(null);
392
+ }
393
+ function submitEdit() {
394
+ const err = validateForm();
395
+ if (err) {
396
+ setError(err);
397
+ return;
398
+ }
399
+ if (!editingId) return;
400
+ updateExternalVariable(editingId, { label: form.label.trim(), type: form.type, blocking: form.blocking });
401
+ setEditingId(null);
402
+ setError(null);
403
+ }
404
+ function remove(id) {
405
+ removeExternalVariable(id);
406
+ if (editingId === id) {
407
+ setEditingId(null);
408
+ setError(null);
409
+ }
410
+ }
411
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyle, children: [
412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: headerStyle, children: [
413
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: titleStyle, children: "External Variables" }),
414
+ !isAdding && /* @__PURE__ */ jsxRuntime.jsx("button", { style: addBtnStyle, onClick: startAdd, title: "Add external variable", children: "+ Add" })
415
+ ] }),
416
+ variables.length === 0 && !isAdding && /* @__PURE__ */ jsxRuntime.jsxs("p", { style: emptyStyle, children: [
417
+ "No external variables declared.",
418
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
419
+ "External vars are injected at runtime",
420
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
421
+ "(e.g. ",
422
+ /* @__PURE__ */ jsxRuntime.jsx("code", { style: codeStyle, children: "$ext.userId" }),
423
+ ")."
424
+ ] }),
425
+ variables.map((v) => {
426
+ const refs = usageMap.get(v.id) ?? [];
427
+ const isBeingEdited = editingId === v.id;
428
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...varRowStyle, ...isBeingEdited ? varRowActiveStyle : {} }, children: isBeingEdited ? /* @__PURE__ */ jsxRuntime.jsx(
429
+ VarForm,
430
+ {
431
+ form,
432
+ onChange: setForm,
433
+ error,
434
+ onSubmit: submitEdit,
435
+ onCancel: cancelForm,
436
+ submitLabel: "Save",
437
+ idReadOnly: true
438
+ }
439
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
440
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: varMainStyle, children: [
441
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: varTopRowStyle, children: [
442
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: varIdStyle, children: [
443
+ "$",
444
+ `ext.${v.id}`
445
+ ] }),
446
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: badgeRowStyle, children: [
447
+ /* @__PURE__ */ jsxRuntime.jsx(TypeBadge, { type: v.type }),
448
+ v.blocking && /* @__PURE__ */ jsxRuntime.jsx("span", { style: blockingBadgeStyle, children: "blocking" })
449
+ ] })
450
+ ] }),
451
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: varLabelStyle, children: v.label }),
452
+ refs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: refsStyle, children: refs.map((ref, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: refChipStyle, children: ref }, i)) })
453
+ ] }),
454
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: varActionsStyle, children: [
455
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: actionBtnStyle, onClick: () => startEdit(v), children: "Edit" }),
456
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...actionBtnStyle, color: "#ef4444" }, title: "Remove variable", onClick: () => remove(v.id), children: "\u2715" })
457
+ ] })
458
+ ] }) }, v.id);
459
+ }),
460
+ isAdding && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...varRowStyle, ...varRowActiveStyle }, children: /* @__PURE__ */ jsxRuntime.jsx(
461
+ VarForm,
462
+ {
463
+ form,
464
+ onChange: setForm,
465
+ error,
466
+ onSubmit: submitAdd,
467
+ onCancel: cancelForm,
468
+ submitLabel: "Add"
469
+ }
470
+ ) })
471
+ ] });
472
+ }
473
+ function VarForm({ form, onChange, error, onSubmit, onCancel, submitLabel, idReadOnly }) {
474
+ function set(key, value) {
475
+ onChange({ ...form, [key]: value });
476
+ }
477
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: formStyle, children: [
478
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: formLabelStyle, children: "ID" }),
479
+ /* @__PURE__ */ jsxRuntime.jsx(
480
+ "input",
481
+ {
482
+ style: { ...inputStyle, ...idReadOnly ? { background: "#f9fafb", color: "#6b7280" } : {} },
483
+ value: form.id,
484
+ onChange: (e) => set("id", e.target.value),
485
+ placeholder: "e.g. userId",
486
+ readOnly: idReadOnly
487
+ }
488
+ ),
489
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: formLabelStyle, children: "Label" }),
490
+ /* @__PURE__ */ jsxRuntime.jsx(
491
+ "input",
492
+ {
493
+ style: inputStyle,
494
+ value: form.label,
495
+ onChange: (e) => set("label", e.target.value),
496
+ placeholder: "Human-readable description"
497
+ }
498
+ ),
499
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: formLabelStyle, children: "Type" }),
500
+ /* @__PURE__ */ jsxRuntime.jsxs("select", { style: selectStyle, value: form.type, onChange: (e) => set("type", e.target.value), children: [
501
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "string", children: "string" }),
502
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "number", children: "number" }),
503
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "boolean", children: "boolean" }),
504
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "object", children: "object" })
505
+ ] }),
506
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: checkboxRowStyle, children: [
507
+ /* @__PURE__ */ jsxRuntime.jsx(
508
+ "input",
509
+ {
510
+ type: "checkbox",
511
+ checked: form.blocking,
512
+ onChange: (e) => set("blocking", e.target.checked),
513
+ style: { marginRight: 6 }
514
+ }
515
+ ),
516
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: formLabelStyle, children: "Blocking \u2014 throw if missing at runtime" })
517
+ ] }),
518
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { style: errorStyle, children: error }),
519
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: formActionsStyle, children: [
520
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: cancelBtnStyle, onClick: onCancel, children: "Cancel" }),
521
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: submitBtnStyle, onClick: onSubmit, children: submitLabel })
522
+ ] })
523
+ ] });
524
+ }
525
+ function TypeBadge({ type }) {
526
+ const colors = {
527
+ string: "#d1fae5",
528
+ number: "#dbeafe",
529
+ boolean: "#fef3c7",
530
+ object: "#f3e8ff"
531
+ };
532
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...typeBadgeStyle, background: colors[type] ?? "#f3f4f6" }, children: type });
533
+ }
534
+ function computeUsageMap(steps) {
535
+ const map = /* @__PURE__ */ new Map();
536
+ function addRef(varId, label) {
537
+ const existing = map.get(varId) ?? [];
538
+ if (!existing.includes(label)) existing.push(label);
539
+ map.set(varId, existing);
540
+ }
541
+ function scanPaths(paths, context) {
542
+ for (const path of paths ?? []) {
543
+ if (path.startsWith("$ext.")) addRef(path.slice(5), context);
544
+ }
545
+ }
546
+ function scanCondition(group, context) {
547
+ if (!group) return;
548
+ for (const rule of group.rules ?? []) {
549
+ if (rule.field.startsWith("$ext.")) addRef(rule.field.slice(5), context);
550
+ }
551
+ for (const nested of group.groups ?? []) scanCondition(nested, context);
552
+ }
553
+ for (const step of steps) {
554
+ scanCondition(step.visibleWhen, step.title);
555
+ for (const field of step.fields ?? []) {
556
+ scanPaths(field.dependsOn, `${step.title} \u203A ${field.label}`);
557
+ scanCondition(field.visibleWhen, `${step.title} \u203A ${field.label}`);
558
+ }
559
+ }
560
+ return map;
561
+ }
562
+ var panelStyle = {
563
+ display: "flex",
564
+ flexDirection: "column",
565
+ padding: "8px 0",
566
+ gap: 0
567
+ };
568
+ var headerStyle = {
569
+ display: "flex",
570
+ alignItems: "center",
571
+ justifyContent: "space-between",
572
+ padding: "6px 12px 8px"
573
+ };
574
+ var titleStyle = {
575
+ fontSize: 11,
576
+ fontWeight: 700,
577
+ color: "#9ca3af",
578
+ textTransform: "uppercase",
579
+ letterSpacing: "0.05em"
580
+ };
581
+ var addBtnStyle = {
582
+ fontSize: 11,
583
+ fontWeight: 600,
584
+ color: "#6366f1",
585
+ background: "none",
586
+ border: "none",
587
+ cursor: "pointer",
588
+ padding: "2px 4px"
589
+ };
590
+ var emptyStyle = {
591
+ fontSize: 11,
592
+ color: "#9ca3af",
593
+ padding: "8px 12px 12px",
594
+ lineHeight: 1.5,
595
+ margin: 0
596
+ };
597
+ var codeStyle = {
598
+ fontFamily: "monospace",
599
+ background: "#f3f4f6",
600
+ borderRadius: 3,
601
+ padding: "1px 3px"
602
+ };
603
+ var varRowStyle = {
604
+ display: "flex",
605
+ alignItems: "flex-start",
606
+ gap: 6,
607
+ padding: "8px 12px",
608
+ borderTop: "1px solid #f3f4f6"
609
+ };
610
+ var varRowActiveStyle = {
611
+ background: "#f9fafb"
612
+ };
613
+ var varMainStyle = {
614
+ flex: 1,
615
+ minWidth: 0,
616
+ display: "flex",
617
+ flexDirection: "column",
618
+ gap: 2
619
+ };
620
+ var varTopRowStyle = {
621
+ display: "flex",
622
+ alignItems: "center",
623
+ gap: 6,
624
+ flexWrap: "wrap"
625
+ };
626
+ var varIdStyle = {
627
+ fontSize: 11,
628
+ fontFamily: "monospace",
629
+ fontWeight: 600,
630
+ color: "#374151"
631
+ };
632
+ var badgeRowStyle = {
633
+ display: "flex",
634
+ gap: 4,
635
+ flexWrap: "wrap"
636
+ };
637
+ var typeBadgeStyle = {
638
+ fontSize: 10,
639
+ fontWeight: 600,
640
+ padding: "1px 5px",
641
+ borderRadius: 4,
642
+ color: "#374151"
643
+ };
644
+ var blockingBadgeStyle = {
645
+ fontSize: 10,
646
+ fontWeight: 600,
647
+ padding: "1px 5px",
648
+ borderRadius: 4,
649
+ background: "#fee2e2",
650
+ color: "#dc2626"
651
+ };
652
+ var varLabelStyle = {
653
+ fontSize: 12,
654
+ color: "#6b7280",
655
+ marginTop: 1
656
+ };
657
+ var refsStyle = {
658
+ display: "flex",
659
+ flexWrap: "wrap",
660
+ gap: 4,
661
+ marginTop: 4
662
+ };
663
+ var refChipStyle = {
664
+ fontSize: 10,
665
+ padding: "1px 6px",
666
+ borderRadius: 4,
667
+ background: "#eff6ff",
668
+ color: "#3b82f6",
669
+ border: "1px solid #bfdbfe"
670
+ };
671
+ var varActionsStyle = {
672
+ display: "flex",
673
+ gap: 2,
674
+ flexShrink: 0
675
+ };
676
+ var actionBtnStyle = {
677
+ fontSize: 11,
678
+ background: "none",
679
+ border: "none",
680
+ cursor: "pointer",
681
+ color: "#6b7280",
682
+ padding: "2px 4px"
683
+ };
684
+ var formStyle = {
685
+ width: "100%",
686
+ display: "flex",
687
+ flexDirection: "column",
688
+ gap: 6
689
+ };
690
+ var formLabelStyle = {
691
+ fontSize: 11,
692
+ fontWeight: 600,
693
+ color: "#374151"
694
+ };
695
+ var inputStyle = {
696
+ fontSize: 12,
697
+ padding: "5px 8px",
698
+ border: "1px solid #d1d5db",
699
+ borderRadius: 6,
700
+ outline: "none",
701
+ width: "100%",
702
+ boxSizing: "border-box"
703
+ };
704
+ var selectStyle = {
705
+ ...inputStyle
706
+ };
707
+ var checkboxRowStyle = {
708
+ display: "flex",
709
+ alignItems: "center",
710
+ cursor: "pointer"
711
+ };
712
+ var errorStyle = {
713
+ fontSize: 11,
714
+ color: "#ef4444",
715
+ margin: 0,
716
+ padding: "4px 8px",
717
+ background: "#fef2f2",
718
+ borderRadius: 4,
719
+ border: "1px solid #fca5a5"
720
+ };
721
+ var formActionsStyle = {
722
+ display: "flex",
723
+ gap: 6,
724
+ justifyContent: "flex-end",
725
+ marginTop: 2
726
+ };
727
+ var cancelBtnStyle = {
728
+ fontSize: 12,
729
+ padding: "4px 10px",
730
+ background: "none",
731
+ border: "1px solid #d1d5db",
732
+ borderRadius: 6,
733
+ cursor: "pointer",
734
+ color: "#374151"
735
+ };
736
+ var submitBtnStyle = {
737
+ fontSize: 12,
738
+ padding: "4px 12px",
739
+ background: "#6366f1",
740
+ border: "none",
741
+ borderRadius: 6,
742
+ cursor: "pointer",
743
+ color: "#fff",
744
+ fontWeight: 600
745
+ };
746
+
747
+ // src/hooks/useAllFieldPaths.ts
748
+ function useAllFieldPaths(excludeStepId, excludeFieldId) {
749
+ const { schema } = useBuilderStore();
750
+ const paths = [];
751
+ for (const step of schema.steps) {
752
+ for (const field of step.fields) {
753
+ if (step.id === excludeStepId && field.id === excludeFieldId) continue;
754
+ paths.push({
755
+ path: `${step.id}.${field.id}`,
756
+ label: `${step.title} \u2192 ${field.label}`,
757
+ stepId: step.id,
758
+ fieldId: field.id
759
+ });
760
+ }
761
+ }
762
+ for (const extVar of schema.externalVariables ?? []) {
763
+ paths.push({
764
+ path: `$ext.${extVar.id}`,
765
+ label: `Ext: ${extVar.label}`,
766
+ isExternal: true
767
+ });
768
+ }
769
+ return paths;
770
+ }
771
+ var OPERATORS = [
772
+ { value: "equals", label: "equals", hasValue: true },
773
+ { value: "notEquals", label: "not equals", hasValue: true },
774
+ { value: "greaterThan", label: ">", hasValue: true },
775
+ { value: "greaterThanOrEqual", label: ">=", hasValue: true },
776
+ { value: "lessThan", label: "<", hasValue: true },
777
+ { value: "lessThanOrEqual", label: "<=", hasValue: true },
778
+ { value: "contains", label: "contains", hasValue: true },
779
+ { value: "notContains", label: "not contains", hasValue: true },
780
+ { value: "in", label: "in (comma list)", hasValue: true },
781
+ { value: "notIn", label: "not in (comma list)", hasValue: true },
782
+ { value: "matches", label: "matches regex", hasValue: true },
783
+ { value: "exists", label: "exists", hasValue: false },
784
+ { value: "notExists", label: "not exists", hasValue: false }
785
+ ];
786
+ function ConditionBuilder({
787
+ value,
788
+ onChange,
789
+ excludeStepId,
790
+ excludeFieldId
791
+ }) {
792
+ const allPaths = useAllFieldPaths(excludeStepId, excludeFieldId);
793
+ const group = value ?? { combinator: "and", rules: [] };
794
+ const updateRule = (index, updates) => {
795
+ const rules = group.rules.map((r, i) => i === index ? { ...r, ...updates } : r);
796
+ onChange({ ...group, rules });
797
+ };
798
+ const addRule = () => {
799
+ const firstPath = allPaths[0]?.path ?? "";
800
+ onChange({
801
+ ...group,
802
+ rules: [...group.rules, { field: firstPath, operator: "equals", value: "" }]
803
+ });
804
+ };
805
+ const removeRule = (index) => {
806
+ const rules = group.rules.filter((_, i) => i !== index);
807
+ if (rules.length === 0) {
808
+ onChange(void 0);
809
+ return;
810
+ }
811
+ onChange({ ...group, rules });
812
+ };
813
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.container, children: [
814
+ group.rules.length > 1 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.combinatorRow, children: [
815
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.combinatorLabel, children: "Match" }),
816
+ ["and", "or"].map((c) => /* @__PURE__ */ jsxRuntime.jsx(
817
+ "button",
818
+ {
819
+ style: {
820
+ ...styles.combinatorBtn,
821
+ ...group.combinator === c ? styles.combinatorActive : {}
822
+ },
823
+ onClick: () => onChange({ ...group, combinator: c }),
824
+ children: c.toUpperCase()
825
+ },
826
+ c
827
+ )),
828
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.combinatorLabel, children: "rules" })
829
+ ] }),
830
+ group.rules.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.empty, children: "No conditions \u2014 this step/field is always visible." }),
831
+ group.rules.map((rule, index) => {
832
+ const opDef = OPERATORS.find((o) => o.value === rule.operator);
833
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.rule, children: [
834
+ /* @__PURE__ */ jsxRuntime.jsxs(
835
+ "select",
836
+ {
837
+ style: styles.select,
838
+ value: rule.field,
839
+ onChange: (e) => updateRule(index, { field: e.target.value }),
840
+ children: [
841
+ allPaths.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "No fields available" }),
842
+ allPaths.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.path, children: p.label }, p.path))
843
+ ]
844
+ }
845
+ ),
846
+ /* @__PURE__ */ jsxRuntime.jsx(
847
+ "select",
848
+ {
849
+ style: { ...styles.select, width: 140 },
850
+ value: rule.operator,
851
+ onChange: (e) => updateRule(index, { operator: e.target.value }),
852
+ children: OPERATORS.map((o) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: o.value, children: o.label }, o.value))
853
+ }
854
+ ),
855
+ opDef?.hasValue && /* @__PURE__ */ jsxRuntime.jsx(
856
+ "input",
857
+ {
858
+ style: styles.valueInput,
859
+ placeholder: "value",
860
+ value: rule.value != null ? String(rule.value) : "",
861
+ onChange: (e) => updateRule(index, { value: e.target.value })
862
+ }
863
+ ),
864
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles.removeBtn, onClick: () => removeRule(index), children: "\u2715" })
865
+ ] }, index);
866
+ }),
867
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles.addBtn, onClick: addRule, children: "+ Add rule" }),
868
+ group.rules.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.preview, children: [
869
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.previewLabel, children: "Preview" }),
870
+ /* @__PURE__ */ jsxRuntime.jsx("pre", { style: styles.previewCode, children: JSON.stringify(group, null, 2) })
871
+ ] })
872
+ ] });
873
+ }
874
+ var styles = {
875
+ container: { display: "flex", flexDirection: "column", gap: 10 },
876
+ combinatorRow: { display: "flex", alignItems: "center", gap: 8, marginBottom: 4 },
877
+ combinatorLabel: { fontSize: 12, color: "var(--wp-text-muted)" },
878
+ combinatorBtn: {
879
+ fontSize: 11,
880
+ fontWeight: 700,
881
+ padding: "3px 10px",
882
+ borderRadius: 5,
883
+ border: "1px solid var(--wp-border-muted)",
884
+ background: "var(--wp-surface)",
885
+ cursor: "pointer",
886
+ color: "var(--wp-text-secondary)"
887
+ },
888
+ combinatorActive: {
889
+ background: "var(--wp-primary)",
890
+ color: "var(--wp-canvas)",
891
+ border: "1px solid var(--wp-primary)"
892
+ },
893
+ empty: { fontSize: 13, color: "var(--wp-text-subtle)", textAlign: "center", padding: "12px 0" },
894
+ rule: {
895
+ display: "flex",
896
+ alignItems: "center",
897
+ gap: 8,
898
+ background: "var(--wp-surface)",
899
+ border: "1px solid var(--wp-border)",
900
+ borderRadius: "var(--wp-radius-lg)",
901
+ padding: "8px 10px"
902
+ },
903
+ select: {
904
+ flex: 1,
905
+ fontSize: 12,
906
+ padding: "5px 6px",
907
+ border: "1px solid var(--wp-border-muted)",
908
+ borderRadius: "var(--wp-radius)",
909
+ background: "var(--wp-canvas)",
910
+ color: "var(--wp-text)",
911
+ minWidth: 0
912
+ },
913
+ valueInput: {
914
+ width: 100,
915
+ fontSize: 12,
916
+ padding: "5px 6px",
917
+ border: "1px solid var(--wp-border-muted)",
918
+ borderRadius: "var(--wp-radius)",
919
+ background: "var(--wp-canvas)",
920
+ color: "var(--wp-text)"
921
+ },
922
+ removeBtn: {
923
+ border: "none",
924
+ background: "transparent",
925
+ color: "var(--wp-danger)",
926
+ cursor: "pointer",
927
+ fontSize: 13,
928
+ flexShrink: 0
929
+ },
930
+ addBtn: {
931
+ fontSize: 12,
932
+ padding: "6px 12px",
933
+ background: "var(--wp-surface-muted)",
934
+ border: "1px solid var(--wp-border-muted)",
935
+ borderRadius: "var(--wp-radius)",
936
+ cursor: "pointer",
937
+ fontWeight: 500,
938
+ alignSelf: "flex-start",
939
+ color: "var(--wp-text-secondary)"
940
+ },
941
+ preview: { marginTop: 4 },
942
+ previewLabel: {
943
+ fontSize: 10,
944
+ fontWeight: 600,
945
+ color: "var(--wp-text-subtle)",
946
+ textTransform: "uppercase",
947
+ display: "block",
948
+ marginBottom: 4
949
+ },
950
+ previewCode: {
951
+ fontSize: 10,
952
+ background: "var(--wp-surface-alt)",
953
+ border: "1px solid var(--wp-border)",
954
+ borderRadius: "var(--wp-radius)",
955
+ padding: 8,
956
+ overflow: "auto",
957
+ maxHeight: 120,
958
+ margin: 0,
959
+ color: "var(--wp-text-mono)"
960
+ }
961
+ };
962
+ function DependsOnInput({
963
+ value,
964
+ onChange,
965
+ excludeStepId,
966
+ excludeFieldId
967
+ }) {
968
+ const allPaths = useAllFieldPaths(excludeStepId, excludeFieldId);
969
+ const [query, setQuery] = react.useState("");
970
+ const [open, setOpen] = react.useState(false);
971
+ const inputRef = react.useRef(null);
972
+ const containerRef = react.useRef(null);
973
+ const available = allPaths.filter(
974
+ (p) => !value.includes(p.path) && (p.path.toLowerCase().includes(query.toLowerCase()) || p.label.toLowerCase().includes(query.toLowerCase()))
975
+ );
976
+ const add = (path) => {
977
+ onChange([...value, path]);
978
+ setQuery("");
979
+ setOpen(false);
980
+ inputRef.current?.focus();
981
+ };
982
+ const remove = (path) => {
983
+ onChange(value.filter((p) => p !== path));
984
+ };
985
+ react.useEffect(() => {
986
+ const handler = (e) => {
987
+ if (!containerRef.current?.contains(e.target)) setOpen(false);
988
+ };
989
+ document.addEventListener("mousedown", handler);
990
+ return () => document.removeEventListener("mousedown", handler);
991
+ }, []);
992
+ const getLabel = (path) => allPaths.find((p) => p.path === path)?.label ?? path;
993
+ const isExternal = (path) => path.startsWith("$ext.");
994
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, style: styles2.container, children: [
995
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.tags, children: [
996
+ value.map((path) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { ...styles2.tag, ...isExternal(path) ? styles2.tagExt : {} }, children: [
997
+ getLabel(path),
998
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles2.tagRemove, onClick: () => remove(path), children: "\u2715" })
999
+ ] }, path)),
1000
+ /* @__PURE__ */ jsxRuntime.jsx(
1001
+ "input",
1002
+ {
1003
+ ref: inputRef,
1004
+ style: styles2.input,
1005
+ placeholder: value.length === 0 ? "Search fields or $ext vars\u2026" : "Add more\u2026",
1006
+ value: query,
1007
+ onChange: (e) => {
1008
+ setQuery(e.target.value);
1009
+ setOpen(true);
1010
+ },
1011
+ onFocus: () => setOpen(true)
1012
+ }
1013
+ )
1014
+ ] }),
1015
+ open && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles2.dropdown, children: [
1016
+ available.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles2.noResults, children: allPaths.length === 0 ? "No fields available in the tree yet." : "No matching fields." }),
1017
+ available.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(
1018
+ "button",
1019
+ {
1020
+ style: styles2.option,
1021
+ onMouseDown: (e) => {
1022
+ e.preventDefault();
1023
+ add(p.path);
1024
+ },
1025
+ children: [
1026
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles2.optionLabel, children: p.label }),
1027
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles2.optionPath, children: p.path })
1028
+ ]
1029
+ },
1030
+ p.path
1031
+ ))
1032
+ ] }),
1033
+ value.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles2.hint, children: "This field will be blocked until all dependencies have a value." })
1034
+ ] });
1035
+ }
1036
+ var styles2 = {
1037
+ container: { position: "relative" },
1038
+ tags: {
1039
+ display: "flex",
1040
+ flexWrap: "wrap",
1041
+ gap: 4,
1042
+ border: "1px solid var(--wp-border-muted)",
1043
+ borderRadius: "var(--wp-radius)",
1044
+ padding: "4px 6px",
1045
+ background: "var(--wp-canvas)",
1046
+ minHeight: 34,
1047
+ alignItems: "center"
1048
+ },
1049
+ tag: {
1050
+ display: "flex",
1051
+ alignItems: "center",
1052
+ gap: 4,
1053
+ fontSize: 11,
1054
+ fontWeight: 600,
1055
+ padding: "2px 8px",
1056
+ background: "var(--wp-primary-bg)",
1057
+ color: "var(--wp-primary-dark)",
1058
+ borderRadius: 4
1059
+ },
1060
+ tagExt: { background: "var(--wp-warning-bg)", color: "var(--wp-warning)" },
1061
+ tagRemove: {
1062
+ border: "none",
1063
+ background: "transparent",
1064
+ cursor: "pointer",
1065
+ color: "inherit",
1066
+ fontSize: 10,
1067
+ padding: 0,
1068
+ lineHeight: 1
1069
+ },
1070
+ input: {
1071
+ flex: 1,
1072
+ minWidth: 140,
1073
+ fontSize: 12,
1074
+ border: "none",
1075
+ outline: "none",
1076
+ background: "transparent",
1077
+ padding: "2px 4px",
1078
+ color: "var(--wp-text)"
1079
+ },
1080
+ dropdown: {
1081
+ position: "absolute",
1082
+ top: "calc(100% + 4px)",
1083
+ left: 0,
1084
+ right: 0,
1085
+ background: "var(--wp-canvas)",
1086
+ border: "1px solid var(--wp-border)",
1087
+ borderRadius: "var(--wp-radius-lg)",
1088
+ boxShadow: "0 4px 16px rgba(0,0,0,0.1)",
1089
+ zIndex: 100,
1090
+ maxHeight: 200,
1091
+ overflowY: "auto"
1092
+ },
1093
+ noResults: { padding: "10px 12px", fontSize: 12, color: "var(--wp-text-subtle)", textAlign: "center" },
1094
+ option: {
1095
+ width: "100%",
1096
+ display: "flex",
1097
+ alignItems: "center",
1098
+ justifyContent: "space-between",
1099
+ padding: "8px 12px",
1100
+ border: "none",
1101
+ background: "transparent",
1102
+ cursor: "pointer",
1103
+ textAlign: "left",
1104
+ gap: 8
1105
+ },
1106
+ optionLabel: { fontSize: 13, fontWeight: 600, color: "var(--wp-text)" },
1107
+ optionPath: { fontSize: 10, fontFamily: "monospace", color: "var(--wp-text-subtle)" },
1108
+ hint: { fontSize: 10, color: "var(--wp-text-subtle)", marginTop: 4 }
1109
+ };
1110
+ function Modal({ title, onClose, children, width = 560 }) {
1111
+ react.useEffect(() => {
1112
+ const handler = (e) => {
1113
+ if (e.key === "Escape") onClose();
1114
+ };
1115
+ document.addEventListener("keydown", handler);
1116
+ return () => document.removeEventListener("keydown", handler);
1117
+ }, [onClose]);
1118
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.overlay, onClick: onClose, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...styles3.panel, width }, onClick: (e) => e.stopPropagation(), children: [
1119
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles3.header, children: [
1120
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles3.title, children: title }),
1121
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles3.closeBtn, onClick: onClose, children: "\u2715" })
1122
+ ] }),
1123
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles3.body, children })
1124
+ ] }) });
1125
+ }
1126
+ var styles3 = {
1127
+ overlay: {
1128
+ position: "fixed",
1129
+ inset: 0,
1130
+ background: "rgba(0,0,0,0.4)",
1131
+ display: "flex",
1132
+ alignItems: "center",
1133
+ justifyContent: "center",
1134
+ zIndex: 1e3
1135
+ },
1136
+ panel: {
1137
+ background: "var(--wp-canvas)",
1138
+ borderRadius: 12,
1139
+ boxShadow: "0 20px 60px rgba(0,0,0,0.2)",
1140
+ display: "flex",
1141
+ flexDirection: "column",
1142
+ maxHeight: "80vh",
1143
+ overflow: "hidden"
1144
+ },
1145
+ header: {
1146
+ display: "flex",
1147
+ alignItems: "center",
1148
+ justifyContent: "space-between",
1149
+ padding: "14px 20px",
1150
+ borderBottom: "1px solid var(--wp-border)"
1151
+ },
1152
+ title: { fontWeight: 700, fontSize: 14, color: "var(--wp-text)" },
1153
+ closeBtn: {
1154
+ border: "none",
1155
+ background: "transparent",
1156
+ cursor: "pointer",
1157
+ fontSize: 14,
1158
+ color: "var(--wp-text-subtle)",
1159
+ padding: 4
1160
+ },
1161
+ body: { overflowY: "auto", padding: 20, color: "var(--wp-text)" }
1162
+ };
1163
+ var VALIDATION_TYPES = [
1164
+ { type: "required", label: "Required", hasValue: false },
1165
+ { type: "min", label: "Min value", hasValue: true },
1166
+ { type: "max", label: "Max value", hasValue: true },
1167
+ { type: "minLength", label: "Min length", hasValue: true },
1168
+ { type: "maxLength", label: "Max length", hasValue: true },
1169
+ { type: "email", label: "Email format", hasValue: false },
1170
+ { type: "url", label: "URL format", hasValue: false },
1171
+ { type: "regex", label: "Regex pattern", hasValue: true }
1172
+ ];
1173
+ function FieldEditor() {
1174
+ const {
1175
+ schema,
1176
+ selectedStepId,
1177
+ selectedFieldId,
1178
+ updateField,
1179
+ setFieldCondition
1180
+ } = useBuilderStore();
1181
+ const [newValidationType, setNewValidationType] = react.useState("required");
1182
+ const [conditionModalOpen, setConditionModalOpen] = react.useState(false);
1183
+ const step = schema.steps.find((s) => s.id === selectedStepId);
1184
+ const field = step?.fields.find((f) => f.id === selectedFieldId);
1185
+ if (!field || !step) {
1186
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.empty, children: "Select a field in the middle panel to edit its properties." });
1187
+ }
1188
+ const validation = field.validation ?? [];
1189
+ const isRequired = validation.some((v) => v.type === "required");
1190
+ const hasCondition = !!field.visibleWhen;
1191
+ const ruleCount = field.visibleWhen?.rules.length ?? 0;
1192
+ const updateValidationRule = (index, updates) => {
1193
+ const updated = validation.map((v, i) => i === index ? { ...v, ...updates } : v);
1194
+ updateField(step.id, field.id, { validation: updated });
1195
+ };
1196
+ const removeValidationRule = (index) => {
1197
+ const updated = validation.filter((_, i) => i !== index);
1198
+ updateField(step.id, field.id, { validation: updated.length ? updated : void 0 });
1199
+ };
1200
+ const addValidationRule = () => {
1201
+ const newRule = {
1202
+ type: newValidationType,
1203
+ message: `${newValidationType} error`
1204
+ };
1205
+ updateField(step.id, field.id, { validation: [...validation, newRule] });
1206
+ };
1207
+ const handleDependsOnChange = (paths) => {
1208
+ updateField(step.id, field.id, { dependsOn: paths.length ? paths : void 0 });
1209
+ };
1210
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.container, children: [
1211
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.header, children: [
1212
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.headerLeft, children: [
1213
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.headerTitle, children: "Field Editor" }),
1214
+ !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.optionalBadge, children: "optional" }),
1215
+ isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.requiredBadge, children: "required" })
1216
+ ] }),
1217
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.fieldId, children: [
1218
+ "id: ",
1219
+ field.id
1220
+ ] })
1221
+ ] }),
1222
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.body, children: [
1223
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1224
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Label" }),
1225
+ /* @__PURE__ */ jsxRuntime.jsx(
1226
+ "input",
1227
+ {
1228
+ style: styles4.input,
1229
+ value: field.label,
1230
+ onChange: (e) => updateField(step.id, field.id, { label: e.target.value })
1231
+ }
1232
+ )
1233
+ ] }),
1234
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1235
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Placeholder" }),
1236
+ /* @__PURE__ */ jsxRuntime.jsx(
1237
+ "input",
1238
+ {
1239
+ style: styles4.input,
1240
+ value: field.placeholder ?? "",
1241
+ placeholder: "Optional",
1242
+ onChange: (e) => updateField(step.id, field.id, { placeholder: e.target.value || void 0 })
1243
+ }
1244
+ )
1245
+ ] }),
1246
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1247
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Default value" }),
1248
+ /* @__PURE__ */ jsxRuntime.jsx(
1249
+ "input",
1250
+ {
1251
+ style: styles4.input,
1252
+ value: field.defaultValue != null ? String(field.defaultValue) : "",
1253
+ placeholder: "Optional",
1254
+ onChange: (e) => updateField(step.id, field.id, { defaultValue: e.target.value || void 0 })
1255
+ }
1256
+ )
1257
+ ] }),
1258
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.group, children: [
1259
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.label, children: "Depends on" }),
1260
+ /* @__PURE__ */ jsxRuntime.jsx(
1261
+ DependsOnInput,
1262
+ {
1263
+ value: field.dependsOn ?? [],
1264
+ onChange: handleDependsOnChange,
1265
+ excludeStepId: step.id,
1266
+ excludeFieldId: field.id
1267
+ }
1268
+ )
1269
+ ] }),
1270
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
1271
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionRow, children: [
1272
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionInfo, children: [
1273
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.label, children: "Visibility condition" }),
1274
+ hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionSummary, children: [
1275
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles4.conditionBadge, children: [
1276
+ ruleCount,
1277
+ " rule",
1278
+ ruleCount !== 1 ? "s" : "",
1279
+ " \xB7 ",
1280
+ field.visibleWhen.combinator.toUpperCase()
1281
+ ] }),
1282
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.conditionDesc, children: "Field is conditional" })
1283
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.conditionNone, children: "Always visible" })
1284
+ ] }),
1285
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.conditionActions, children: [
1286
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.editConditionBtn, onClick: () => setConditionModalOpen(true), children: hasCondition ? "Edit" : "Add" }),
1287
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx(
1288
+ "button",
1289
+ {
1290
+ style: styles4.clearConditionBtn,
1291
+ onClick: () => setFieldCondition(step.id, field.id, void 0),
1292
+ children: "Clear"
1293
+ }
1294
+ )
1295
+ ] })
1296
+ ] }),
1297
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
1298
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.sectionTitle, children: [
1299
+ "Validation",
1300
+ !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles4.optionalHint, children: '\u2014 no "required" rule \u2192 field is optional' })
1301
+ ] }),
1302
+ validation.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.noRules, children: "No rules \xB7 field is optional by default." }),
1303
+ validation.map((rule, index) => {
1304
+ const def = VALIDATION_TYPES.find((vt) => vt.type === rule.type);
1305
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleCard, children: [
1306
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleHeader, children: [
1307
+ /* @__PURE__ */ jsxRuntime.jsx(
1308
+ "span",
1309
+ {
1310
+ style: {
1311
+ ...styles4.ruleBadge,
1312
+ ...rule.type === "required" ? styles4.requiredRuleBadge : {}
1313
+ },
1314
+ children: rule.type
1315
+ }
1316
+ ),
1317
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.removeRuleBtn, onClick: () => removeValidationRule(index), children: "\u2715" })
1318
+ ] }),
1319
+ def?.hasValue && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleRow, children: [
1320
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.ruleLabel, children: "Value" }),
1321
+ /* @__PURE__ */ jsxRuntime.jsx(
1322
+ "input",
1323
+ {
1324
+ style: styles4.ruleInput,
1325
+ value: rule.value != null ? String(rule.value) : "",
1326
+ onChange: (e) => updateValidationRule(index, { value: e.target.value })
1327
+ }
1328
+ )
1329
+ ] }),
1330
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.ruleRow, children: [
1331
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles4.ruleLabel, children: "Error message" }),
1332
+ /* @__PURE__ */ jsxRuntime.jsx(
1333
+ "input",
1334
+ {
1335
+ style: styles4.ruleInput,
1336
+ value: rule.message,
1337
+ onChange: (e) => updateValidationRule(index, { message: e.target.value })
1338
+ }
1339
+ )
1340
+ ] })
1341
+ ] }, index);
1342
+ }),
1343
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles4.addRule, children: [
1344
+ /* @__PURE__ */ jsxRuntime.jsx(
1345
+ "select",
1346
+ {
1347
+ style: styles4.ruleSelect,
1348
+ value: newValidationType,
1349
+ onChange: (e) => setNewValidationType(e.target.value),
1350
+ children: VALIDATION_TYPES.map((vt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: vt.type, children: vt.label }, vt.type))
1351
+ }
1352
+ ),
1353
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.addRuleBtn, onClick: addValidationRule, children: "+ Add rule" })
1354
+ ] })
1355
+ ] }),
1356
+ conditionModalOpen && /* @__PURE__ */ jsxRuntime.jsxs(
1357
+ Modal,
1358
+ {
1359
+ title: `Condition \u2014 "${field.label}"`,
1360
+ onClose: () => setConditionModalOpen(false),
1361
+ width: 620,
1362
+ children: [
1363
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles4.modalHint, children: "Define when this field is visible within its step." }),
1364
+ /* @__PURE__ */ jsxRuntime.jsx(
1365
+ ConditionBuilder,
1366
+ {
1367
+ value: field.visibleWhen,
1368
+ onChange: (c) => setFieldCondition(step.id, field.id, c),
1369
+ excludeStepId: step.id,
1370
+ excludeFieldId: field.id
1371
+ }
1372
+ ),
1373
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles4.modalCloseBtn, onClick: () => setConditionModalOpen(false), children: "Done" }) })
1374
+ ]
1375
+ }
1376
+ )
1377
+ ] });
1378
+ }
1379
+ var styles4 = {
1380
+ container: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" },
1381
+ empty: {
1382
+ display: "flex",
1383
+ alignItems: "center",
1384
+ justifyContent: "center",
1385
+ height: "100%",
1386
+ color: "var(--wp-text-subtle)",
1387
+ fontSize: 13,
1388
+ textAlign: "center",
1389
+ padding: 32
1390
+ },
1391
+ header: {
1392
+ padding: "12px 16px",
1393
+ borderBottom: "1px solid var(--wp-border)",
1394
+ display: "flex",
1395
+ justifyContent: "space-between",
1396
+ alignItems: "center"
1397
+ },
1398
+ headerLeft: { display: "flex", alignItems: "center", gap: 8 },
1399
+ headerTitle: { fontWeight: 700, fontSize: 13, color: "var(--wp-text)" },
1400
+ optionalBadge: {
1401
+ fontSize: 10,
1402
+ fontWeight: 600,
1403
+ padding: "2px 7px",
1404
+ background: "var(--wp-surface-muted)",
1405
+ color: "var(--wp-text-subtle)",
1406
+ borderRadius: 4
1407
+ },
1408
+ requiredBadge: {
1409
+ fontSize: 10,
1410
+ fontWeight: 600,
1411
+ padding: "2px 7px",
1412
+ background: "var(--wp-danger-bg-strong)",
1413
+ color: "var(--wp-danger)",
1414
+ borderRadius: 4
1415
+ },
1416
+ fieldId: { fontSize: 10, color: "var(--wp-text-subtle)", fontFamily: "monospace" },
1417
+ body: { flex: 1, overflowY: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 12 },
1418
+ group: { display: "flex", flexDirection: "column", gap: 4 },
1419
+ label: { fontSize: 11, fontWeight: 600, color: "var(--wp-text-muted)", textTransform: "uppercase", letterSpacing: "0.05em" },
1420
+ input: {
1421
+ fontSize: 13,
1422
+ padding: "6px 8px",
1423
+ border: "1px solid var(--wp-border-muted)",
1424
+ borderRadius: "var(--wp-radius)",
1425
+ outline: "none",
1426
+ background: "var(--wp-canvas)",
1427
+ color: "var(--wp-text)"
1428
+ },
1429
+ divider: { height: 1, background: "var(--wp-border)" },
1430
+ conditionRow: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 8 },
1431
+ conditionInfo: { display: "flex", flexDirection: "column", gap: 6, flex: 1 },
1432
+ conditionSummary: { display: "flex", alignItems: "center", gap: 8 },
1433
+ conditionBadge: {
1434
+ fontSize: 11,
1435
+ fontWeight: 700,
1436
+ background: "var(--wp-warning-bg)",
1437
+ color: "var(--wp-warning)",
1438
+ padding: "2px 8px",
1439
+ borderRadius: 4
1440
+ },
1441
+ conditionDesc: { fontSize: 11, color: "var(--wp-text-subtle)" },
1442
+ conditionNone: { fontSize: 12, color: "var(--wp-text-subtle)", fontStyle: "italic" },
1443
+ conditionActions: { display: "flex", gap: 6, flexShrink: 0, alignItems: "flex-start", marginTop: 16 },
1444
+ editConditionBtn: {
1445
+ fontSize: 11,
1446
+ padding: "4px 10px",
1447
+ background: "var(--wp-primary)",
1448
+ color: "var(--wp-canvas)",
1449
+ border: "none",
1450
+ borderRadius: "var(--wp-radius)",
1451
+ cursor: "pointer",
1452
+ fontWeight: 500
1453
+ },
1454
+ clearConditionBtn: {
1455
+ fontSize: 11,
1456
+ padding: "4px 10px",
1457
+ background: "var(--wp-danger-bg-strong)",
1458
+ color: "var(--wp-danger)",
1459
+ border: "none",
1460
+ borderRadius: "var(--wp-radius)",
1461
+ cursor: "pointer"
1462
+ },
1463
+ sectionTitle: { fontSize: 12, fontWeight: 700, color: "var(--wp-text-secondary)", textTransform: "uppercase", letterSpacing: "0.05em" },
1464
+ optionalHint: { fontSize: 10, color: "var(--wp-text-subtle)", fontWeight: 400, textTransform: "none", letterSpacing: 0 },
1465
+ noRules: { fontSize: 12, color: "var(--wp-text-subtle)" },
1466
+ ruleCard: {
1467
+ background: "var(--wp-surface)",
1468
+ border: "1px solid var(--wp-border)",
1469
+ borderRadius: "var(--wp-radius-lg)",
1470
+ padding: 10,
1471
+ display: "flex",
1472
+ flexDirection: "column",
1473
+ gap: 8
1474
+ },
1475
+ ruleHeader: { display: "flex", justifyContent: "space-between", alignItems: "center" },
1476
+ ruleBadge: {
1477
+ fontSize: 11,
1478
+ fontWeight: 700,
1479
+ color: "var(--wp-primary-dark)",
1480
+ background: "var(--wp-primary-bg)",
1481
+ padding: "2px 8px",
1482
+ borderRadius: 4
1483
+ },
1484
+ requiredRuleBadge: { background: "var(--wp-danger-bg-strong)", color: "var(--wp-danger)" },
1485
+ removeRuleBtn: { border: "none", background: "transparent", color: "var(--wp-danger)", cursor: "pointer", fontSize: 12 },
1486
+ ruleRow: { display: "flex", flexDirection: "column", gap: 3 },
1487
+ ruleLabel: { fontSize: 10, fontWeight: 600, color: "var(--wp-text-subtle)", textTransform: "uppercase" },
1488
+ ruleInput: {
1489
+ fontSize: 12,
1490
+ padding: "4px 6px",
1491
+ border: "1px solid var(--wp-border-muted)",
1492
+ borderRadius: 4,
1493
+ outline: "none",
1494
+ background: "var(--wp-canvas)",
1495
+ color: "var(--wp-text)"
1496
+ },
1497
+ addRule: { display: "flex", gap: 8, alignItems: "center" },
1498
+ ruleSelect: {
1499
+ flex: 1,
1500
+ fontSize: 12,
1501
+ padding: "5px 6px",
1502
+ border: "1px solid var(--wp-border-muted)",
1503
+ borderRadius: "var(--wp-radius)",
1504
+ background: "var(--wp-canvas)",
1505
+ color: "var(--wp-text)"
1506
+ },
1507
+ addRuleBtn: {
1508
+ fontSize: 12,
1509
+ padding: "5px 10px",
1510
+ background: "var(--wp-surface-muted)",
1511
+ border: "1px solid var(--wp-border-muted)",
1512
+ borderRadius: "var(--wp-radius)",
1513
+ cursor: "pointer",
1514
+ fontWeight: 500,
1515
+ whiteSpace: "nowrap",
1516
+ color: "var(--wp-text-secondary)"
1517
+ },
1518
+ modalHint: { fontSize: 13, color: "var(--wp-text-muted)", marginBottom: 16, marginTop: 0 },
1519
+ modalFooter: { marginTop: 20, display: "flex", justifyContent: "flex-end" },
1520
+ modalCloseBtn: {
1521
+ fontSize: 13,
1522
+ padding: "7px 20px",
1523
+ background: "var(--wp-primary)",
1524
+ color: "var(--wp-canvas)",
1525
+ border: "none",
1526
+ borderRadius: "var(--wp-radius-lg)",
1527
+ cursor: "pointer",
1528
+ fontWeight: 600
1529
+ }
1530
+ };
1531
+
1532
+ // src/utils/step-dependencies.ts
1533
+ function extractStepIdsFromCondition(group, ownStepId) {
1534
+ const ids = /* @__PURE__ */ new Set();
1535
+ if (!group) return ids;
1536
+ for (const rule of group.rules) {
1537
+ if (rule.field.startsWith("$ext.")) continue;
1538
+ const dotIndex = rule.field.indexOf(".");
1539
+ if (dotIndex === -1) continue;
1540
+ const refStep = rule.field.slice(0, dotIndex);
1541
+ if (refStep !== ownStepId) ids.add(refStep);
1542
+ }
1543
+ for (const subGroup of group.groups ?? []) {
1544
+ for (const id of extractStepIdsFromCondition(subGroup, ownStepId)) {
1545
+ ids.add(id);
1546
+ }
1547
+ }
1548
+ return ids;
1549
+ }
1550
+ function computeStepDependencies(schema) {
1551
+ const deps = /* @__PURE__ */ new Map();
1552
+ for (const step of schema.steps) {
1553
+ const required = /* @__PURE__ */ new Set();
1554
+ for (const id of extractStepIdsFromCondition(step.visibleWhen, step.id)) {
1555
+ required.add(id);
1556
+ }
1557
+ for (const field of step.fields) {
1558
+ for (const path of field.dependsOn ?? []) {
1559
+ if (path.startsWith("$ext.")) continue;
1560
+ const dotIndex = path.indexOf(".");
1561
+ if (dotIndex === -1) continue;
1562
+ const refStep = path.slice(0, dotIndex);
1563
+ if (refStep !== step.id) required.add(refStep);
1564
+ }
1565
+ for (const id of extractStepIdsFromCondition(field.visibleWhen, step.id)) {
1566
+ required.add(id);
1567
+ }
1568
+ }
1569
+ deps.set(step.id, required);
1570
+ }
1571
+ return deps;
1572
+ }
1573
+ function isMoveValid(steps, deps, fromIndex, toIndex) {
1574
+ if (fromIndex === toIndex) return { valid: true };
1575
+ const reordered = [...steps];
1576
+ const [moved] = reordered.splice(fromIndex, 1);
1577
+ reordered.splice(toIndex, 0, moved);
1578
+ const indexById = new Map(reordered.map((s, i) => [s.id, i]));
1579
+ for (const step of reordered) {
1580
+ const stepIndex = indexById.get(step.id);
1581
+ const required = deps.get(step.id) ?? /* @__PURE__ */ new Set();
1582
+ for (const depId of required) {
1583
+ const depIndex = indexById.get(depId);
1584
+ if (depIndex === void 0) continue;
1585
+ if (depIndex > stepIndex) {
1586
+ const depTitle = reordered.find((s) => s.id === depId)?.title ?? depId;
1587
+ return {
1588
+ valid: false,
1589
+ reason: `"${step.title}" depends on "${depTitle}" which must come first`
1590
+ };
1591
+ }
1592
+ }
1593
+ }
1594
+ return { valid: true };
1595
+ }
1596
+ function isFieldMoveValid(fields, stepId, fromIndex, toIndex) {
1597
+ if (fromIndex === toIndex) return { valid: true };
1598
+ const reordered = [...fields];
1599
+ const [moved] = reordered.splice(fromIndex, 1);
1600
+ reordered.splice(toIndex, 0, moved);
1601
+ const indexById = new Map(reordered.map((f, i) => [f.id, i]));
1602
+ for (const field of reordered) {
1603
+ const fieldIndex = indexById.get(field.id);
1604
+ for (const path of field.dependsOn ?? []) {
1605
+ if (path.startsWith("$ext.")) continue;
1606
+ const dotIndex = path.indexOf(".");
1607
+ if (dotIndex === -1) continue;
1608
+ const refStep = path.slice(0, dotIndex);
1609
+ if (refStep !== stepId) continue;
1610
+ const refFieldId = path.slice(dotIndex + 1);
1611
+ const depIndex = indexById.get(refFieldId);
1612
+ if (depIndex === void 0) continue;
1613
+ if (depIndex > fieldIndex) {
1614
+ const depLabel = reordered.find((f) => f.id === refFieldId)?.label ?? refFieldId;
1615
+ return {
1616
+ valid: false,
1617
+ reason: `"${field.label}" depends on "${depLabel}" which must come first`
1618
+ };
1619
+ }
1620
+ }
1621
+ }
1622
+ return { valid: true };
1623
+ }
1624
+ function getStepDependencyLabels(stepId, deps, schema) {
1625
+ const required = deps.get(stepId) ?? /* @__PURE__ */ new Set();
1626
+ return [...required].map((id) => schema.steps.find((s) => s.id === id)?.title ?? id).filter(Boolean);
1627
+ }
1628
+ var FIELD_TYPES = [
1629
+ "text",
1630
+ "number",
1631
+ "email",
1632
+ "password",
1633
+ "tel",
1634
+ "url",
1635
+ "textarea",
1636
+ "select",
1637
+ "multiselect",
1638
+ "checkbox",
1639
+ "radio",
1640
+ "date",
1641
+ "file"
1642
+ ];
1643
+ function FieldList() {
1644
+ const {
1645
+ schema,
1646
+ selectedStepId,
1647
+ selectedFieldId,
1648
+ addField,
1649
+ removeField,
1650
+ updateField,
1651
+ selectField,
1652
+ reorderFields
1653
+ } = useBuilderStore();
1654
+ const [moveError, setMoveError] = react.useState(null);
1655
+ const step = schema.steps.find((s) => s.id === selectedStepId);
1656
+ const allDependencyTargets = /* @__PURE__ */ new Set();
1657
+ for (const s of schema.steps) {
1658
+ for (const f of s.fields) {
1659
+ for (const dep of f.dependsOn ?? []) {
1660
+ allDependencyTargets.add(dep);
1661
+ }
1662
+ }
1663
+ }
1664
+ if (!step) {
1665
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.empty, children: "Select a step on the left to manage its fields." });
1666
+ }
1667
+ const tryMove = (fromIndex, toIndex) => {
1668
+ const check = isFieldMoveValid(step.fields, step.id, fromIndex, toIndex);
1669
+ if (!check.valid) {
1670
+ setMoveError(check.reason ?? "Invalid move");
1671
+ setTimeout(() => setMoveError(null), 3e3);
1672
+ return;
1673
+ }
1674
+ setMoveError(null);
1675
+ reorderFields(step.id, fromIndex, toIndex);
1676
+ };
1677
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.container, children: [
1678
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.header, children: [
1679
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1680
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.stepTitle, children: step.title }),
1681
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.stepSub, children: [
1682
+ step.fields.length,
1683
+ " field",
1684
+ step.fields.length !== 1 ? "s" : ""
1685
+ ] })
1686
+ ] }),
1687
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles5.addBtn, onClick: () => addField(step.id), children: "+ Add field" })
1688
+ ] }),
1689
+ moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.errorBanner, children: [
1690
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u26A0" }),
1691
+ " ",
1692
+ moveError
1693
+ ] }),
1694
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.list, children: [
1695
+ step.fields.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.emptyFields, children: 'No fields yet. Click "Add field" to start.' }),
1696
+ step.fields.map((field, index) => {
1697
+ const isSelected = field.id === selectedFieldId;
1698
+ const isRequired = field.validation?.some((v) => v.type === "required") ?? false;
1699
+ const hasCondition = !!field.visibleWhen;
1700
+ const hasDeps = (field.dependsOn?.length ?? 0) > 0;
1701
+ const isUsedAsDep = allDependencyTargets.has(`${step.id}.${field.id}`);
1702
+ const canMoveUp = index > 0 && isFieldMoveValid(step.fields, step.id, index, index - 1).valid;
1703
+ const canMoveDown = index < step.fields.length - 1 && isFieldMoveValid(step.fields, step.id, index, index + 1).valid;
1704
+ const intraStepDeps = (field.dependsOn ?? []).filter((p) => p.startsWith(`${step.id}.`)).map((p) => {
1705
+ const fieldId = p.slice(step.id.length + 1);
1706
+ return step.fields.find((f) => f.id === fieldId)?.label ?? fieldId;
1707
+ });
1708
+ const intraStepDependents = step.fields.filter(
1709
+ (f) => f.id !== field.id && (f.dependsOn ?? []).includes(`${step.id}.${field.id}`)
1710
+ );
1711
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1712
+ "div",
1713
+ {
1714
+ style: { ...styles5.card, ...isSelected ? styles5.cardSelected : {} },
1715
+ onClick: () => selectField(field.id),
1716
+ children: [
1717
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardTop, children: [
1718
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardLeft, children: [
1719
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.typeBadge, children: field.type }),
1720
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.fieldLabel, children: field.label })
1721
+ ] }),
1722
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.cardRight, children: [
1723
+ /* @__PURE__ */ jsxRuntime.jsx(
1724
+ "select",
1725
+ {
1726
+ style: styles5.typeSelect,
1727
+ value: field.type,
1728
+ onClick: (e) => e.stopPropagation(),
1729
+ onChange: (e) => updateField(step.id, field.id, { type: e.target.value }),
1730
+ children: FIELD_TYPES.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t, children: t }, t))
1731
+ }
1732
+ ),
1733
+ index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1734
+ "button",
1735
+ {
1736
+ style: { ...styles5.iconBtn, ...canMoveUp ? {} : styles5.iconBtnBlocked },
1737
+ title: canMoveUp ? "Move up" : "Can't move \u2014 dependency order required",
1738
+ onClick: (e) => {
1739
+ e.stopPropagation();
1740
+ tryMove(index, index - 1);
1741
+ },
1742
+ children: "\u2191"
1743
+ }
1744
+ ),
1745
+ index < step.fields.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
1746
+ "button",
1747
+ {
1748
+ style: { ...styles5.iconBtn, ...canMoveDown ? {} : styles5.iconBtnBlocked },
1749
+ title: canMoveDown ? "Move down" : "Can't move \u2014 dependency order required",
1750
+ onClick: (e) => {
1751
+ e.stopPropagation();
1752
+ tryMove(index, index + 1);
1753
+ },
1754
+ children: "\u2193"
1755
+ }
1756
+ ),
1757
+ /* @__PURE__ */ jsxRuntime.jsx(
1758
+ "button",
1759
+ {
1760
+ style: { ...styles5.iconBtn, color: "var(--wp-danger)" },
1761
+ title: "Remove field",
1762
+ onClick: (e) => {
1763
+ e.stopPropagation();
1764
+ removeField(step.id, field.id);
1765
+ },
1766
+ children: "\u2715"
1767
+ }
1768
+ )
1769
+ ] })
1770
+ ] }),
1771
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.badges, children: [
1772
+ !isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeOptional, children: "optional" }),
1773
+ isRequired && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeRequired, children: "required" }),
1774
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeCondition, children: "conditional" }),
1775
+ hasDeps && /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles5.badgeDep, children: [
1776
+ "depends on ",
1777
+ field.dependsOn.length
1778
+ ] }),
1779
+ isUsedAsDep && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.badgeUsed, children: "\u2190 dependency" })
1780
+ ] }),
1781
+ intraStepDeps.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.depRow, children: [
1782
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depLabel, children: "needs:" }),
1783
+ intraStepDeps.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depBadge, children: label }, label))
1784
+ ] }),
1785
+ intraStepDependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.depRow, children: [
1786
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depLabelUsed, children: "used by:" }),
1787
+ intraStepDependents.map((f) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.depBadgeUsed, children: f.label }, f.id))
1788
+ ] })
1789
+ ]
1790
+ },
1791
+ field.id
1792
+ );
1793
+ })
1794
+ ] })
1795
+ ] });
1796
+ }
1797
+ var styles5 = {
1798
+ container: { display: "flex", flexDirection: "column", height: "100%" },
1799
+ empty: {
1800
+ display: "flex",
1801
+ alignItems: "center",
1802
+ justifyContent: "center",
1803
+ height: "100%",
1804
+ color: "var(--wp-text-subtle)",
1805
+ fontSize: 13,
1806
+ textAlign: "center",
1807
+ padding: 32
1808
+ },
1809
+ emptyFields: { padding: 24, textAlign: "center", color: "var(--wp-text-subtle)", fontSize: 13 },
1810
+ header: {
1811
+ display: "flex",
1812
+ alignItems: "center",
1813
+ justifyContent: "space-between",
1814
+ padding: "12px 16px",
1815
+ borderBottom: "1px solid var(--wp-border)"
1816
+ },
1817
+ stepTitle: { fontWeight: 700, fontSize: 14, color: "var(--wp-text)" },
1818
+ stepSub: { fontSize: 11, color: "var(--wp-text-subtle)", marginTop: 2 },
1819
+ addBtn: {
1820
+ fontSize: 12,
1821
+ padding: "4px 10px",
1822
+ background: "var(--wp-primary)",
1823
+ color: "var(--wp-canvas)",
1824
+ border: "none",
1825
+ borderRadius: "var(--wp-radius)",
1826
+ cursor: "pointer",
1827
+ fontWeight: 500
1828
+ },
1829
+ errorBanner: {
1830
+ margin: "8px 8px 0",
1831
+ padding: "8px 12px",
1832
+ background: "var(--wp-danger-bg)",
1833
+ border: "1px solid var(--wp-danger-border)",
1834
+ borderRadius: "var(--wp-radius-lg)",
1835
+ fontSize: 12,
1836
+ color: "var(--wp-danger-text)",
1837
+ display: "flex",
1838
+ alignItems: "center",
1839
+ gap: 6
1840
+ },
1841
+ list: { flex: 1, overflowY: "auto", padding: 8 },
1842
+ card: {
1843
+ padding: "10px 12px",
1844
+ borderRadius: "var(--wp-radius-lg)",
1845
+ marginBottom: 4,
1846
+ border: "1px solid transparent",
1847
+ cursor: "pointer",
1848
+ background: "var(--wp-surface)",
1849
+ display: "flex",
1850
+ flexDirection: "column",
1851
+ gap: 6
1852
+ },
1853
+ cardSelected: { background: "var(--wp-primary-muted)", border: "1px solid var(--wp-primary-border)" },
1854
+ cardTop: { display: "flex", alignItems: "center", justifyContent: "space-between" },
1855
+ cardLeft: { display: "flex", alignItems: "center", gap: 8, minWidth: 0 },
1856
+ cardRight: { display: "flex", alignItems: "center", gap: 4, flexShrink: 0 },
1857
+ typeBadge: {
1858
+ fontSize: 10,
1859
+ background: "var(--wp-primary-bg)",
1860
+ color: "var(--wp-primary-dark)",
1861
+ padding: "2px 7px",
1862
+ borderRadius: 4,
1863
+ fontWeight: 600,
1864
+ flexShrink: 0
1865
+ },
1866
+ fieldLabel: {
1867
+ fontSize: 13,
1868
+ fontWeight: 600,
1869
+ color: "var(--wp-text)",
1870
+ overflow: "hidden",
1871
+ textOverflow: "ellipsis",
1872
+ whiteSpace: "nowrap"
1873
+ },
1874
+ typeSelect: {
1875
+ fontSize: 11,
1876
+ border: "1px solid var(--wp-border)",
1877
+ borderRadius: 4,
1878
+ padding: "2px 4px",
1879
+ background: "var(--wp-canvas)",
1880
+ cursor: "pointer",
1881
+ color: "var(--wp-text-secondary)"
1882
+ },
1883
+ iconBtn: {
1884
+ width: 22,
1885
+ height: 22,
1886
+ border: "none",
1887
+ background: "transparent",
1888
+ cursor: "pointer",
1889
+ borderRadius: 4,
1890
+ fontSize: 11,
1891
+ color: "var(--wp-text-subtle)"
1892
+ },
1893
+ iconBtnBlocked: { color: "var(--wp-border-muted)", cursor: "not-allowed", opacity: 0.4 },
1894
+ badges: { display: "flex", flexWrap: "wrap", gap: 4 },
1895
+ badgeOptional: {
1896
+ fontSize: 9,
1897
+ fontWeight: 600,
1898
+ padding: "1px 6px",
1899
+ background: "var(--wp-surface-muted)",
1900
+ color: "var(--wp-text-subtle)",
1901
+ borderRadius: 3,
1902
+ textTransform: "uppercase"
1903
+ },
1904
+ badgeRequired: {
1905
+ fontSize: 9,
1906
+ fontWeight: 600,
1907
+ padding: "1px 6px",
1908
+ background: "var(--wp-danger-bg-strong)",
1909
+ color: "var(--wp-danger)",
1910
+ borderRadius: 3,
1911
+ textTransform: "uppercase"
1912
+ },
1913
+ badgeCondition: {
1914
+ fontSize: 9,
1915
+ fontWeight: 600,
1916
+ padding: "1px 6px",
1917
+ background: "var(--wp-warning-bg)",
1918
+ color: "var(--wp-warning)",
1919
+ borderRadius: 3,
1920
+ textTransform: "uppercase"
1921
+ },
1922
+ badgeDep: {
1923
+ fontSize: 9,
1924
+ fontWeight: 600,
1925
+ padding: "1px 6px",
1926
+ background: "var(--wp-primary-bg)",
1927
+ color: "var(--wp-primary-dark)",
1928
+ borderRadius: 3,
1929
+ textTransform: "uppercase"
1930
+ },
1931
+ badgeUsed: {
1932
+ fontSize: 9,
1933
+ fontWeight: 600,
1934
+ padding: "1px 6px",
1935
+ background: "var(--wp-success-bg)",
1936
+ color: "var(--wp-success)",
1937
+ borderRadius: 3,
1938
+ textTransform: "uppercase"
1939
+ },
1940
+ depRow: { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 4 },
1941
+ depLabel: { fontSize: 10, fontWeight: 600, color: "var(--wp-text-muted)", textTransform: "uppercase" },
1942
+ depLabelUsed: { fontSize: 10, fontWeight: 600, color: "var(--wp-success)", textTransform: "uppercase" },
1943
+ depBadge: {
1944
+ fontSize: 10,
1945
+ fontWeight: 600,
1946
+ padding: "1px 6px",
1947
+ background: "var(--wp-primary-bg)",
1948
+ color: "var(--wp-primary-dark)",
1949
+ borderRadius: 4
1950
+ },
1951
+ depBadgeUsed: {
1952
+ fontSize: 10,
1953
+ fontWeight: 600,
1954
+ padding: "1px 6px",
1955
+ background: "var(--wp-success-bg)",
1956
+ color: "var(--wp-success)",
1957
+ borderRadius: 4
1958
+ }
1959
+ };
1960
+ function PreviewPanel({ store, schema }) {
1961
+ const [done, setDone] = react.useState(false);
1962
+ const { tree, currentStep, progress } = react$1.useWaypoint(store);
1963
+ const stepId = currentStep?.definition.id ?? "";
1964
+ const { fields, stepData, setFieldValue } = react$1.useWaypointStep(store, stepId);
1965
+ const [errors, setErrors] = react.useState({});
1966
+ function handleNext() {
1967
+ const newErrors = {};
1968
+ for (const field of fields) {
1969
+ const isRequired = field.definition.validation?.some((r) => r.type === "required");
1970
+ if (isRequired) {
1971
+ const val = stepData[field.definition.id];
1972
+ if (val === void 0 || val === null || val === "" || val === false) {
1973
+ const rule = field.definition.validation?.find((r) => r.type === "required");
1974
+ newErrors[field.definition.id] = rule?.message ?? "Ce champ est requis";
1975
+ }
1976
+ }
1977
+ }
1978
+ if (Object.keys(newErrors).length > 0) {
1979
+ setErrors(newErrors);
1980
+ return;
1981
+ }
1982
+ setErrors({});
1983
+ const oldIds = tree.steps.map((s) => s.definition.id).join(",");
1984
+ store.getState().setStepData(stepId, stepData);
1985
+ const newData = store.getState().data;
1986
+ const newTree = core.resolveTree(schema, newData, {});
1987
+ const newIds = newTree.steps.map((s) => s.definition.id).join(",");
1988
+ if (oldIds !== newIds) {
1989
+ store.getState().truncateHistoryAt(stepId);
1990
+ }
1991
+ const next = core.getNextStep(newTree.steps, stepId);
1992
+ if (next) {
1993
+ store.getState().setCurrentStep(next.definition.id);
1994
+ } else {
1995
+ setDone(true);
1996
+ }
1997
+ }
1998
+ function handlePrev() {
1999
+ const prev = core.getPreviousStep(tree.steps, stepId);
2000
+ if (prev) store.getState().setCurrentStep(prev.definition.id);
2001
+ }
2002
+ function handleRestart() {
2003
+ store.getState().init(schema);
2004
+ setDone(false);
2005
+ setErrors({});
2006
+ }
2007
+ const currentIdx = tree.steps.findIndex(
2008
+ (s) => s.definition.id === currentStep?.definition.id
2009
+ );
2010
+ if (done) {
2011
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.panel, children: [
2012
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.leftCol, children: /* @__PURE__ */ jsxRuntime.jsx(
2013
+ StepList,
2014
+ {
2015
+ tree,
2016
+ currentIdx,
2017
+ onSelect: (id) => store.getState().setCurrentStep(id)
2018
+ }
2019
+ ) }),
2020
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.divider }),
2021
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.doneScreen, children: [
2022
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.doneIcon, children: "\u2713" }),
2023
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.doneTitle, children: "Parcours termin\xE9 !" }),
2024
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.doneText, children: "Toutes les \xE9tapes ont \xE9t\xE9 compl\xE9t\xE9es avec succ\xE8s." }),
2025
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles6.primaryBtn, onClick: handleRestart, children: "Recommencer" })
2026
+ ] }) })
2027
+ ] });
2028
+ }
2029
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.panel, children: [
2030
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.leftCol, children: /* @__PURE__ */ jsxRuntime.jsx(
2031
+ StepList,
2032
+ {
2033
+ tree,
2034
+ currentIdx,
2035
+ onSelect: (id) => store.getState().setCurrentStep(id)
2036
+ }
2037
+ ) }),
2038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.divider }),
2039
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.rightCol, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.stepRenderer, children: [
2040
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.progressTrack, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: { ...styles6.progressFill, width: `${progress}%` } }) }),
2041
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { style: styles6.stepTitle, children: currentStep?.definition.title ?? "" }),
2042
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.fieldsContainer, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsx(
2043
+ FieldRenderer,
2044
+ {
2045
+ field,
2046
+ value: stepData[field.definition.id],
2047
+ error: errors[field.definition.id],
2048
+ onChange: (val) => {
2049
+ setFieldValue(field.definition.id, val);
2050
+ if (errors[field.definition.id]) {
2051
+ setErrors((prev) => {
2052
+ const next = { ...prev };
2053
+ delete next[field.definition.id];
2054
+ return next;
2055
+ });
2056
+ }
2057
+ }
2058
+ },
2059
+ field.definition.id
2060
+ )) }),
2061
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.navRow, children: [
2062
+ currentIdx > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles6.secondaryBtn, onClick: handlePrev, children: "\u2190 Pr\xE9c\xE9dent" }),
2063
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles6.primaryBtn, marginLeft: "auto" }, onClick: handleNext, children: core.getNextStep(tree.steps, stepId) ? "Continuer \u2192" : "Terminer \u2713" })
2064
+ ] })
2065
+ ] }) })
2066
+ ] });
2067
+ }
2068
+ function StepList({ tree, currentIdx, onSelect }) {
2069
+ const allSteps = [
2070
+ ...tree.steps.map((s) => ({ ...s, hidden: false })),
2071
+ ...tree.hiddenSteps.map((s) => ({ ...s, hidden: true }))
2072
+ ];
2073
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.stepList, children: [
2074
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.stepListTitle, children: "\xC9tapes" }),
2075
+ allSteps.map((step) => {
2076
+ const isVisible = !step.hidden;
2077
+ const visIdx = tree.steps.findIndex((s) => s.definition.id === step.definition.id);
2078
+ let status = "hidden";
2079
+ if (isVisible) {
2080
+ if (visIdx < currentIdx) status = "done";
2081
+ else if (visIdx === currentIdx) status = "current";
2082
+ else status = "upcoming";
2083
+ }
2084
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2085
+ "div",
2086
+ {
2087
+ style: {
2088
+ ...styles6.stepItem,
2089
+ ...status === "current" ? styles6.stepItemCurrent : {},
2090
+ ...status === "hidden" ? styles6.stepItemHidden : {},
2091
+ cursor: status === "done" ? "pointer" : "default"
2092
+ },
2093
+ onClick: () => {
2094
+ if (status === "done") onSelect(step.definition.id);
2095
+ },
2096
+ children: [
2097
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles6.stepStatus, children: [
2098
+ status === "done" && "\u2713",
2099
+ status === "current" && "\u2192",
2100
+ status === "upcoming" && "\u25CB",
2101
+ status === "hidden" && "\u2013"
2102
+ ] }),
2103
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.stepName, children: step.definition.title }),
2104
+ status === "hidden" && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.hiddenBadge, children: "hidden" })
2105
+ ]
2106
+ },
2107
+ step.definition.id
2108
+ );
2109
+ })
2110
+ ] });
2111
+ }
2112
+ function FieldRenderer({ field, value, error, onChange }) {
2113
+ const { definition } = field;
2114
+ const inputStyle2 = { ...styles6.input, ...error ? styles6.inputError : {} };
2115
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.fieldGroup, children: [
2116
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { style: styles6.label, children: [
2117
+ definition.label,
2118
+ definition.validation?.some((r) => r.type === "required") && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.required, children: " *" })
2119
+ ] }),
2120
+ (definition.type === "text" || definition.type === "email" || definition.type === "tel" || definition.type === "password" || definition.type === "url" || definition.type === "number" || definition.type === "date") && /* @__PURE__ */ jsxRuntime.jsx(
2121
+ "input",
2122
+ {
2123
+ type: definition.type,
2124
+ style: inputStyle2,
2125
+ value: value ?? "",
2126
+ placeholder: definition.placeholder,
2127
+ onChange: (e) => onChange(e.target.value)
2128
+ }
2129
+ ),
2130
+ definition.type === "textarea" && /* @__PURE__ */ jsxRuntime.jsx(
2131
+ "textarea",
2132
+ {
2133
+ style: { ...inputStyle2, minHeight: 80, resize: "vertical" },
2134
+ value: value ?? "",
2135
+ placeholder: definition.placeholder,
2136
+ onChange: (e) => onChange(e.target.value)
2137
+ }
2138
+ ),
2139
+ definition.type === "select" && /* @__PURE__ */ jsxRuntime.jsxs(
2140
+ "select",
2141
+ {
2142
+ style: inputStyle2,
2143
+ value: value ?? "",
2144
+ onChange: (e) => onChange(e.target.value),
2145
+ children: [
2146
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "\u2014 Choisir \u2014" }),
2147
+ definition.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2148
+ ]
2149
+ }
2150
+ ),
2151
+ definition.type === "multiselect" && /* @__PURE__ */ jsxRuntime.jsx(
2152
+ "select",
2153
+ {
2154
+ style: { ...inputStyle2, minHeight: 80 },
2155
+ multiple: true,
2156
+ value: value ?? [],
2157
+ onChange: (e) => {
2158
+ const selected = Array.from(e.target.selectedOptions).map((o) => o.value);
2159
+ onChange(selected);
2160
+ },
2161
+ children: definition.options?.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: String(opt.value), children: opt.label }, String(opt.value)))
2162
+ }
2163
+ ),
2164
+ 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: [
2165
+ /* @__PURE__ */ jsxRuntime.jsx(
2166
+ "input",
2167
+ {
2168
+ type: "radio",
2169
+ name: definition.id,
2170
+ value: String(opt.value),
2171
+ checked: value === String(opt.value),
2172
+ onChange: () => onChange(String(opt.value))
2173
+ }
2174
+ ),
2175
+ opt.label
2176
+ ] }, String(opt.value))) }),
2177
+ definition.type === "checkbox" && /* @__PURE__ */ jsxRuntime.jsxs("label", { style: { display: "flex", alignItems: "center", gap: 8, cursor: "pointer", fontSize: 13 }, children: [
2178
+ /* @__PURE__ */ jsxRuntime.jsx(
2179
+ "input",
2180
+ {
2181
+ type: "checkbox",
2182
+ checked: Boolean(value),
2183
+ onChange: (e) => onChange(e.target.checked)
2184
+ }
2185
+ ),
2186
+ definition.placeholder ?? definition.label
2187
+ ] }),
2188
+ error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.errorMsg, children: error })
2189
+ ] });
2190
+ }
2191
+ var styles6 = {
2192
+ panel: {
2193
+ display: "flex",
2194
+ flex: 1,
2195
+ overflow: "hidden"
2196
+ },
2197
+ leftCol: {
2198
+ width: 220,
2199
+ flexShrink: 0,
2200
+ overflowY: "auto",
2201
+ borderRight: "1px solid var(--wp-border)",
2202
+ background: "var(--wp-panel-bg)"
2203
+ },
2204
+ divider: {
2205
+ width: 1,
2206
+ background: "var(--wp-border)",
2207
+ flexShrink: 0
2208
+ },
2209
+ rightCol: {
2210
+ flex: 1,
2211
+ overflow: "auto",
2212
+ display: "flex",
2213
+ flexDirection: "column",
2214
+ alignItems: "center",
2215
+ padding: "32px 24px"
2216
+ },
2217
+ stepRenderer: {
2218
+ width: "100%",
2219
+ maxWidth: 520,
2220
+ display: "flex",
2221
+ flexDirection: "column",
2222
+ gap: 20
2223
+ },
2224
+ progressTrack: {
2225
+ height: 4,
2226
+ background: "var(--wp-border)",
2227
+ borderRadius: 2,
2228
+ overflow: "hidden"
2229
+ },
2230
+ progressFill: {
2231
+ height: "100%",
2232
+ background: "var(--wp-primary)",
2233
+ borderRadius: 2,
2234
+ transition: "width 0.3s ease"
2235
+ },
2236
+ stepTitle: {
2237
+ fontSize: 20,
2238
+ fontWeight: 700,
2239
+ color: "var(--wp-text)",
2240
+ margin: 0
2241
+ },
2242
+ fieldsContainer: {
2243
+ display: "flex",
2244
+ flexDirection: "column",
2245
+ gap: 16
2246
+ },
2247
+ fieldGroup: {
2248
+ display: "flex",
2249
+ flexDirection: "column",
2250
+ gap: 4
2251
+ },
2252
+ label: {
2253
+ fontSize: 13,
2254
+ fontWeight: 600,
2255
+ color: "var(--wp-text)"
2256
+ },
2257
+ required: {
2258
+ color: "var(--wp-danger)"
2259
+ },
2260
+ input: {
2261
+ fontSize: 13,
2262
+ padding: "8px 10px",
2263
+ border: "1px solid var(--wp-border)",
2264
+ borderRadius: "var(--wp-radius)",
2265
+ background: "var(--wp-canvas)",
2266
+ color: "var(--wp-text)",
2267
+ outline: "none",
2268
+ width: "100%",
2269
+ boxSizing: "border-box"
2270
+ },
2271
+ inputError: {
2272
+ borderColor: "var(--wp-danger)"
2273
+ },
2274
+ errorMsg: {
2275
+ fontSize: 11,
2276
+ color: "var(--wp-danger)",
2277
+ marginTop: 2
2278
+ },
2279
+ navRow: {
2280
+ display: "flex",
2281
+ alignItems: "center",
2282
+ gap: 8,
2283
+ paddingTop: 8
2284
+ },
2285
+ primaryBtn: {
2286
+ fontSize: 13,
2287
+ fontWeight: 600,
2288
+ padding: "9px 20px",
2289
+ background: "var(--wp-primary)",
2290
+ color: "var(--wp-canvas)",
2291
+ border: "none",
2292
+ borderRadius: "var(--wp-radius)",
2293
+ cursor: "pointer"
2294
+ },
2295
+ secondaryBtn: {
2296
+ fontSize: 13,
2297
+ fontWeight: 500,
2298
+ padding: "9px 16px",
2299
+ background: "transparent",
2300
+ color: "var(--wp-text-muted)",
2301
+ border: "1px solid var(--wp-border)",
2302
+ borderRadius: "var(--wp-radius)",
2303
+ cursor: "pointer"
2304
+ },
2305
+ // Step list
2306
+ stepList: {
2307
+ padding: "16px 12px",
2308
+ display: "flex",
2309
+ flexDirection: "column",
2310
+ gap: 4
2311
+ },
2312
+ stepListTitle: {
2313
+ fontSize: 11,
2314
+ fontWeight: 700,
2315
+ color: "var(--wp-text-muted)",
2316
+ textTransform: "uppercase",
2317
+ letterSpacing: "0.5px",
2318
+ marginBottom: 8
2319
+ },
2320
+ stepItem: {
2321
+ display: "flex",
2322
+ alignItems: "center",
2323
+ gap: 8,
2324
+ padding: "6px 8px",
2325
+ borderRadius: 6,
2326
+ fontSize: 12,
2327
+ color: "var(--wp-text-muted)"
2328
+ },
2329
+ stepItemCurrent: {
2330
+ background: "var(--wp-primary-subtle, rgba(99,102,241,0.08))",
2331
+ color: "var(--wp-primary)",
2332
+ fontWeight: 600
2333
+ },
2334
+ stepItemHidden: {
2335
+ opacity: 0.45
2336
+ },
2337
+ stepStatus: {
2338
+ fontSize: 11,
2339
+ width: 14,
2340
+ flexShrink: 0,
2341
+ textAlign: "center"
2342
+ },
2343
+ stepName: {
2344
+ flex: 1,
2345
+ overflow: "hidden",
2346
+ textOverflow: "ellipsis",
2347
+ whiteSpace: "nowrap"
2348
+ },
2349
+ hiddenBadge: {
2350
+ fontSize: 9,
2351
+ fontWeight: 700,
2352
+ padding: "1px 5px",
2353
+ borderRadius: 4,
2354
+ background: "var(--wp-border)",
2355
+ color: "var(--wp-text-muted)",
2356
+ textTransform: "uppercase",
2357
+ letterSpacing: "0.3px",
2358
+ flexShrink: 0
2359
+ },
2360
+ // Done screen
2361
+ doneScreen: {
2362
+ display: "flex",
2363
+ flexDirection: "column",
2364
+ alignItems: "center",
2365
+ justifyContent: "center",
2366
+ flex: 1,
2367
+ gap: 12,
2368
+ paddingTop: 60,
2369
+ textAlign: "center"
2370
+ },
2371
+ doneIcon: {
2372
+ width: 64,
2373
+ height: 64,
2374
+ borderRadius: "50%",
2375
+ background: "var(--wp-success-subtle, rgba(34,197,94,0.1))",
2376
+ color: "var(--wp-success, #22c55e)",
2377
+ display: "flex",
2378
+ alignItems: "center",
2379
+ justifyContent: "center",
2380
+ fontSize: 28,
2381
+ fontWeight: 700
2382
+ },
2383
+ doneTitle: {
2384
+ fontSize: 22,
2385
+ fontWeight: 700,
2386
+ color: "var(--wp-text)"
2387
+ },
2388
+ doneText: {
2389
+ fontSize: 14,
2390
+ color: "var(--wp-text-muted)",
2391
+ margin: 0
2392
+ }
2393
+ };
2394
+ function StepEditor() {
2395
+ const { schema, selectedStepId, updateStep, setStepCondition } = useBuilderStore();
2396
+ const [conditionModalOpen, setConditionModalOpen] = react.useState(false);
2397
+ const step = schema.steps.find((s) => s.id === selectedStepId);
2398
+ if (!step) {
2399
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.empty, children: "Select a step to configure its properties." });
2400
+ }
2401
+ const hasCondition = !!step.visibleWhen;
2402
+ const ruleCount = step.visibleWhen?.rules.length ?? 0;
2403
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.container, children: [
2404
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.header, children: [
2405
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.headerTitle, children: "Step Config" }),
2406
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.stepId, children: [
2407
+ "id: ",
2408
+ step.id
2409
+ ] })
2410
+ ] }),
2411
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.body, children: [
2412
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.group, children: [
2413
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles7.label, children: "Title" }),
2414
+ /* @__PURE__ */ jsxRuntime.jsx(
2415
+ "input",
2416
+ {
2417
+ style: styles7.input,
2418
+ value: step.title,
2419
+ placeholder: "Step title",
2420
+ onChange: (e) => updateStep(step.id, { title: e.target.value })
2421
+ }
2422
+ )
2423
+ ] }),
2424
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.group, children: [
2425
+ /* @__PURE__ */ jsxRuntime.jsx("label", { style: styles7.label, children: "URL" }),
2426
+ /* @__PURE__ */ jsxRuntime.jsx(
2427
+ "input",
2428
+ {
2429
+ style: styles7.input,
2430
+ value: step.url,
2431
+ placeholder: "/onboarding/step-name",
2432
+ onChange: (e) => updateStep(step.id, { url: e.target.value })
2433
+ }
2434
+ ),
2435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.hint, children: [
2436
+ "Supports ",
2437
+ "{{PARAM}}",
2438
+ " placeholders"
2439
+ ] })
2440
+ ] }),
2441
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.checkRow, children: [
2442
+ /* @__PURE__ */ jsxRuntime.jsx(
2443
+ "input",
2444
+ {
2445
+ type: "checkbox",
2446
+ id: `resume-${step.id}`,
2447
+ checked: !!step.enableResumeFromHere,
2448
+ onChange: (e) => updateStep(step.id, { enableResumeFromHere: e.target.checked || void 0 })
2449
+ }
2450
+ ),
2451
+ /* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: `resume-${step.id}`, style: styles7.checkLabel, children: "Resume from this step" })
2452
+ ] }),
2453
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.divider }),
2454
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionRow, children: [
2455
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionInfo, children: [
2456
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.label, children: "Visibility condition" }),
2457
+ hasCondition ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionSummary, children: [
2458
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles7.conditionBadge, children: [
2459
+ ruleCount,
2460
+ " rule",
2461
+ ruleCount !== 1 ? "s" : "",
2462
+ " \xB7 ",
2463
+ step.visibleWhen.combinator.toUpperCase()
2464
+ ] }),
2465
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles7.conditionDesc, children: "Step is conditional" })
2466
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.conditionNone, children: "Always visible" })
2467
+ ] }),
2468
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles7.conditionActions, children: [
2469
+ /* @__PURE__ */ jsxRuntime.jsx(
2470
+ "button",
2471
+ {
2472
+ style: styles7.editConditionBtn,
2473
+ onClick: () => setConditionModalOpen(true),
2474
+ children: hasCondition ? "Edit" : "Add condition"
2475
+ }
2476
+ ),
2477
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx(
2478
+ "button",
2479
+ {
2480
+ style: styles7.clearConditionBtn,
2481
+ onClick: () => setStepCondition(step.id, void 0),
2482
+ children: "Clear"
2483
+ }
2484
+ )
2485
+ ] })
2486
+ ] })
2487
+ ] }),
2488
+ conditionModalOpen && /* @__PURE__ */ jsxRuntime.jsxs(
2489
+ Modal,
2490
+ {
2491
+ title: `Condition \u2014 "${step.title}"`,
2492
+ onClose: () => setConditionModalOpen(false),
2493
+ width: 620,
2494
+ children: [
2495
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: styles7.modalHint, children: "Define when this step is visible. Leave empty to always show it." }),
2496
+ /* @__PURE__ */ jsxRuntime.jsx(
2497
+ ConditionBuilder,
2498
+ {
2499
+ value: step.visibleWhen,
2500
+ onChange: (c) => setStepCondition(step.id, c)
2501
+ }
2502
+ ),
2503
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles7.modalFooter, children: /* @__PURE__ */ jsxRuntime.jsx(
2504
+ "button",
2505
+ {
2506
+ style: styles7.modalCloseBtn,
2507
+ onClick: () => setConditionModalOpen(false),
2508
+ children: "Done"
2509
+ }
2510
+ ) })
2511
+ ]
2512
+ }
2513
+ )
2514
+ ] });
2515
+ }
2516
+ var styles7 = {
2517
+ container: { display: "flex", flexDirection: "column", height: "100%", overflow: "hidden" },
2518
+ empty: {
2519
+ display: "flex",
2520
+ alignItems: "center",
2521
+ justifyContent: "center",
2522
+ height: "100%",
2523
+ color: "var(--wp-text-subtle)",
2524
+ fontSize: 13,
2525
+ textAlign: "center",
2526
+ padding: 32
2527
+ },
2528
+ header: {
2529
+ padding: "12px 16px",
2530
+ borderBottom: "1px solid var(--wp-border)",
2531
+ display: "flex",
2532
+ justifyContent: "space-between",
2533
+ alignItems: "center"
2534
+ },
2535
+ headerTitle: { fontWeight: 700, fontSize: 13, color: "var(--wp-text)" },
2536
+ stepId: { fontSize: 10, color: "var(--wp-text-subtle)", fontFamily: "monospace" },
2537
+ body: { flex: 1, overflowY: "auto", padding: 16, display: "flex", flexDirection: "column", gap: 12 },
2538
+ group: { display: "flex", flexDirection: "column", gap: 4 },
2539
+ label: { fontSize: 11, fontWeight: 600, color: "var(--wp-text-muted)", textTransform: "uppercase", letterSpacing: "0.05em" },
2540
+ input: {
2541
+ fontSize: 13,
2542
+ padding: "6px 8px",
2543
+ border: "1px solid var(--wp-border-muted)",
2544
+ borderRadius: "var(--wp-radius)",
2545
+ outline: "none",
2546
+ background: "var(--wp-canvas)",
2547
+ color: "var(--wp-text)"
2548
+ },
2549
+ hint: { fontSize: 10, color: "var(--wp-text-subtle)" },
2550
+ checkRow: { display: "flex", alignItems: "center", gap: 8 },
2551
+ checkLabel: { fontSize: 13, color: "var(--wp-text-secondary)" },
2552
+ divider: { height: 1, background: "var(--wp-border)" },
2553
+ conditionRow: {
2554
+ display: "flex",
2555
+ alignItems: "flex-start",
2556
+ justifyContent: "space-between",
2557
+ gap: 8
2558
+ },
2559
+ conditionInfo: { display: "flex", flexDirection: "column", gap: 6, flex: 1 },
2560
+ conditionSummary: { display: "flex", alignItems: "center", gap: 8 },
2561
+ conditionBadge: {
2562
+ fontSize: 11,
2563
+ fontWeight: 700,
2564
+ background: "var(--wp-warning-bg)",
2565
+ color: "var(--wp-warning)",
2566
+ padding: "2px 8px",
2567
+ borderRadius: 4
2568
+ },
2569
+ conditionDesc: { fontSize: 11, color: "var(--wp-text-subtle)" },
2570
+ conditionNone: { fontSize: 12, color: "var(--wp-text-subtle)", fontStyle: "italic" },
2571
+ conditionActions: { display: "flex", gap: 6, flexShrink: 0, alignItems: "flex-start", marginTop: 16 },
2572
+ editConditionBtn: {
2573
+ fontSize: 11,
2574
+ padding: "4px 10px",
2575
+ background: "var(--wp-primary)",
2576
+ color: "var(--wp-canvas)",
2577
+ border: "none",
2578
+ borderRadius: "var(--wp-radius)",
2579
+ cursor: "pointer",
2580
+ fontWeight: 500
2581
+ },
2582
+ clearConditionBtn: {
2583
+ fontSize: 11,
2584
+ padding: "4px 10px",
2585
+ background: "var(--wp-danger-bg-strong)",
2586
+ color: "var(--wp-danger)",
2587
+ border: "none",
2588
+ borderRadius: "var(--wp-radius)",
2589
+ cursor: "pointer"
2590
+ },
2591
+ modalHint: { fontSize: 13, color: "var(--wp-text-muted)", marginBottom: 16, marginTop: 0 },
2592
+ modalFooter: { marginTop: 20, display: "flex", justifyContent: "flex-end" },
2593
+ modalCloseBtn: {
2594
+ fontSize: 13,
2595
+ padding: "7px 20px",
2596
+ background: "var(--wp-primary)",
2597
+ color: "var(--wp-canvas)",
2598
+ border: "none",
2599
+ borderRadius: "var(--wp-radius-lg)",
2600
+ cursor: "pointer",
2601
+ fontWeight: 600
2602
+ }
2603
+ };
2604
+ function StepList2() {
2605
+ const { schema, selectedStepId, addStep, removeStep, selectStep, reorderSteps } = useBuilderStore();
2606
+ const [moveError, setMoveError] = react.useState(null);
2607
+ const steps = schema.steps;
2608
+ const deps = computeStepDependencies(schema);
2609
+ const tryMove = (fromIndex, toIndex) => {
2610
+ const check = isMoveValid(steps, deps, fromIndex, toIndex);
2611
+ if (!check.valid) {
2612
+ setMoveError(check.reason ?? "Invalid move");
2613
+ setTimeout(() => setMoveError(null), 3e3);
2614
+ return;
2615
+ }
2616
+ setMoveError(null);
2617
+ reorderSteps(fromIndex, toIndex);
2618
+ };
2619
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.container, children: [
2620
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.header, children: [
2621
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles8.title, children: [
2622
+ "Steps (",
2623
+ steps.length,
2624
+ ")"
2625
+ ] }),
2626
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles8.addBtn, onClick: () => addStep(), children: "+ Add step" })
2627
+ ] }),
2628
+ moveError && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.errorBanner, children: [
2629
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.errorIcon, children: "\u26A0" }),
2630
+ moveError
2631
+ ] }),
2632
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.list, children: [
2633
+ steps.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.empty, children: 'No steps yet. Click "Add step" to start.' }),
2634
+ steps.map((step, index) => {
2635
+ const isSelected = step.id === selectedStepId;
2636
+ const hasCondition = !!step.visibleWhen;
2637
+ const depLabels = getStepDependencyLabels(step.id, deps, schema);
2638
+ const canMoveUp = index > 0 && isMoveValid(steps, deps, index, index - 1).valid;
2639
+ const canMoveDown = index < steps.length - 1 && isMoveValid(steps, deps, index, index + 1).valid;
2640
+ const dependents = steps.filter(
2641
+ (s) => (deps.get(s.id) ?? /* @__PURE__ */ new Set()).has(step.id)
2642
+ );
2643
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2644
+ "div",
2645
+ {
2646
+ style: {
2647
+ ...styles8.card,
2648
+ ...isSelected ? styles8.cardSelected : {}
2649
+ },
2650
+ onClick: () => selectStep(step.id),
2651
+ children: [
2652
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardMain, children: [
2653
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardLeft, children: [
2654
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.cardIndex, children: index + 1 }),
2655
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { minWidth: 0 }, children: [
2656
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles8.cardTitle, children: step.title }),
2657
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardMeta, children: [
2658
+ step.fields.length,
2659
+ " field",
2660
+ step.fields.length !== 1 ? "s" : "",
2661
+ hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.conditionBadge, children: "conditional" })
2662
+ ] })
2663
+ ] })
2664
+ ] }),
2665
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.cardActions, children: [
2666
+ index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
2667
+ "button",
2668
+ {
2669
+ style: {
2670
+ ...styles8.iconBtn,
2671
+ ...canMoveUp ? {} : styles8.iconBtnBlocked
2672
+ },
2673
+ title: canMoveUp ? "Move up" : `Can't move up \u2014 dependency order required`,
2674
+ onClick: (e) => {
2675
+ e.stopPropagation();
2676
+ tryMove(index, index - 1);
2677
+ },
2678
+ children: "\u2191"
2679
+ }
2680
+ ),
2681
+ index < steps.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
2682
+ "button",
2683
+ {
2684
+ style: {
2685
+ ...styles8.iconBtn,
2686
+ ...canMoveDown ? {} : styles8.iconBtnBlocked
2687
+ },
2688
+ title: canMoveDown ? "Move down" : `Can't move down \u2014 dependency order required`,
2689
+ onClick: (e) => {
2690
+ e.stopPropagation();
2691
+ tryMove(index, index + 1);
2692
+ },
2693
+ children: "\u2193"
2694
+ }
2695
+ ),
2696
+ /* @__PURE__ */ jsxRuntime.jsx(
2697
+ "button",
2698
+ {
2699
+ style: { ...styles8.iconBtn, ...styles8.deleteBtn },
2700
+ title: "Remove step",
2701
+ onClick: (e) => {
2702
+ e.stopPropagation();
2703
+ removeStep(step.id);
2704
+ },
2705
+ children: "\u2715"
2706
+ }
2707
+ )
2708
+ ] })
2709
+ ] }),
2710
+ depLabels.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.depRow, children: [
2711
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depLabel, children: "needs:" }),
2712
+ depLabels.map((label) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depBadge, children: label }, label))
2713
+ ] }),
2714
+ dependents.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles8.depRow, children: [
2715
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depLabelUsed, children: "used by:" }),
2716
+ dependents.map((s) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles8.depBadgeUsed, children: s.title }, s.id))
2717
+ ] })
2718
+ ]
2719
+ },
2720
+ step.id
2721
+ );
2722
+ })
2723
+ ] })
2724
+ ] });
2725
+ }
2726
+ var styles8 = {
2727
+ container: { display: "flex", flexDirection: "column", height: "100%" },
2728
+ header: {
2729
+ display: "flex",
2730
+ alignItems: "center",
2731
+ justifyContent: "space-between",
2732
+ padding: "12px 16px",
2733
+ borderBottom: "1px solid var(--wp-border)"
2734
+ },
2735
+ title: { fontWeight: 600, fontSize: 13, color: "var(--wp-text-secondary)" },
2736
+ addBtn: {
2737
+ fontSize: 12,
2738
+ padding: "4px 10px",
2739
+ background: "var(--wp-primary)",
2740
+ color: "var(--wp-canvas)",
2741
+ border: "none",
2742
+ borderRadius: "var(--wp-radius)",
2743
+ cursor: "pointer",
2744
+ fontWeight: 500
2745
+ },
2746
+ errorBanner: {
2747
+ margin: "8px 8px 0",
2748
+ padding: "8px 12px",
2749
+ background: "var(--wp-danger-bg)",
2750
+ border: "1px solid var(--wp-danger-border)",
2751
+ borderRadius: "var(--wp-radius-lg)",
2752
+ fontSize: 12,
2753
+ color: "var(--wp-danger-text)",
2754
+ display: "flex",
2755
+ alignItems: "center",
2756
+ gap: 6
2757
+ },
2758
+ errorIcon: { fontSize: 14 },
2759
+ list: { flex: 1, overflowY: "auto", padding: 8 },
2760
+ empty: { padding: 24, textAlign: "center", color: "var(--wp-text-subtle)", fontSize: 13 },
2761
+ card: {
2762
+ padding: "10px 12px",
2763
+ borderRadius: "var(--wp-radius-lg)",
2764
+ marginBottom: 4,
2765
+ border: "1px solid transparent",
2766
+ cursor: "pointer",
2767
+ background: "var(--wp-surface)",
2768
+ transition: "all 0.1s",
2769
+ display: "flex",
2770
+ flexDirection: "column",
2771
+ gap: 6
2772
+ },
2773
+ cardSelected: { background: "var(--wp-primary-muted)", border: "1px solid var(--wp-primary-border)" },
2774
+ cardMain: { display: "flex", alignItems: "center", justifyContent: "space-between" },
2775
+ cardLeft: { display: "flex", alignItems: "center", gap: 10, minWidth: 0, flex: 1 },
2776
+ cardIndex: {
2777
+ width: 24,
2778
+ height: 24,
2779
+ borderRadius: "50%",
2780
+ background: "var(--wp-border)",
2781
+ display: "flex",
2782
+ alignItems: "center",
2783
+ justifyContent: "center",
2784
+ fontSize: 11,
2785
+ fontWeight: 700,
2786
+ color: "var(--wp-text-muted)",
2787
+ flexShrink: 0
2788
+ },
2789
+ cardTitle: { fontSize: 13, fontWeight: 600, color: "var(--wp-text)" },
2790
+ cardMeta: {
2791
+ fontSize: 11,
2792
+ color: "var(--wp-text-subtle)",
2793
+ display: "flex",
2794
+ alignItems: "center",
2795
+ gap: 6,
2796
+ marginTop: 2
2797
+ },
2798
+ conditionBadge: {
2799
+ fontSize: 10,
2800
+ background: "var(--wp-warning-bg)",
2801
+ color: "var(--wp-warning)",
2802
+ padding: "1px 6px",
2803
+ borderRadius: 4,
2804
+ fontWeight: 600
2805
+ },
2806
+ cardActions: { display: "flex", gap: 4, flexShrink: 0 },
2807
+ iconBtn: {
2808
+ width: 24,
2809
+ height: 24,
2810
+ border: "none",
2811
+ background: "transparent",
2812
+ cursor: "pointer",
2813
+ borderRadius: 4,
2814
+ fontSize: 12,
2815
+ color: "var(--wp-text-subtle)",
2816
+ display: "flex",
2817
+ alignItems: "center",
2818
+ justifyContent: "center"
2819
+ },
2820
+ iconBtnBlocked: {
2821
+ color: "var(--wp-border-muted)",
2822
+ cursor: "not-allowed",
2823
+ opacity: 0.4
2824
+ },
2825
+ deleteBtn: { color: "var(--wp-danger)" },
2826
+ depRow: { display: "flex", alignItems: "center", flexWrap: "wrap", gap: 4 },
2827
+ depLabel: { fontSize: 10, fontWeight: 600, color: "var(--wp-text-muted)", textTransform: "uppercase" },
2828
+ depLabelUsed: { fontSize: 10, fontWeight: 600, color: "var(--wp-success)", textTransform: "uppercase" },
2829
+ depBadge: {
2830
+ fontSize: 10,
2831
+ fontWeight: 600,
2832
+ padding: "1px 6px",
2833
+ background: "var(--wp-primary-bg)",
2834
+ color: "var(--wp-primary-dark)",
2835
+ borderRadius: 4
2836
+ },
2837
+ depBadgeUsed: {
2838
+ fontSize: 10,
2839
+ fontWeight: 600,
2840
+ padding: "1px 6px",
2841
+ background: "var(--wp-success-bg)",
2842
+ color: "var(--wp-success)",
2843
+ borderRadius: 4
2844
+ }
2845
+ };
2846
+ function Toolbar({ onSave, previewMode, onTest }) {
2847
+ const { schema, isDirty, resetSchema } = useBuilderStore();
2848
+ const handleExport = () => {
2849
+ const json = JSON.stringify(schema, null, 2);
2850
+ const blob = new Blob([json], { type: "application/json" });
2851
+ const url = URL.createObjectURL(blob);
2852
+ const a = document.createElement("a");
2853
+ a.href = url;
2854
+ a.download = `${schema.id}.waypoint.json`;
2855
+ a.click();
2856
+ URL.revokeObjectURL(url);
2857
+ };
2858
+ const handleImport = () => {
2859
+ const input = document.createElement("input");
2860
+ input.type = "file";
2861
+ input.accept = ".json";
2862
+ input.onchange = (e) => {
2863
+ const file = e.target.files?.[0];
2864
+ if (!file) return;
2865
+ const reader = new FileReader();
2866
+ reader.onload = (ev) => {
2867
+ try {
2868
+ const parsed = JSON.parse(ev.target?.result);
2869
+ const result = core.validateSchema(parsed);
2870
+ if (!result.valid) {
2871
+ alert(`Invalid schema:
2872
+
2873
+ ${result.errors.map((e2) => `\u2022 ${e2}`).join("\n")}`);
2874
+ return;
2875
+ }
2876
+ useBuilderStore.getState().loadSchema(parsed);
2877
+ } catch {
2878
+ alert("Invalid JSON file \u2014 could not parse");
2879
+ }
2880
+ };
2881
+ reader.readAsText(file);
2882
+ };
2883
+ input.click();
2884
+ };
2885
+ if (previewMode) {
2886
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.toolbar, children: [
2887
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.left, children: [
2888
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.logo, children: "\u25C8 waypoint" }),
2889
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.separator, children: "/" }),
2890
+ /* @__PURE__ */ jsxRuntime.jsx(
2891
+ "button",
2892
+ {
2893
+ style: { ...styles9.btn, ...styles9.editBtn },
2894
+ onClick: onTest,
2895
+ children: "\u2190 \xC9diter"
2896
+ }
2897
+ )
2898
+ ] }),
2899
+ /* @__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" }) })
2900
+ ] });
2901
+ }
2902
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.toolbar, children: [
2903
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.left, children: [
2904
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.logo, children: "\u25C8 waypoint" }),
2905
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.separator, children: "/" }),
2906
+ /* @__PURE__ */ jsxRuntime.jsx(
2907
+ "input",
2908
+ {
2909
+ style: styles9.journeyName,
2910
+ value: schema.name,
2911
+ placeholder: "Journey name",
2912
+ onChange: (e) => useBuilderStore.setState((s) => ({
2913
+ schema: { ...s.schema, name: e.target.value },
2914
+ isDirty: true
2915
+ }))
2916
+ }
2917
+ ),
2918
+ isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles9.dirtyDot, title: "Unsaved changes" })
2919
+ ] }),
2920
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles9.right, children: [
2921
+ onTest && /* @__PURE__ */ jsxRuntime.jsx("button", { style: { ...styles9.btn, ...styles9.testBtn }, onClick: onTest, children: "\u25B6 Tester" }),
2922
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles9.btn, onClick: handleImport, children: "Import" }),
2923
+ /* @__PURE__ */ jsxRuntime.jsx("button", { style: styles9.btn, onClick: handleExport, children: "Export JSON" }),
2924
+ onSave && /* @__PURE__ */ jsxRuntime.jsx(
2925
+ "button",
2926
+ {
2927
+ style: { ...styles9.btn, ...styles9.saveBtn },
2928
+ onClick: () => onSave(schema),
2929
+ children: "Save"
2930
+ }
2931
+ ),
2932
+ /* @__PURE__ */ jsxRuntime.jsx(
2933
+ "button",
2934
+ {
2935
+ style: { ...styles9.btn, color: "var(--wp-danger)" },
2936
+ onClick: () => {
2937
+ if (confirm("Reset the journey? All changes will be lost.")) resetSchema();
2938
+ },
2939
+ children: "Reset"
2940
+ }
2941
+ )
2942
+ ] })
2943
+ ] });
2944
+ }
2945
+ var styles9 = {
2946
+ toolbar: {
2947
+ display: "flex",
2948
+ alignItems: "center",
2949
+ justifyContent: "space-between",
2950
+ padding: "0 16px",
2951
+ height: 48,
2952
+ background: "var(--wp-toolbar-bg)",
2953
+ borderBottom: "1px solid var(--wp-toolbar-border)",
2954
+ flexShrink: 0
2955
+ },
2956
+ left: { display: "flex", alignItems: "center", gap: 8 },
2957
+ logo: { fontSize: 14, fontWeight: 800, color: "var(--wp-toolbar-logo)", letterSpacing: "-0.5px" },
2958
+ separator: { color: "var(--wp-toolbar-text-subtle)", fontSize: 16 },
2959
+ journeyName: {
2960
+ fontSize: 13,
2961
+ fontWeight: 600,
2962
+ color: "var(--wp-toolbar-text)",
2963
+ background: "transparent",
2964
+ border: "none",
2965
+ outline: "none",
2966
+ borderBottom: "1px solid transparent"
2967
+ },
2968
+ dirtyDot: {
2969
+ width: 6,
2970
+ height: 6,
2971
+ borderRadius: "50%",
2972
+ background: "var(--wp-warning-strong)",
2973
+ flexShrink: 0
2974
+ },
2975
+ right: { display: "flex", alignItems: "center", gap: 8 },
2976
+ btn: {
2977
+ fontSize: 12,
2978
+ padding: "5px 12px",
2979
+ border: "1px solid var(--wp-toolbar-border)",
2980
+ background: "transparent",
2981
+ color: "var(--wp-toolbar-text-muted)",
2982
+ borderRadius: "var(--wp-radius)",
2983
+ cursor: "pointer",
2984
+ fontWeight: 500
2985
+ },
2986
+ saveBtn: { background: "var(--wp-primary)", color: "var(--wp-canvas)", border: "1px solid var(--wp-primary)" },
2987
+ testBtn: { background: "var(--wp-success, #22c55e)", color: "#fff", border: "1px solid var(--wp-success, #22c55e)", fontWeight: 600 },
2988
+ editBtn: { background: "transparent", color: "var(--wp-toolbar-text)", border: "none", fontWeight: 600, cursor: "pointer", fontSize: 13, padding: "5px 0" }
2989
+ };
2990
+ function WaypointBuilder({
2991
+ defaultValue,
2992
+ onChange,
2993
+ onSave,
2994
+ theme,
2995
+ className,
2996
+ style
2997
+ }) {
2998
+ const { loadSchema, schema } = useBuilderStore();
2999
+ const [previewMode, setPreviewMode] = react.useState(false);
3000
+ const previewStoreRef = react.useRef(null);
3001
+ if (previewStoreRef.current === null) {
3002
+ previewStoreRef.current = core.createRuntimeStore();
3003
+ }
3004
+ react.useEffect(() => {
3005
+ if (defaultValue) loadSchema(defaultValue);
3006
+ }, []);
3007
+ react.useEffect(() => {
3008
+ onChange?.(schema);
3009
+ }, [schema, onChange]);
3010
+ function handleTest() {
3011
+ previewStoreRef.current.getState().init(schema);
3012
+ setPreviewMode(true);
3013
+ }
3014
+ const themeVars = buildThemeVars(theme);
3015
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...rootStyle, ...themeVars, ...style }, children: [
3016
+ /* @__PURE__ */ jsxRuntime.jsx(
3017
+ Toolbar,
3018
+ {
3019
+ onSave: !previewMode && onSave ? () => onSave(schema) : void 0,
3020
+ previewMode,
3021
+ onTest: previewMode ? () => setPreviewMode(false) : handleTest
3022
+ }
3023
+ ),
3024
+ previewMode ? /* @__PURE__ */ jsxRuntime.jsx(
3025
+ PreviewPanel,
3026
+ {
3027
+ store: previewStoreRef.current,
3028
+ schema,
3029
+ onEdit: () => setPreviewMode(false)
3030
+ }
3031
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { style: layoutStyle, children: [
3032
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: colStyle, children: [
3033
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "hidden", display: "flex", flexDirection: "column" }, children: /* @__PURE__ */ jsxRuntime.jsx(StepList2, {}) }),
3034
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { borderTop: "1px solid var(--wp-border)", flexShrink: 0, overflow: "auto", maxHeight: 280 }, children: /* @__PURE__ */ jsxRuntime.jsx(ExternalVariablePanel, {}) })
3035
+ ] }),
3036
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
3037
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: colStyle, children: /* @__PURE__ */ jsxRuntime.jsx(FieldList, {}) }),
3038
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: dividerStyle }),
3039
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { ...colStyle, flex: 1.2, display: "flex", flexDirection: "column" }, children: [
3040
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, borderBottom: "1px solid var(--wp-border)", overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(StepEditor, {}) }),
3041
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "hidden" }, children: /* @__PURE__ */ jsxRuntime.jsx(FieldEditor, {}) })
3042
+ ] })
3043
+ ] })
3044
+ ] });
3045
+ }
3046
+ var rootStyle = {
3047
+ display: "flex",
3048
+ flexDirection: "column",
3049
+ height: "100%",
3050
+ background: "var(--wp-canvas)",
3051
+ borderRadius: 12,
3052
+ border: "1px solid var(--wp-border)",
3053
+ overflow: "hidden",
3054
+ fontFamily: "var(--wp-font)"
3055
+ };
3056
+ var layoutStyle = {
3057
+ display: "flex",
3058
+ flex: 1,
3059
+ overflow: "hidden"
3060
+ };
3061
+ var colStyle = {
3062
+ flex: 1,
3063
+ display: "flex",
3064
+ flexDirection: "column",
3065
+ overflow: "hidden",
3066
+ minWidth: 0
3067
+ };
3068
+ var dividerStyle = {
3069
+ width: 1,
3070
+ background: "var(--wp-border)",
3071
+ flexShrink: 0
3072
+ };
3073
+
3074
+ exports.DARK_THEME = DARK_THEME;
3075
+ exports.DEFAULT_THEME = DEFAULT_THEME;
3076
+ exports.WaypointBuilder = WaypointBuilder;
3077
+ exports.buildThemeVars = buildThemeVars;
3078
+ exports.useBuilderStore = useBuilderStore;
3079
+ //# sourceMappingURL=index.cjs.map
3080
+ //# sourceMappingURL=index.cjs.map