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