@squaredr/fieldcraft-pro 1.7.0 → 1.9.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/LICENSE.txt +51 -51
- package/README.md +139 -139
- package/dist/{chunk-VEP3DOCQ.mjs → chunk-5QXKDYWY.mjs} +103 -19
- package/dist/{chunk-GZIV2XAD.mjs → chunk-7GPX3YIB.mjs} +146 -183
- package/dist/{chunk-J5V6OVZO.mjs → chunk-DWRLPGX5.mjs} +690 -211
- package/dist/{chunk-4TN6YJDF.mjs → chunk-KTIU7VCP.mjs} +971 -214
- package/dist/default-schema-BGxf9Jrg.d.ts +174 -0
- package/dist/default-schema-Bwq8FATF.d.mts +174 -0
- package/dist/form-builder/index.d.mts +14 -170
- package/dist/form-builder/index.d.ts +14 -170
- package/dist/form-builder/index.js +827 -326
- package/dist/form-builder/index.mjs +1 -1
- package/dist/index.d.mts +111 -10
- package/dist/index.d.ts +111 -10
- package/dist/index.js +3525 -971
- package/dist/index.mjs +1424 -124
- package/dist/response-viewer/index.d.mts +1 -1
- package/dist/response-viewer/index.d.ts +1 -1
- package/dist/response-viewer/index.js +146 -183
- package/dist/response-viewer/index.mjs +1 -1
- package/dist/styles.css +2 -2
- package/dist/templates/index.d.mts +1 -1
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +103 -19
- package/dist/templates/index.mjs +1 -1
- package/dist/theme-editor/index.d.mts +12 -7
- package/dist/theme-editor/index.d.ts +12 -7
- package/dist/theme-editor/index.js +971 -214
- package/dist/theme-editor/index.mjs +1 -1
- package/dist/{types-bFHsZT1n.d.mts → types-BQOeI3LX.d.mts} +1 -1
- package/dist/{types-bFHsZT1n.d.ts → types-BQOeI3LX.d.ts} +1 -1
- package/package.json +29 -18
- package/theme-editor/styles.css +497 -466
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React = require('react');
|
|
4
4
|
var jsxRuntime = require('react/jsx-runtime');
|
|
5
5
|
var core = require('@dnd-kit/core');
|
|
6
6
|
var lucideReact = require('lucide-react');
|
|
@@ -8,9 +8,31 @@ var fieldcraftReact = require('@squaredr/fieldcraft-react');
|
|
|
8
8
|
var fieldcraftCore = require('@squaredr/fieldcraft-core');
|
|
9
9
|
var clsx = require('clsx');
|
|
10
10
|
var tailwindMerge = require('tailwind-merge');
|
|
11
|
-
var
|
|
11
|
+
var SelectPrimitive = require('@radix-ui/react-select');
|
|
12
|
+
var react = require('@xyflow/react');
|
|
12
13
|
require('@xyflow/react/dist/style.css');
|
|
13
14
|
|
|
15
|
+
function _interopNamespace(e) {
|
|
16
|
+
if (e && e.__esModule) return e;
|
|
17
|
+
var n = Object.create(null);
|
|
18
|
+
if (e) {
|
|
19
|
+
Object.keys(e).forEach(function (k) {
|
|
20
|
+
if (k !== 'default') {
|
|
21
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
22
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
23
|
+
enumerable: true,
|
|
24
|
+
get: function () { return e[k]; }
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
n.default = e;
|
|
30
|
+
return Object.freeze(n);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
|
+
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
35
|
+
|
|
14
36
|
// ../license/dist/index.mjs
|
|
15
37
|
var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
16
38
|
"localhost",
|
|
@@ -85,9 +107,9 @@ function isProductionEnvironment() {
|
|
|
85
107
|
}
|
|
86
108
|
typeof process !== "undefined" && process.env?.NEXT_PUBLIC_FCPRO_PING_URL || "https://fieldcraft.dev/api/license/ping";
|
|
87
109
|
var defaultContext = { status: "validating" };
|
|
88
|
-
var LicenseCtx =
|
|
110
|
+
var LicenseCtx = React.createContext(defaultContext);
|
|
89
111
|
function useLicense() {
|
|
90
|
-
return
|
|
112
|
+
return React.useContext(LicenseCtx);
|
|
91
113
|
}
|
|
92
114
|
function UnlicensedOverlay({ featureName, reason, children }) {
|
|
93
115
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", minHeight: "200px" }, children: [
|
|
@@ -312,38 +334,40 @@ function requireLicense(Component3, featureName) {
|
|
|
312
334
|
}
|
|
313
335
|
var MAX_HISTORY = 50;
|
|
314
336
|
function useUndoRedo(currentSchema, setSchema) {
|
|
315
|
-
const historyRef =
|
|
316
|
-
const [currentIndex, setCurrentIndex] =
|
|
337
|
+
const historyRef = React.useRef([currentSchema]);
|
|
338
|
+
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
317
339
|
const canUndo = currentIndex > 0;
|
|
318
340
|
const canRedo = currentIndex < historyRef.current.length - 1;
|
|
319
|
-
const push =
|
|
341
|
+
const push = React.useCallback(
|
|
320
342
|
(schema) => {
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
343
|
+
setCurrentIndex((prevIndex) => {
|
|
344
|
+
historyRef.current = historyRef.current.slice(0, prevIndex + 1);
|
|
345
|
+
historyRef.current.push(schema);
|
|
346
|
+
let newIndex = prevIndex + 1;
|
|
347
|
+
if (historyRef.current.length > MAX_HISTORY) {
|
|
348
|
+
historyRef.current.shift();
|
|
349
|
+
newIndex = Math.max(0, newIndex - 1);
|
|
350
|
+
}
|
|
351
|
+
return newIndex;
|
|
352
|
+
});
|
|
329
353
|
},
|
|
330
|
-
[
|
|
354
|
+
[]
|
|
331
355
|
);
|
|
332
|
-
const undo =
|
|
356
|
+
const undo = React.useCallback(() => {
|
|
333
357
|
if (currentIndex > 0) {
|
|
334
358
|
const newIndex = currentIndex - 1;
|
|
335
359
|
setCurrentIndex(newIndex);
|
|
336
360
|
setSchema(historyRef.current[newIndex]);
|
|
337
361
|
}
|
|
338
362
|
}, [currentIndex, setSchema]);
|
|
339
|
-
const redo =
|
|
363
|
+
const redo = React.useCallback(() => {
|
|
340
364
|
if (currentIndex < historyRef.current.length - 1) {
|
|
341
365
|
const newIndex = currentIndex + 1;
|
|
342
366
|
setCurrentIndex(newIndex);
|
|
343
367
|
setSchema(historyRef.current[newIndex]);
|
|
344
368
|
}
|
|
345
369
|
}, [currentIndex, setSchema]);
|
|
346
|
-
const clear =
|
|
370
|
+
const clear = React.useCallback(() => {
|
|
347
371
|
historyRef.current = [currentSchema];
|
|
348
372
|
setCurrentIndex(0);
|
|
349
373
|
}, [currentSchema]);
|
|
@@ -358,13 +382,9 @@ function useUndoRedo(currentSchema, setSchema) {
|
|
|
358
382
|
}
|
|
359
383
|
|
|
360
384
|
// src/form-builder/utils/id-generator.ts
|
|
361
|
-
var counter = 0;
|
|
362
385
|
function generateId(prefix) {
|
|
363
|
-
const
|
|
364
|
-
|
|
365
|
-
counter = (counter + 1) % 1e4;
|
|
366
|
-
const count = counter.toString(36);
|
|
367
|
-
return `${prefix}_${timestamp}${count}${random}`;
|
|
386
|
+
const uuid = crypto.randomUUID().replace(/-/g, "").substring(0, 12);
|
|
387
|
+
return `${prefix}_${uuid}`;
|
|
368
388
|
}
|
|
369
389
|
function generateSectionId() {
|
|
370
390
|
return generateId("section");
|
|
@@ -451,18 +471,39 @@ function duplicateSection(schema, sectionId) {
|
|
|
451
471
|
const sectionIndex = newSchema.sections.findIndex((s) => s.id === sectionId);
|
|
452
472
|
if (sectionIndex === -1) return schema;
|
|
453
473
|
const original = newSchema.sections[sectionIndex];
|
|
474
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
475
|
+
for (const q of original.questions) {
|
|
476
|
+
idMap.set(q.id, generateQuestionId());
|
|
477
|
+
}
|
|
454
478
|
const duplicate = {
|
|
455
479
|
...original,
|
|
456
480
|
id: generateSectionId(),
|
|
457
481
|
title: `${original.title} (Copy)`,
|
|
482
|
+
showIf: original.showIf ? remapConditionFieldIds(original.showIf, idMap) : void 0,
|
|
458
483
|
questions: original.questions.map((q) => ({
|
|
459
484
|
...q,
|
|
460
|
-
id:
|
|
485
|
+
id: idMap.get(q.id),
|
|
486
|
+
showIf: q.showIf ? remapConditionFieldIds(q.showIf, idMap) : void 0
|
|
461
487
|
}))
|
|
462
488
|
};
|
|
463
489
|
newSchema.sections.splice(sectionIndex + 1, 0, duplicate);
|
|
464
490
|
return newSchema;
|
|
465
491
|
}
|
|
492
|
+
function remapConditionFieldIds(expr, idMap) {
|
|
493
|
+
if (expr.field) {
|
|
494
|
+
return {
|
|
495
|
+
...expr,
|
|
496
|
+
field: idMap.get(expr.field) ?? expr.field
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
if (expr.conditions) {
|
|
500
|
+
return {
|
|
501
|
+
...expr,
|
|
502
|
+
conditions: expr.conditions.map((c) => remapConditionFieldIds(c, idMap))
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
return expr;
|
|
506
|
+
}
|
|
466
507
|
function addQuestion(schema, sectionId, question, index) {
|
|
467
508
|
const newSchema = deepClone(schema);
|
|
468
509
|
const section = newSchema.sections.find((s) => s.id === sectionId);
|
|
@@ -572,16 +613,16 @@ function findSection(schema, sectionId) {
|
|
|
572
613
|
|
|
573
614
|
// src/form-builder/hooks/use-builder-state.ts
|
|
574
615
|
function useBuilderState(initialSchema) {
|
|
575
|
-
const [schema, setSchema] =
|
|
576
|
-
const [selectedItem, setSelectedItem] =
|
|
577
|
-
const [isDirty, setIsDirty] =
|
|
578
|
-
const schemaRef =
|
|
616
|
+
const [schema, setSchema] = React.useState(initialSchema);
|
|
617
|
+
const [selectedItem, setSelectedItem] = React.useState(null);
|
|
618
|
+
const [isDirty, setIsDirty] = React.useState(false);
|
|
619
|
+
const schemaRef = React.useRef(schema);
|
|
579
620
|
schemaRef.current = schema;
|
|
580
621
|
const undoRedo = useUndoRedo(schema, (newSchema) => {
|
|
581
622
|
setSchema(newSchema);
|
|
582
623
|
setIsDirty(true);
|
|
583
624
|
});
|
|
584
|
-
const updateSchema =
|
|
625
|
+
const updateSchema = React.useCallback(
|
|
585
626
|
(newSchema) => {
|
|
586
627
|
setSchema(newSchema);
|
|
587
628
|
undoRedo.push(newSchema);
|
|
@@ -589,54 +630,54 @@ function useBuilderState(initialSchema) {
|
|
|
589
630
|
},
|
|
590
631
|
[undoRedo]
|
|
591
632
|
);
|
|
592
|
-
const applyMutation =
|
|
633
|
+
const applyMutation = React.useCallback(
|
|
593
634
|
(mutate) => {
|
|
594
635
|
const result = mutate(schemaRef.current);
|
|
595
636
|
updateSchema(result);
|
|
596
637
|
},
|
|
597
638
|
[updateSchema]
|
|
598
639
|
);
|
|
599
|
-
const addSection2 =
|
|
640
|
+
const addSection2 = React.useCallback(
|
|
600
641
|
(section, index) => {
|
|
601
642
|
applyMutation((s) => addSection(s, section, index));
|
|
602
643
|
},
|
|
603
644
|
[applyMutation]
|
|
604
645
|
);
|
|
605
|
-
const removeSection2 =
|
|
646
|
+
const removeSection2 = React.useCallback(
|
|
606
647
|
(sectionId) => {
|
|
607
648
|
applyMutation((s) => removeSection(s, sectionId));
|
|
608
649
|
setSelectedItem((prev) => {
|
|
609
|
-
if (prev?.
|
|
650
|
+
if (prev?.sectionId === sectionId) return null;
|
|
610
651
|
return prev;
|
|
611
652
|
});
|
|
612
653
|
},
|
|
613
654
|
[applyMutation]
|
|
614
655
|
);
|
|
615
|
-
const updateSection2 =
|
|
656
|
+
const updateSection2 = React.useCallback(
|
|
616
657
|
(sectionId, updates) => {
|
|
617
658
|
applyMutation((s) => updateSection(s, sectionId, updates));
|
|
618
659
|
},
|
|
619
660
|
[applyMutation]
|
|
620
661
|
);
|
|
621
|
-
const moveSection2 =
|
|
662
|
+
const moveSection2 = React.useCallback(
|
|
622
663
|
(sectionId, newIndex) => {
|
|
623
664
|
applyMutation((s) => moveSection(s, sectionId, newIndex));
|
|
624
665
|
},
|
|
625
666
|
[applyMutation]
|
|
626
667
|
);
|
|
627
|
-
const duplicateSection2 =
|
|
668
|
+
const duplicateSection2 = React.useCallback(
|
|
628
669
|
(sectionId) => {
|
|
629
670
|
applyMutation((s) => duplicateSection(s, sectionId));
|
|
630
671
|
},
|
|
631
672
|
[applyMutation]
|
|
632
673
|
);
|
|
633
|
-
const addQuestion2 =
|
|
674
|
+
const addQuestion2 = React.useCallback(
|
|
634
675
|
(sectionId, question, index) => {
|
|
635
676
|
applyMutation((s) => addQuestion(s, sectionId, question, index));
|
|
636
677
|
},
|
|
637
678
|
[applyMutation]
|
|
638
679
|
);
|
|
639
|
-
const removeQuestion2 =
|
|
680
|
+
const removeQuestion2 = React.useCallback(
|
|
640
681
|
(sectionId, questionId) => {
|
|
641
682
|
applyMutation((s) => removeQuestion(s, sectionId, questionId));
|
|
642
683
|
setSelectedItem((prev) => {
|
|
@@ -648,34 +689,34 @@ function useBuilderState(initialSchema) {
|
|
|
648
689
|
},
|
|
649
690
|
[applyMutation]
|
|
650
691
|
);
|
|
651
|
-
const updateQuestion2 =
|
|
692
|
+
const updateQuestion2 = React.useCallback(
|
|
652
693
|
(sectionId, questionId, updates) => {
|
|
653
694
|
applyMutation((s) => updateQuestion(s, sectionId, questionId, updates));
|
|
654
695
|
},
|
|
655
696
|
[applyMutation]
|
|
656
697
|
);
|
|
657
|
-
const moveQuestion2 =
|
|
698
|
+
const moveQuestion2 = React.useCallback(
|
|
658
699
|
(sectionId, questionId, targetSectionId, newIndex) => {
|
|
659
700
|
applyMutation((s) => moveQuestion(s, sectionId, questionId, targetSectionId, newIndex));
|
|
660
701
|
},
|
|
661
702
|
[applyMutation]
|
|
662
703
|
);
|
|
663
|
-
const duplicateQuestion2 =
|
|
704
|
+
const duplicateQuestion2 = React.useCallback(
|
|
664
705
|
(sectionId, questionId) => {
|
|
665
706
|
applyMutation((s) => duplicateQuestion(s, sectionId, questionId));
|
|
666
707
|
},
|
|
667
708
|
[applyMutation]
|
|
668
709
|
);
|
|
669
|
-
const selectQuestion =
|
|
710
|
+
const selectQuestion = React.useCallback((sectionId, questionId) => {
|
|
670
711
|
setSelectedItem({ type: "question", sectionId, questionId });
|
|
671
712
|
}, []);
|
|
672
|
-
const selectSection =
|
|
713
|
+
const selectSection = React.useCallback((sectionId) => {
|
|
673
714
|
setSelectedItem({ type: "section", sectionId });
|
|
674
715
|
}, []);
|
|
675
|
-
const clearSelection =
|
|
716
|
+
const clearSelection = React.useCallback(() => {
|
|
676
717
|
setSelectedItem(null);
|
|
677
718
|
}, []);
|
|
678
|
-
const resetSchema =
|
|
719
|
+
const resetSchema = React.useCallback(
|
|
679
720
|
(newSchema) => {
|
|
680
721
|
setSchema(newSchema);
|
|
681
722
|
undoRedo.clear();
|
|
@@ -684,7 +725,7 @@ function useBuilderState(initialSchema) {
|
|
|
684
725
|
},
|
|
685
726
|
[undoRedo]
|
|
686
727
|
);
|
|
687
|
-
const markClean =
|
|
728
|
+
const markClean = React.useCallback(() => {
|
|
688
729
|
setIsDirty(false);
|
|
689
730
|
}, []);
|
|
690
731
|
return {
|
|
@@ -945,7 +986,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
945
986
|
category: "advanced",
|
|
946
987
|
icon: "ListPlus",
|
|
947
988
|
description: "Repeatable group of fields",
|
|
948
|
-
defaultConfig: { type: "repeater", fields: [],
|
|
989
|
+
defaultConfig: { type: "repeater", fields: [], minEntries: 1, maxEntries: 10 }
|
|
949
990
|
},
|
|
950
991
|
likert: {
|
|
951
992
|
type: "likert",
|
|
@@ -956,13 +997,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
956
997
|
requiresOptions: true,
|
|
957
998
|
defaultConfig: {
|
|
958
999
|
type: "likert",
|
|
959
|
-
|
|
960
|
-
{ label: "Strongly Disagree", value: "1" },
|
|
961
|
-
{ label: "Disagree", value: "2" },
|
|
962
|
-
{ label: "Neutral", value: "3" },
|
|
963
|
-
{ label: "Agree", value: "4" },
|
|
964
|
-
{ label: "Strongly Agree", value: "5" }
|
|
965
|
-
]
|
|
1000
|
+
labels: ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]
|
|
966
1001
|
}
|
|
967
1002
|
},
|
|
968
1003
|
scoring: {
|
|
@@ -1015,7 +1050,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
1015
1050
|
category: "advanced",
|
|
1016
1051
|
icon: "CreditCard",
|
|
1017
1052
|
description: "Collect payment via Stripe",
|
|
1018
|
-
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
|
|
1053
|
+
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD", serverUrl: "" }
|
|
1019
1054
|
},
|
|
1020
1055
|
// ── Structural ──
|
|
1021
1056
|
section_header: {
|
|
@@ -1162,7 +1197,7 @@ var DEFAULT_PALETTE = [
|
|
|
1162
1197
|
|
|
1163
1198
|
// src/form-builder/hooks/use-drag-drop.ts
|
|
1164
1199
|
function useDragDrop(builderState) {
|
|
1165
|
-
const [activeDragItem, setActiveDragItem] =
|
|
1200
|
+
const [activeDragItem, setActiveDragItem] = React.useState(null);
|
|
1166
1201
|
const sensors = core.useSensors(
|
|
1167
1202
|
core.useSensor(core.MouseSensor, {
|
|
1168
1203
|
activationConstraint: {
|
|
@@ -1212,11 +1247,11 @@ function useDragDrop(builderState) {
|
|
|
1212
1247
|
}
|
|
1213
1248
|
return null;
|
|
1214
1249
|
};
|
|
1215
|
-
const handleDragStart =
|
|
1250
|
+
const handleDragStart = React.useCallback((event) => {
|
|
1216
1251
|
const item = parseDragItem(event.active);
|
|
1217
1252
|
setActiveDragItem(item);
|
|
1218
1253
|
}, []);
|
|
1219
|
-
const handleDragCancel =
|
|
1254
|
+
const handleDragCancel = React.useCallback(() => {
|
|
1220
1255
|
setActiveDragItem(null);
|
|
1221
1256
|
}, []);
|
|
1222
1257
|
const handleDragEnd = (event) => {
|
|
@@ -1386,9 +1421,9 @@ function PaletteItem({ questionType, typeInfo }) {
|
|
|
1386
1421
|
);
|
|
1387
1422
|
}
|
|
1388
1423
|
function QuestionPalette({ questionTypes, palette }) {
|
|
1389
|
-
const [collapsed, setCollapsed] =
|
|
1390
|
-
const [search, setSearch] =
|
|
1391
|
-
const mergedPalette =
|
|
1424
|
+
const [collapsed, setCollapsed] = React.useState({});
|
|
1425
|
+
const [search, setSearch] = React.useState("");
|
|
1426
|
+
const mergedPalette = React.useMemo(
|
|
1392
1427
|
() => palette ? [...DEFAULT_PALETTE, ...palette] : DEFAULT_PALETTE,
|
|
1393
1428
|
[palette]
|
|
1394
1429
|
);
|
|
@@ -1469,13 +1504,13 @@ function QuestionBlock({
|
|
|
1469
1504
|
}) {
|
|
1470
1505
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
1471
1506
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
1472
|
-
const [isEditing, setIsEditing] =
|
|
1473
|
-
const [editValue, setEditValue] =
|
|
1474
|
-
const inputRef =
|
|
1475
|
-
|
|
1507
|
+
const [isEditing, setIsEditing] = React.useState(false);
|
|
1508
|
+
const [editValue, setEditValue] = React.useState(question.label);
|
|
1509
|
+
const inputRef = React.useRef(null);
|
|
1510
|
+
React.useEffect(() => {
|
|
1476
1511
|
if (!isEditing) setEditValue(question.label);
|
|
1477
1512
|
}, [question.label, isEditing]);
|
|
1478
|
-
|
|
1513
|
+
React.useEffect(() => {
|
|
1479
1514
|
if (isEditing && inputRef.current) {
|
|
1480
1515
|
inputRef.current.focus();
|
|
1481
1516
|
inputRef.current.select();
|
|
@@ -1632,7 +1667,7 @@ function ConfirmDialog({ open, title, message, onConfirm, onCancel }) {
|
|
|
1632
1667
|
);
|
|
1633
1668
|
}
|
|
1634
1669
|
function SectionBlock({ section, builderState }) {
|
|
1635
|
-
const [confirmDelete, setConfirmDelete] =
|
|
1670
|
+
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
|
1636
1671
|
const { setNodeRef } = core.useDroppable({
|
|
1637
1672
|
id: `section-end-${section.id}`,
|
|
1638
1673
|
data: { type: "section", sectionId: section.id, index: section.questions.length }
|
|
@@ -1745,6 +1780,14 @@ function SectionBlock({ section, builderState }) {
|
|
|
1745
1780
|
}
|
|
1746
1781
|
function FormCanvas({ builderState }) {
|
|
1747
1782
|
const { schema } = builderState;
|
|
1783
|
+
const [localTitle, setLocalTitle] = React.useState(schema.title);
|
|
1784
|
+
const [localDesc, setLocalDesc] = React.useState(schema.description ?? "");
|
|
1785
|
+
React.useEffect(() => {
|
|
1786
|
+
setLocalTitle(schema.title);
|
|
1787
|
+
}, [schema.title]);
|
|
1788
|
+
React.useEffect(() => {
|
|
1789
|
+
setLocalDesc(schema.description ?? "");
|
|
1790
|
+
}, [schema.description]);
|
|
1748
1791
|
const handleAddSection = () => {
|
|
1749
1792
|
const newSection = {
|
|
1750
1793
|
id: generateSectionId(),
|
|
@@ -1761,9 +1804,12 @@ function FormCanvas({ builderState }) {
|
|
|
1761
1804
|
"input",
|
|
1762
1805
|
{
|
|
1763
1806
|
type: "text",
|
|
1764
|
-
value:
|
|
1765
|
-
onChange: (e) =>
|
|
1766
|
-
|
|
1807
|
+
value: localTitle,
|
|
1808
|
+
onChange: (e) => setLocalTitle(e.target.value),
|
|
1809
|
+
onBlur: () => {
|
|
1810
|
+
if (localTitle !== schema.title) {
|
|
1811
|
+
builderState.updateSchema({ ...schema, title: localTitle });
|
|
1812
|
+
}
|
|
1767
1813
|
},
|
|
1768
1814
|
className: "w-full text-xl font-bold bg-transparent text-foreground border-0 outline-none p-1.5 rounded-md focus:bg-card transition-colors",
|
|
1769
1815
|
placeholder: "Form Title"
|
|
@@ -1772,9 +1818,12 @@ function FormCanvas({ builderState }) {
|
|
|
1772
1818
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1773
1819
|
"textarea",
|
|
1774
1820
|
{
|
|
1775
|
-
value:
|
|
1776
|
-
onChange: (e) =>
|
|
1777
|
-
|
|
1821
|
+
value: localDesc,
|
|
1822
|
+
onChange: (e) => setLocalDesc(e.target.value),
|
|
1823
|
+
onBlur: () => {
|
|
1824
|
+
if (localDesc !== (schema.description ?? "")) {
|
|
1825
|
+
builderState.updateSchema({ ...schema, description: localDesc || void 0 });
|
|
1826
|
+
}
|
|
1778
1827
|
},
|
|
1779
1828
|
className: "w-full text-sm text-muted-foreground bg-transparent border-0 outline-none p-1.5 resize-y min-h-12 rounded-md leading-relaxed focus:bg-card transition-colors",
|
|
1780
1829
|
placeholder: "Form description (optional)"
|
|
@@ -1813,259 +1862,469 @@ function FormCanvas({ builderState }) {
|
|
|
1813
1862
|
] })
|
|
1814
1863
|
] }) });
|
|
1815
1864
|
}
|
|
1816
|
-
var
|
|
1817
|
-
|
|
1818
|
-
|
|
1865
|
+
var Select = SelectPrimitive__namespace.Root;
|
|
1866
|
+
var SelectTrigger = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1867
|
+
SelectPrimitive__namespace.Trigger,
|
|
1868
|
+
{
|
|
1869
|
+
ref,
|
|
1870
|
+
className: cn(
|
|
1871
|
+
"flex h-9 w-full items-center justify-between rounded-md border border-input bg-card px-3 py-1 text-sm shadow-xs transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
|
1872
|
+
className
|
|
1873
|
+
),
|
|
1874
|
+
...props,
|
|
1875
|
+
children: [
|
|
1876
|
+
children,
|
|
1877
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4 text-muted-foreground" }) })
|
|
1878
|
+
]
|
|
1879
|
+
}
|
|
1880
|
+
));
|
|
1881
|
+
SelectTrigger.displayName = "SelectTrigger";
|
|
1882
|
+
var SelectContent = React__namespace.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1883
|
+
SelectPrimitive__namespace.Content,
|
|
1884
|
+
{
|
|
1885
|
+
ref,
|
|
1886
|
+
className: cn(
|
|
1887
|
+
"relative z-50 max-h-64 min-w-[8rem] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
1888
|
+
position === "popper" && "data-[side=bottom]:translate-y-1 data-[side=left]:-translate-x-1 data-[side=right]:translate-x-1 data-[side=top]:-translate-y-1",
|
|
1889
|
+
className
|
|
1890
|
+
),
|
|
1891
|
+
position,
|
|
1892
|
+
...props,
|
|
1893
|
+
children: [
|
|
1894
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollUpButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4" }) }),
|
|
1819
1895
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1820
|
-
|
|
1896
|
+
SelectPrimitive__namespace.Viewport,
|
|
1821
1897
|
{
|
|
1822
|
-
ref,
|
|
1823
1898
|
className: cn(
|
|
1824
|
-
"
|
|
1825
|
-
|
|
1899
|
+
"p-1",
|
|
1900
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
1826
1901
|
),
|
|
1827
|
-
...props,
|
|
1828
1902
|
children
|
|
1829
1903
|
}
|
|
1830
1904
|
),
|
|
1831
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1832
|
-
]
|
|
1905
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ScrollDownButton, { className: "flex cursor-default items-center justify-center py-1", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" }) })
|
|
1906
|
+
]
|
|
1833
1907
|
}
|
|
1834
|
-
);
|
|
1835
|
-
|
|
1908
|
+
) }));
|
|
1909
|
+
SelectContent.displayName = "SelectContent";
|
|
1910
|
+
var SelectItem = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1911
|
+
SelectPrimitive__namespace.Item,
|
|
1912
|
+
{
|
|
1913
|
+
ref,
|
|
1914
|
+
className: cn(
|
|
1915
|
+
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-2 pr-8 text-sm outline-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
|
1916
|
+
className
|
|
1917
|
+
),
|
|
1918
|
+
...props,
|
|
1919
|
+
children: [
|
|
1920
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute right-2 flex size-3.5 items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemIndicator, { children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-4" }) }) }),
|
|
1921
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
|
|
1922
|
+
]
|
|
1923
|
+
}
|
|
1924
|
+
));
|
|
1925
|
+
SelectItem.displayName = "SelectItem";
|
|
1836
1926
|
function useConfigUpdater(question, onUpdate) {
|
|
1837
|
-
return (
|
|
1927
|
+
return (updates) => {
|
|
1838
1928
|
const current = question.config ?? {};
|
|
1839
|
-
|
|
1929
|
+
const merged = { ...current, type: question.type, ...updates };
|
|
1930
|
+
for (const key of Object.keys(merged)) {
|
|
1931
|
+
if (merged[key] === void 0) delete merged[key];
|
|
1932
|
+
}
|
|
1933
|
+
onUpdate({ config: merged });
|
|
1840
1934
|
};
|
|
1841
1935
|
}
|
|
1842
|
-
function QuestionConfigEditor({ question, onUpdate }) {
|
|
1936
|
+
function QuestionConfigEditor({ question, schema, onUpdate }) {
|
|
1843
1937
|
const updateConfig = useConfigUpdater(question, onUpdate);
|
|
1844
1938
|
const config = question.config ?? {};
|
|
1939
|
+
const allQuestions = React.useMemo(() => {
|
|
1940
|
+
if (!schema?.sections) return [];
|
|
1941
|
+
return schema.sections.flatMap((s) => s.questions || []);
|
|
1942
|
+
}, [schema]);
|
|
1943
|
+
const candidateAmountFields = React.useMemo(() => {
|
|
1944
|
+
return allQuestions.filter((q) => q.id !== question.id && ["calculated", "number", "slider", "rating", "single_select"].includes(q.type)).map((q) => ({ label: `${q.label || q.id} (${q.id})`, value: q.id }));
|
|
1945
|
+
}, [allQuestions, question.id]);
|
|
1946
|
+
const candidateTimezoneFields = React.useMemo(() => {
|
|
1947
|
+
return allQuestions.filter((q) => q.id !== question.id && ["dropdown", "single_select", "short_text"].includes(q.type)).map((q) => ({ label: `${q.label || q.id} (${q.id})`, value: q.id }));
|
|
1948
|
+
}, [allQuestions, question.id]);
|
|
1845
1949
|
switch (question.type) {
|
|
1846
1950
|
// ── Text ──
|
|
1847
1951
|
case "short_text":
|
|
1848
1952
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Text Settings", children: [
|
|
1849
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "255", onChange: (v) => updateConfig(
|
|
1850
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Input Type", value: config.inputType ?? "text", options: [{ label: "Text", value: "text" }, { label: "Password", value: "password" }], onChange: (v) => updateConfig(
|
|
1851
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig(
|
|
1852
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. USD", onChange: (v) => updateConfig(
|
|
1953
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "255", onChange: (v) => updateConfig({ maxLength: v }) }),
|
|
1954
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Input Type", value: config.inputType ?? "text", options: [{ label: "Text", value: "text" }, { label: "Password", value: "password" }], onChange: (v) => updateConfig({ inputType: v }) }),
|
|
1955
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig({ prefix: v }) }),
|
|
1956
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. USD", onChange: (v) => updateConfig({ suffix: v }) })
|
|
1853
1957
|
] });
|
|
1854
1958
|
case "long_text":
|
|
1855
1959
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Text Settings", children: [
|
|
1856
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "No limit", onChange: (v) => updateConfig(
|
|
1857
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Rows", value: config.rows, placeholder: "4", onChange: (v) => updateConfig(
|
|
1858
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Character Count", checked: !!config.showCharCount, onChange: (v) => updateConfig(
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "No limit", onChange: (v) => updateConfig({ maxLength: v }) }),
|
|
1961
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Rows", value: config.rows, placeholder: "4", onChange: (v) => updateConfig({ rows: v }) }),
|
|
1962
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Character Count", checked: !!config.showCharCount, onChange: (v) => updateConfig({ showCharCount: v }) })
|
|
1859
1963
|
] });
|
|
1860
1964
|
case "legal_name":
|
|
1861
1965
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Name Fields", children: [
|
|
1862
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Middle Name", checked: !!config.showMiddleName, onChange: (v) => updateConfig(
|
|
1863
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Suffix", checked: !!config.showSuffix, onChange: (v) => updateConfig(
|
|
1966
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Middle Name", checked: !!config.showMiddleName, onChange: (v) => updateConfig({ showMiddleName: v }) }),
|
|
1967
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Suffix", checked: !!config.showSuffix, onChange: (v) => updateConfig({ showSuffix: v }) })
|
|
1864
1968
|
] });
|
|
1865
1969
|
// ── Numeric ──
|
|
1866
1970
|
case "number":
|
|
1867
1971
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Number Settings", children: [
|
|
1868
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, onChange: (v) => updateConfig(
|
|
1869
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, onChange: (v) => updateConfig(
|
|
1870
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1871
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1872
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1873
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. kg", onChange: (v) => updateConfig("suffix", v) })
|
|
1972
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Value", value: config.min, onChange: (v) => updateConfig({ min: v }) }),
|
|
1973
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Value", value: config.max, onChange: (v) => updateConfig({ max: v }) }),
|
|
1974
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v }) }),
|
|
1975
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig({ prefix: v }) }),
|
|
1976
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. kg", onChange: (v) => updateConfig({ suffix: v }) })
|
|
1874
1977
|
] });
|
|
1875
1978
|
case "slider":
|
|
1876
1979
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Slider Settings", children: [
|
|
1877
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "0", onChange: (v) => updateConfig(
|
|
1878
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "100", onChange: (v) => updateConfig(
|
|
1879
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1880
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1881
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1882
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1980
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Value", value: config.min, placeholder: "0", onChange: (v) => updateConfig({ min: v ?? 0 }) }),
|
|
1981
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Value", value: config.max, placeholder: "100", onChange: (v) => updateConfig({ max: v ?? 100 }) }),
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v ?? 1 }) }),
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, placeholder: "Low", onChange: (v) => updateConfig({ minLabel: v }) }),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, placeholder: "High", onChange: (v) => updateConfig({ maxLabel: v }) }),
|
|
1985
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Value", checked: config.showValue !== false, onChange: (v) => updateConfig({ showValue: v }) }),
|
|
1986
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Unit", value: config.unit, placeholder: "e.g. %", onChange: (v) => updateConfig({ unit: v }) })
|
|
1883
1987
|
] });
|
|
1884
1988
|
case "rating":
|
|
1885
1989
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rating Settings", children: [
|
|
1886
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max
|
|
1887
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "
|
|
1888
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "
|
|
1990
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Rating", value: config.maxRating, placeholder: "5", onChange: (v) => updateConfig({ maxRating: v ?? 5 }) }),
|
|
1991
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "Thumb", value: "thumb" }], onChange: (v) => updateConfig({ icon: v }) }),
|
|
1992
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Half Ratings", checked: !!config.allowHalf, onChange: (v) => updateConfig({ allowHalf: v }) })
|
|
1889
1993
|
] });
|
|
1890
1994
|
case "nps":
|
|
1891
1995
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "NPS Settings", children: [
|
|
1892
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1893
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1996
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Left Label", value: config.leftLabel ?? "Not likely", onChange: (v) => updateConfig({ leftLabel: v }) }),
|
|
1997
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Right Label", value: config.rightLabel ?? "Extremely likely", onChange: (v) => updateConfig({ rightLabel: v }) })
|
|
1894
1998
|
] });
|
|
1895
1999
|
case "opinion_scale":
|
|
1896
2000
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Scale Settings", children: [
|
|
1897
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "1", onChange: (v) => updateConfig(
|
|
1898
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "5", onChange: (v) => updateConfig(
|
|
1899
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1900
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig(
|
|
1901
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, onChange: (v) => updateConfig(
|
|
2001
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "1", onChange: (v) => updateConfig({ min: v }) }),
|
|
2002
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "5", onChange: (v) => updateConfig({ max: v }) }),
|
|
2003
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v }) }),
|
|
2004
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig({ minLabel: v }) }),
|
|
2005
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, onChange: (v) => updateConfig({ maxLabel: v }) })
|
|
1902
2006
|
] });
|
|
1903
2007
|
case "likert":
|
|
1904
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Likert Settings", children: /* @__PURE__ */ jsxRuntime.jsx(LikertLabelsEditor, { labels: config.labels ?? ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"], onChange: (v) => updateConfig(
|
|
2008
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Likert Settings", children: /* @__PURE__ */ jsxRuntime.jsx(LikertLabelsEditor, { labels: config.labels ?? ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"], onChange: (v) => updateConfig({ labels: v }) }) });
|
|
1905
2009
|
// ── Selection ──
|
|
1906
2010
|
case "single_select":
|
|
1907
2011
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Select Settings", children: [
|
|
1908
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Layout", value: config.layout ?? "vertical", options: [{ label: "Vertical", value: "vertical" }, { label: "Horizontal", value: "horizontal" }, { label: "Grid", value: "grid" }], onChange: (v) => updateConfig(
|
|
1909
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1910
|
-
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig(
|
|
2012
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Layout", value: config.layout ?? "vertical", options: [{ label: "Vertical", value: "vertical" }, { label: "Horizontal", value: "horizontal" }, { label: "Grid", value: "grid" }], onChange: (v) => updateConfig({ layout: v }) }),
|
|
2013
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => v ? updateConfig({ allowOther: true }) : updateConfig({ allowOther: false, otherLabel: void 0 }) }),
|
|
2014
|
+
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig({ otherLabel: v }) })
|
|
1911
2015
|
] });
|
|
1912
2016
|
case "multi_select":
|
|
1913
2017
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Multi-Select Settings", children: [
|
|
1914
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Layout", value: config.layout ?? "vertical", options: [{ label: "Vertical", value: "vertical" }, { label: "Horizontal", value: "horizontal" }, { label: "Grid", value: "grid" }], onChange: (v) => updateConfig(
|
|
1915
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Selections", value: config.minSelections, onChange: (v) => updateConfig(
|
|
1916
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Selections", value: config.maxSelections, onChange: (v) => updateConfig(
|
|
1917
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1918
|
-
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig(
|
|
2018
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Layout", value: config.layout ?? "vertical", options: [{ label: "Vertical", value: "vertical" }, { label: "Horizontal", value: "horizontal" }, { label: "Grid", value: "grid" }], onChange: (v) => updateConfig({ layout: v }) }),
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Selections", value: config.minSelections, onChange: (v) => updateConfig({ minSelections: v }) }),
|
|
2020
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Selections", value: config.maxSelections, onChange: (v) => updateConfig({ maxSelections: v }) }),
|
|
2021
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => v ? updateConfig({ allowOther: true }) : updateConfig({ allowOther: false, otherLabel: void 0 }) }),
|
|
2022
|
+
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig({ otherLabel: v }) })
|
|
1919
2023
|
] });
|
|
1920
2024
|
case "dropdown":
|
|
1921
2025
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Dropdown Settings", children: [
|
|
1922
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Searchable", checked: !!config.searchable, onChange: (v) => updateConfig(
|
|
1923
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1924
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Multiple", checked: !!config.multiple, onChange: (v) => updateConfig(
|
|
2026
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Searchable", checked: !!config.searchable, onChange: (v) => updateConfig({ searchable: v }) }),
|
|
2027
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig({ allowOther: v }) }),
|
|
2028
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Multiple", checked: !!config.multiple, onChange: (v) => updateConfig({ multiple: v }) })
|
|
1925
2029
|
] });
|
|
1926
2030
|
case "boolean":
|
|
1927
2031
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Yes/No Settings", children: [
|
|
1928
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Style", value: config.style ?? "toggle", options: [{ label: "Toggle", value: "toggle" }, { label: "Radio", value: "radio" }, { label: "Checkbox", value: "checkbox" }], onChange: (v) => updateConfig(
|
|
1929
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "True Label", value: config.trueLabel ?? "Yes", onChange: (v) => updateConfig(
|
|
1930
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "False Label", value: config.falseLabel ?? "No", onChange: (v) => updateConfig(
|
|
2032
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Style", value: config.style ?? "toggle", options: [{ label: "Toggle", value: "toggle" }, { label: "Radio", value: "radio" }, { label: "Checkbox", value: "checkbox" }], onChange: (v) => updateConfig({ style: v }) }),
|
|
2033
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "True Label", value: config.trueLabel ?? "Yes", onChange: (v) => updateConfig({ trueLabel: v }) }),
|
|
2034
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "False Label", value: config.falseLabel ?? "No", onChange: (v) => updateConfig({ falseLabel: v }) })
|
|
1931
2035
|
] });
|
|
1932
2036
|
case "country_select":
|
|
1933
2037
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Country Settings", children: [
|
|
1934
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Flags", checked: config.showFlags !== false, onChange: (v) => updateConfig(
|
|
1935
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Priority Countries", value: config.priorityCountries?.join(", "), placeholder: "e.g. US, GB, CA", onChange: (v) => updateConfig(
|
|
1936
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Exclude Countries", value: config.excludeCountries?.join(", "), placeholder: "e.g. XX, YY", onChange: (v) => updateConfig(
|
|
2038
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Flags", checked: config.showFlags !== false, onChange: (v) => updateConfig({ showFlags: v }) }),
|
|
2039
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Priority Countries", value: config.priorityCountries?.join(", "), placeholder: "e.g. US, GB, CA", onChange: (v) => updateConfig({ priorityCountries: v ? v.split(",").map((s) => s.trim()).filter(Boolean) : void 0 }) }),
|
|
2040
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Exclude Countries", value: config.excludeCountries?.join(", "), placeholder: "e.g. XX, YY", onChange: (v) => updateConfig({ excludeCountries: v ? v.split(",").map((s) => s.trim()).filter(Boolean) : void 0 }) })
|
|
1937
2041
|
] });
|
|
1938
2042
|
// ── Date/Time ──
|
|
1939
2043
|
case "date":
|
|
1940
2044
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Date Settings", children: [
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1942
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1943
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Past Dates", checked: !!config.disablePast, onChange: (v) => updateConfig(
|
|
1944
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Future Dates", checked: !!config.disableFuture, onChange: (v) => updateConfig(
|
|
1945
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Format", value: config.format, placeholder: "e.g. MM/DD/YYYY", onChange: (v) => updateConfig(
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ minDate: v }) }),
|
|
2046
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ maxDate: v }) }),
|
|
2047
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Past Dates", checked: !!config.disablePast, onChange: (v) => updateConfig({ disablePast: v }) }),
|
|
2048
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Future Dates", checked: !!config.disableFuture, onChange: (v) => updateConfig({ disableFuture: v }) }),
|
|
2049
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Format", value: config.format, placeholder: "e.g. MM/DD/YYYY", onChange: (v) => updateConfig({ format: v }) })
|
|
1946
2050
|
] });
|
|
1947
2051
|
case "time":
|
|
1948
2052
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Time Settings", children: [
|
|
1949
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "12h", options: [{ label: "12 Hour", value: "12h" }, { label: "24 Hour", value: "24h" }], onChange: (v) => updateConfig(
|
|
1950
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Minute Step", value: config.minuteStep, placeholder: "1", onChange: (v) => updateConfig(
|
|
2053
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "12h", options: [{ label: "12 Hour", value: "12h" }, { label: "24 Hour", value: "24h" }], onChange: (v) => updateConfig({ format: v }) }),
|
|
2054
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Minute Step", value: config.minuteStep, placeholder: "1", onChange: (v) => updateConfig({ minuteStep: v }) })
|
|
1951
2055
|
] });
|
|
1952
2056
|
case "date_range":
|
|
1953
2057
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Date Range Settings", children: [
|
|
1954
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1955
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1956
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Range (days)", value: config.maxRangeDays, onChange: (v) => updateConfig(
|
|
2058
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ minDate: v }) }),
|
|
2059
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ maxDate: v }) }),
|
|
2060
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Range (days)", value: config.maxRangeDays, onChange: (v) => updateConfig({ maxRangeDays: v }) })
|
|
1957
2061
|
] });
|
|
1958
|
-
case "appointment":
|
|
2062
|
+
case "appointment": {
|
|
2063
|
+
const appointmentMode = typeof config.slotsUrl === "string" ? "url" : typeof config.embedUrl === "string" ? "embed" : "static";
|
|
2064
|
+
const timezoneFieldOptions = [
|
|
2065
|
+
{ label: "None (Static Timezone)", value: "" },
|
|
2066
|
+
...candidateTimezoneFields,
|
|
2067
|
+
{ label: "Custom Field ID...", value: "__custom__" }
|
|
2068
|
+
];
|
|
2069
|
+
const isCustomTzField = Boolean(config.timezoneField) && !candidateTimezoneFields.some((opt) => opt.value === config.timezoneField);
|
|
1959
2070
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Appointment Settings", children: [
|
|
1960
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1961
|
-
|
|
1962
|
-
|
|
2071
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2072
|
+
SelectField,
|
|
2073
|
+
{
|
|
2074
|
+
label: "Scheduling Mode",
|
|
2075
|
+
value: appointmentMode,
|
|
2076
|
+
options: [
|
|
2077
|
+
{ label: "Manual Static Slots", value: "static" },
|
|
2078
|
+
{ label: "Fetch from URL", value: "url" },
|
|
2079
|
+
{ label: "Third-Party Embed (Calendly / Cal.com)", value: "embed" }
|
|
2080
|
+
],
|
|
2081
|
+
onChange: (v) => {
|
|
2082
|
+
if (v === "url") {
|
|
2083
|
+
updateConfig({
|
|
2084
|
+
slotsUrl: "",
|
|
2085
|
+
embedUrl: void 0,
|
|
2086
|
+
embedProvider: void 0,
|
|
2087
|
+
slots: void 0
|
|
2088
|
+
});
|
|
2089
|
+
} else if (v === "embed") {
|
|
2090
|
+
updateConfig({
|
|
2091
|
+
embedUrl: "",
|
|
2092
|
+
embedProvider: config.embedProvider || "cal_com",
|
|
2093
|
+
slotsUrl: void 0,
|
|
2094
|
+
slots: void 0
|
|
2095
|
+
});
|
|
2096
|
+
} else {
|
|
2097
|
+
updateConfig({
|
|
2098
|
+
slots: config.slots ?? [],
|
|
2099
|
+
slotsUrl: void 0,
|
|
2100
|
+
embedUrl: void 0,
|
|
2101
|
+
embedProvider: void 0
|
|
2102
|
+
});
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
}
|
|
2106
|
+
),
|
|
2107
|
+
appointmentMode === "url" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2108
|
+
TextField,
|
|
2109
|
+
{
|
|
2110
|
+
label: "Slots URL",
|
|
2111
|
+
value: config.slotsUrl,
|
|
2112
|
+
placeholder: "https://example.com/slots",
|
|
2113
|
+
onChange: (v) => updateConfig({ slotsUrl: v ?? "" })
|
|
2114
|
+
}
|
|
2115
|
+
),
|
|
2116
|
+
appointmentMode === "embed" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2118
|
+
TextField,
|
|
2119
|
+
{
|
|
2120
|
+
label: "Embed URL",
|
|
2121
|
+
value: config.embedUrl,
|
|
2122
|
+
placeholder: "https://calendly.com/... or https://cal.com/...",
|
|
2123
|
+
onChange: (v) => updateConfig({ embedUrl: v ?? "" })
|
|
2124
|
+
}
|
|
2125
|
+
),
|
|
2126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2127
|
+
SelectField,
|
|
2128
|
+
{
|
|
2129
|
+
label: "Embed Provider",
|
|
2130
|
+
value: config.embedProvider ?? "cal_com",
|
|
2131
|
+
options: [
|
|
2132
|
+
{ label: "Cal.com", value: "cal_com" },
|
|
2133
|
+
{ label: "Calendly", value: "calendly" },
|
|
2134
|
+
{ label: "Custom", value: "custom" }
|
|
2135
|
+
],
|
|
2136
|
+
onChange: (v) => updateConfig({ embedProvider: v })
|
|
2137
|
+
}
|
|
2138
|
+
)
|
|
2139
|
+
] }),
|
|
2140
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Duration (min)", value: config.duration ?? 30, onChange: (v) => updateConfig({ duration: v }) }),
|
|
2141
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Timezone", value: config.timezone, placeholder: "e.g. America/New_York", onChange: (v) => updateConfig({ timezone: v }) }),
|
|
2142
|
+
candidateTimezoneFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2143
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2144
|
+
SelectField,
|
|
2145
|
+
{
|
|
2146
|
+
label: "Dynamic Timezone Field",
|
|
2147
|
+
value: isCustomTzField ? "__custom__" : config.timezoneField ?? "",
|
|
2148
|
+
options: timezoneFieldOptions,
|
|
2149
|
+
onChange: (v) => {
|
|
2150
|
+
if (v !== "__custom__") {
|
|
2151
|
+
updateConfig({ timezoneField: v || void 0 });
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
),
|
|
2156
|
+
isCustomTzField && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2157
|
+
TextField,
|
|
2158
|
+
{
|
|
2159
|
+
label: "Custom Timezone Field ID",
|
|
2160
|
+
value: config.timezoneField,
|
|
2161
|
+
placeholder: "e.g. timezone",
|
|
2162
|
+
onChange: (v) => updateConfig({ timezoneField: v || void 0 })
|
|
2163
|
+
}
|
|
2164
|
+
) })
|
|
2165
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2166
|
+
TextField,
|
|
2167
|
+
{
|
|
2168
|
+
label: "Timezone Field",
|
|
2169
|
+
value: config.timezoneField,
|
|
2170
|
+
placeholder: "Field ID for dynamic timezone",
|
|
2171
|
+
onChange: (v) => updateConfig({ timezoneField: v || void 0 })
|
|
2172
|
+
}
|
|
2173
|
+
),
|
|
2174
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Date Format", value: config.dateFormat, placeholder: "Locale-aware (default)", onChange: (v) => updateConfig({ dateFormat: v }) }),
|
|
2175
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2176
|
+
ToggleField,
|
|
2177
|
+
{
|
|
2178
|
+
label: "Auto-Advance on Booking Complete",
|
|
2179
|
+
checked: config.autoAdvance !== false,
|
|
2180
|
+
onChange: (v) => updateConfig({ autoAdvance: v })
|
|
2181
|
+
}
|
|
2182
|
+
),
|
|
2183
|
+
appointmentMode === "static" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2184
|
+
AppointmentSlotsEditor,
|
|
2185
|
+
{
|
|
2186
|
+
slots: config.slots ?? [],
|
|
2187
|
+
onChange: (v) => updateConfig({ slots: v })
|
|
2188
|
+
}
|
|
2189
|
+
)
|
|
1963
2190
|
] });
|
|
2191
|
+
}
|
|
1964
2192
|
// ── Media ──
|
|
1965
2193
|
case "file_upload":
|
|
1966
2194
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Upload Settings", children: [
|
|
1967
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
2195
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2.5 bg-muted/40 border border-border rounded-md text-xs text-muted-foreground flex items-center gap-1.5", children: [
|
|
2196
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u{1F4E6}" }),
|
|
2197
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Uploads stream to your cloud bucket using Form / Account Storage settings." })
|
|
2198
|
+
] }),
|
|
2199
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Files", value: config.maxFiles ?? 1, onChange: (v) => updateConfig({ maxFiles: v }) }),
|
|
2200
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb ?? 10, onChange: (v) => updateConfig({ maxSizeMb: v }) }),
|
|
2201
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2202
|
+
TextField,
|
|
2203
|
+
{
|
|
2204
|
+
label: "Accepted Types (comma-separated)",
|
|
2205
|
+
value: config.accept?.join(", "),
|
|
2206
|
+
placeholder: "e.g. image/*, .pdf, .docx, .zip",
|
|
2207
|
+
onChange: (v) => updateConfig({
|
|
2208
|
+
accept: v ? v.split(",").map((s) => s.trim()).filter(Boolean) : void 0
|
|
2209
|
+
})
|
|
2210
|
+
}
|
|
2211
|
+
),
|
|
2212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2213
|
+
TextField,
|
|
2214
|
+
{
|
|
2215
|
+
label: "Upload URL",
|
|
2216
|
+
value: config.uploadUrl,
|
|
2217
|
+
placeholder: "https://api.example.com/s3/presign",
|
|
2218
|
+
onChange: (v) => updateConfig({ uploadUrl: v || void 0 })
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2222
|
+
TextField,
|
|
2223
|
+
{
|
|
2224
|
+
label: "Public Key",
|
|
2225
|
+
value: config.publicKey,
|
|
2226
|
+
placeholder: "pk_test_...",
|
|
2227
|
+
onChange: (v) => updateConfig({ publicKey: v || void 0 })
|
|
2228
|
+
}
|
|
2229
|
+
)
|
|
1971
2230
|
] });
|
|
1972
2231
|
case "signature":
|
|
1973
2232
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Signature Settings", children: [
|
|
1974
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Pen Color", value: config.penColor, placeholder: "#000000", onChange: (v) => updateConfig(
|
|
1975
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Background", value: config.backgroundColor, placeholder: "#ffffff", onChange: (v) => updateConfig(
|
|
1976
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Width (px)", value: config.width, onChange: (v) => updateConfig(
|
|
1977
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Height (px)", value: config.height, onChange: (v) => updateConfig(
|
|
2233
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Pen Color", value: config.penColor, placeholder: "#000000", onChange: (v) => updateConfig({ penColor: v }) }),
|
|
2234
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Background", value: config.backgroundColor, placeholder: "#ffffff", onChange: (v) => updateConfig({ backgroundColor: v }) }),
|
|
2235
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Width (px)", value: config.width, onChange: (v) => updateConfig({ width: v }) }),
|
|
2236
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Height (px)", value: config.height, onChange: (v) => updateConfig({ height: v }) })
|
|
1978
2237
|
] });
|
|
1979
2238
|
case "image_capture":
|
|
1980
2239
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Camera Settings", children: [
|
|
1981
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Camera", value: config.camera ?? "any", options: [{ label: "Any", value: "any" }, { label: "Front", value: "front" }, { label: "Back", value: "back" }], onChange: (v) => updateConfig(
|
|
1982
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb, onChange: (v) => updateConfig(
|
|
1983
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Gallery", checked: config.allowGallery !== false, onChange: (v) => updateConfig(
|
|
2240
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Camera", value: config.camera ?? "any", options: [{ label: "Any", value: "any" }, { label: "Front", value: "front" }, { label: "Back", value: "back" }], onChange: (v) => updateConfig({ camera: v }) }),
|
|
2241
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb, onChange: (v) => updateConfig({ maxSizeMb: v }) }),
|
|
2242
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Gallery", checked: config.allowGallery !== false, onChange: (v) => updateConfig({ allowGallery: v }) })
|
|
1984
2243
|
] });
|
|
1985
2244
|
// ── Content & Visual ──
|
|
1986
2245
|
case "welcome-screen":
|
|
1987
2246
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Welcome Screen", children: [
|
|
1988
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Welcome", onChange: (v) => updateConfig(
|
|
1989
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description, onChange: (v) => updateConfig(
|
|
1990
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Button Text", value: config.buttonText ?? "Start", onChange: (v) => updateConfig(
|
|
1991
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
1992
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Alignment", value: config.alignment ?? "center", options: [{ label: "Left", value: "left" }, { label: "Center", value: "center" }, { label: "Right", value: "right" }], onChange: (v) => updateConfig(
|
|
2247
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Welcome", onChange: (v) => updateConfig({ heading: v }) }),
|
|
2248
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description, onChange: (v) => updateConfig({ description: v }) }),
|
|
2249
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Button Text", value: config.buttonText ?? "Start", onChange: (v) => updateConfig({ buttonText: v }) }),
|
|
2250
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig({ imageUrl: v }) }),
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Alignment", value: config.alignment ?? "center", options: [{ label: "Left", value: "left" }, { label: "Center", value: "center" }, { label: "Right", value: "right" }], onChange: (v) => updateConfig({ alignment: v }) })
|
|
1993
2252
|
] });
|
|
1994
2253
|
case "thank-you-screen":
|
|
1995
2254
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Thank You Screen", children: [
|
|
1996
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Thank You!", onChange: (v) => updateConfig(
|
|
1997
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description ?? "", onChange: (v) => updateConfig(
|
|
1998
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
1999
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Redirect URL", value: config.redirectUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2000
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Redirect Delay (s)", value: config.redirectDelay, placeholder: "0", onChange: (v) => updateConfig(
|
|
2001
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Response Summary", checked: !!config.showSummary, onChange: (v) => updateConfig(
|
|
2255
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Thank You!", onChange: (v) => updateConfig({ heading: v }) }),
|
|
2256
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description ?? "", onChange: (v) => updateConfig({ description: v }) }),
|
|
2257
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig({ imageUrl: v }) }),
|
|
2258
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Redirect URL", value: config.redirectUrl, placeholder: "https://...", onChange: (v) => updateConfig({ redirectUrl: v }) }),
|
|
2259
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Redirect Delay (s)", value: config.redirectDelay, placeholder: "0", onChange: (v) => updateConfig({ redirectDelay: v }) }),
|
|
2260
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Response Summary", checked: !!config.showSummary, onChange: (v) => updateConfig({ showSummary: v }) })
|
|
2002
2261
|
] });
|
|
2003
2262
|
case "rich-text":
|
|
2004
2263
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rich Text", children: [
|
|
2005
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 6, onChange: (v) => updateConfig(
|
|
2006
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "html", options: [{ label: "HTML", value: "html" }, { label: "Markdown", value: "markdown" }], onChange: (v) => updateConfig(
|
|
2264
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 6, onChange: (v) => updateConfig({ content: v }) }),
|
|
2265
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "html", options: [{ label: "HTML", value: "html" }, { label: "Markdown", value: "markdown" }], onChange: (v) => updateConfig({ format: v }) })
|
|
2007
2266
|
] });
|
|
2008
2267
|
case "image":
|
|
2009
2268
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Image Settings", children: [
|
|
2010
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2011
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Alt Text", value: config.alt ?? "", onChange: (v) => updateConfig(
|
|
2012
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Caption", value: config.caption, onChange: (v) => updateConfig(
|
|
2013
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Alignment", value: config.alignment ?? "center", options: [{ label: "Left", value: "left" }, { label: "Center", value: "center" }, { label: "Right", value: "right" }], onChange: (v) => updateConfig(
|
|
2014
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 300px", onChange: (v) => updateConfig(
|
|
2015
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Link URL", value: config.link, placeholder: "Click opens this URL", onChange: (v) => updateConfig(
|
|
2269
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "https://...", onChange: (v) => updateConfig({ src: v }) }),
|
|
2270
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Alt Text", value: config.alt ?? "", onChange: (v) => updateConfig({ alt: v }) }),
|
|
2271
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Caption", value: config.caption, onChange: (v) => updateConfig({ caption: v }) }),
|
|
2272
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Alignment", value: config.alignment ?? "center", options: [{ label: "Left", value: "left" }, { label: "Center", value: "center" }, { label: "Right", value: "right" }], onChange: (v) => updateConfig({ alignment: v }) }),
|
|
2273
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 300px", onChange: (v) => updateConfig({ width: v }) }),
|
|
2274
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Link URL", value: config.link, placeholder: "Click opens this URL", onChange: (v) => updateConfig({ link: v }) })
|
|
2016
2275
|
] });
|
|
2017
2276
|
case "video":
|
|
2018
2277
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Video Settings", children: [
|
|
2019
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "YouTube/Vimeo URL", onChange: (v) => updateConfig(
|
|
2020
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "youtube", options: [{ label: "YouTube", value: "youtube" }, { label: "Vimeo", value: "vimeo" }, { label: "Direct URL", value: "url" }], onChange: (v) => updateConfig(
|
|
2021
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Autoplay", checked: !!config.autoplay, onChange: (v) => updateConfig(
|
|
2022
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Muted", checked: !!config.muted, onChange: (v) => updateConfig(
|
|
2023
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 640px", onChange: (v) => updateConfig(
|
|
2024
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Height", value: config.height, placeholder: "e.g. 360px", onChange: (v) => updateConfig(
|
|
2278
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "YouTube/Vimeo URL", onChange: (v) => updateConfig({ src: v }) }),
|
|
2279
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "youtube", options: [{ label: "YouTube", value: "youtube" }, { label: "Vimeo", value: "vimeo" }, { label: "Direct URL", value: "url" }], onChange: (v) => updateConfig({ provider: v }) }),
|
|
2280
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Autoplay", checked: !!config.autoplay, onChange: (v) => updateConfig({ autoplay: v }) }),
|
|
2281
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Muted", checked: !!config.muted, onChange: (v) => updateConfig({ muted: v }) }),
|
|
2282
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 640px", onChange: (v) => updateConfig({ width: v }) }),
|
|
2283
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Height", value: config.height, placeholder: "e.g. 360px", onChange: (v) => updateConfig({ height: v }) })
|
|
2025
2284
|
] });
|
|
2026
2285
|
case "divider":
|
|
2027
2286
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Divider Settings", children: [
|
|
2028
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Style", value: config.style ?? "solid", options: [{ label: "Solid", value: "solid" }, { label: "Dashed", value: "dashed" }, { label: "Dotted", value: "dotted" }], onChange: (v) => updateConfig(
|
|
2029
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Color", value: config.color, placeholder: "#e5e7eb", onChange: (v) => updateConfig(
|
|
2030
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Thickness (px)", value: config.thickness, placeholder: "1", onChange: (v) => updateConfig(
|
|
2031
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Spacing (px)", value: config.spacing, placeholder: "16", onChange: (v) => updateConfig(
|
|
2287
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Style", value: config.style ?? "solid", options: [{ label: "Solid", value: "solid" }, { label: "Dashed", value: "dashed" }, { label: "Dotted", value: "dotted" }], onChange: (v) => updateConfig({ style: v }) }),
|
|
2288
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Color", value: config.color, placeholder: "#e5e7eb", onChange: (v) => updateConfig({ color: v }) }),
|
|
2289
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Thickness (px)", value: config.thickness, placeholder: "1", onChange: (v) => updateConfig({ thickness: v }) }),
|
|
2290
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Spacing (px)", value: config.spacing, placeholder: "16", onChange: (v) => updateConfig({ spacing: v }) })
|
|
2032
2291
|
] });
|
|
2033
2292
|
case "spacer":
|
|
2034
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Spacer Settings", children: /* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Height (px)", value: config.height ?? 32, onChange: (v) => updateConfig(
|
|
2293
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Spacer Settings", children: /* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Height (px)", value: config.height ?? 32, onChange: (v) => updateConfig({ height: v }) }) });
|
|
2035
2294
|
// ── Structural ──
|
|
2036
2295
|
case "section_header":
|
|
2037
2296
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Header Settings", children: [
|
|
2038
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Level", value: config.level ?? "h3", options: [{ label: "H2", value: "h2" }, { label: "H3", value: "h3" }, { label: "H4", value: "h4" }], onChange: (v) => updateConfig(
|
|
2039
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Divider", checked: !!config.showDivider, onChange: (v) => updateConfig(
|
|
2297
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Level", value: config.level ?? "h3", options: [{ label: "H2", value: "h2" }, { label: "H3", value: "h3" }, { label: "H4", value: "h4" }], onChange: (v) => updateConfig({ level: v }) }),
|
|
2298
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Divider", checked: !!config.showDivider, onChange: (v) => updateConfig({ showDivider: v }) })
|
|
2040
2299
|
] });
|
|
2041
2300
|
case "info_block":
|
|
2042
2301
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Info Block", children: [
|
|
2043
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 4, onChange: (v) => updateConfig(
|
|
2044
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Variant", value: config.variant ?? "info", options: [{ label: "Info", value: "info" }, { label: "Warning", value: "warning" }, { label: "Success", value: "success" }, { label: "Error", value: "error" }], onChange: (v) => updateConfig(
|
|
2302
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 4, onChange: (v) => updateConfig({ content: v }) }),
|
|
2303
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Variant", value: config.variant ?? "info", options: [{ label: "Info", value: "info" }, { label: "Warning", value: "warning" }, { label: "Success", value: "success" }, { label: "Error", value: "error" }], onChange: (v) => updateConfig({ variant: v }) })
|
|
2045
2304
|
] });
|
|
2046
2305
|
case "page_break":
|
|
2047
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Page Break", children: /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Label", value: config.label, placeholder: "Next page label", onChange: (v) => updateConfig(
|
|
2306
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Page Break", children: /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Label", value: config.label, placeholder: "Next page label", onChange: (v) => updateConfig({ label: v }) }) });
|
|
2048
2307
|
case "consent":
|
|
2049
2308
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Consent Settings", children: [
|
|
2050
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Consent Text", value: config.text ?? "", rows: 4, onChange: (v) => updateConfig(
|
|
2051
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Checkbox Label", value: config.checkboxLabel ?? "I agree", onChange: (v) => updateConfig(
|
|
2052
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Expandable Text", value: config.expandableText, rows: 3, placeholder: "Additional text shown on expand", onChange: (v) => updateConfig(
|
|
2309
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Consent Text", value: config.text ?? "", rows: 4, onChange: (v) => updateConfig({ text: v }) }),
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Checkbox Label", value: config.checkboxLabel ?? "I agree", onChange: (v) => updateConfig({ checkboxLabel: v }) }),
|
|
2311
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Expandable Text", value: config.expandableText, rows: 3, placeholder: "Additional text shown on expand", onChange: (v) => updateConfig({ expandableText: v }) })
|
|
2053
2312
|
] });
|
|
2054
2313
|
// ── Advanced ──
|
|
2055
2314
|
case "matrix":
|
|
2056
2315
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Matrix Settings", children: [
|
|
2057
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Input Type", value: config.inputType ?? "radio", options: [{ label: "Radio", value: "radio" }, { label: "Checkbox", value: "checkbox" }, { label: "Text", value: "text" }, { label: "Number", value: "number" }], onChange: (v) => updateConfig(
|
|
2058
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Required", value: config.required ?? "none", options: [{ label: "All rows", value: "all" }, { label: "Any row", value: "any" }, { label: "None", value: "none" }], onChange: (v) => updateConfig(
|
|
2059
|
-
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Rows", items: config.rows ?? [], onChange: (v) => updateConfig(
|
|
2060
|
-
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Columns", items: config.columns ?? [], onChange: (v) => updateConfig(
|
|
2316
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Input Type", value: config.inputType ?? "radio", options: [{ label: "Radio", value: "radio" }, { label: "Checkbox", value: "checkbox" }, { label: "Text", value: "text" }, { label: "Number", value: "number" }], onChange: (v) => updateConfig({ inputType: v }) }),
|
|
2317
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Required", value: config.required ?? "none", options: [{ label: "All rows", value: "all" }, { label: "Any row", value: "any" }, { label: "None", value: "none" }], onChange: (v) => updateConfig({ required: v }) }),
|
|
2318
|
+
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Rows", items: config.rows ?? [], onChange: (v) => updateConfig({ rows: v }) }),
|
|
2319
|
+
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Columns", items: config.columns ?? [], onChange: (v) => updateConfig({ columns: v }) })
|
|
2061
2320
|
] });
|
|
2062
2321
|
case "repeater":
|
|
2063
2322
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Repeater Settings", children: [
|
|
2064
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Entries", value: config.minEntries, placeholder: "1", onChange: (v) => updateConfig(
|
|
2065
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Entries", value: config.maxEntries, onChange: (v) => updateConfig(
|
|
2066
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Default Entries", value: config.defaultEntries, placeholder: "1", onChange: (v) => updateConfig(
|
|
2067
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Add Button Label", value: config.addLabel, placeholder: "Add Entry", onChange: (v) => updateConfig(
|
|
2068
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Remove Button Label", value: config.removeLabel, placeholder: "Remove", onChange: (v) => updateConfig(
|
|
2323
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Entries", value: config.minEntries, placeholder: "1", onChange: (v) => updateConfig({ minEntries: v }) }),
|
|
2324
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Entries", value: config.maxEntries, onChange: (v) => updateConfig({ maxEntries: v }) }),
|
|
2325
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Default Entries", value: config.defaultEntries, placeholder: "1", onChange: (v) => updateConfig({ defaultEntries: v }) }),
|
|
2326
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Add Button Label", value: config.addLabel, placeholder: "Add Entry", onChange: (v) => updateConfig({ addLabel: v }) }),
|
|
2327
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Remove Button Label", value: config.removeLabel, placeholder: "Remove", onChange: (v) => updateConfig({ removeLabel: v }) }),
|
|
2069
2328
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 text-[11px] text-muted-foreground leading-relaxed", children: "Sub-fields for each repeater entry are configured by nesting questions inside the repeater in the schema JSON." })
|
|
2070
2329
|
] });
|
|
2071
2330
|
case "address": {
|
|
@@ -2079,63 +2338,157 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2079
2338
|
];
|
|
2080
2339
|
const activeFields = config.fields ?? ["street", "city", "state", "zip", "country"];
|
|
2081
2340
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Address Settings", children: [
|
|
2082
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "none", options: [{ label: "None", value: "none" }, { label: "Google", value: "google" }, { label: "Mapbox", value: "mapbox" }], onChange: (v) => updateConfig(
|
|
2083
|
-
config.provider !== "none" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "API Key", value: config.apiKey, placeholder: "Provider API key", onChange: (v) => updateConfig(
|
|
2084
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry, placeholder: "e.g. US", onChange: (v) => updateConfig(
|
|
2341
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "none", options: [{ label: "None", value: "none" }, { label: "Google", value: "google" }, { label: "Mapbox", value: "mapbox" }], onChange: (v) => updateConfig({ provider: v }) }),
|
|
2342
|
+
config.provider !== "none" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "API Key", value: config.apiKey, placeholder: "Provider API key", onChange: (v) => updateConfig({ apiKey: v }) }),
|
|
2343
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry, placeholder: "e.g. US", onChange: (v) => updateConfig({ defaultCountry: v }) }),
|
|
2085
2344
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2086
2345
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-2 block", children: "Fields" }),
|
|
2087
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) =>
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2346
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) => {
|
|
2347
|
+
const isChecked = activeFields.includes(f.value);
|
|
2348
|
+
const isLastChecked = isChecked && activeFields.length === 1;
|
|
2349
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2350
|
+
ToggleField,
|
|
2351
|
+
{
|
|
2352
|
+
label: f.label,
|
|
2353
|
+
checked: isChecked,
|
|
2354
|
+
disabled: isLastChecked,
|
|
2355
|
+
onChange: (checked) => {
|
|
2356
|
+
const next = checked ? [...activeFields, f.value] : activeFields.filter((v) => v !== f.value);
|
|
2357
|
+
updateConfig({ fields: next });
|
|
2358
|
+
}
|
|
2359
|
+
},
|
|
2360
|
+
f.value
|
|
2361
|
+
);
|
|
2362
|
+
}) })
|
|
2099
2363
|
] })
|
|
2100
2364
|
] });
|
|
2101
2365
|
}
|
|
2102
|
-
case "payment":
|
|
2366
|
+
case "payment": {
|
|
2367
|
+
const amountFieldOptions = [
|
|
2368
|
+
{ label: "None (Fixed Amount)", value: "" },
|
|
2369
|
+
...candidateAmountFields,
|
|
2370
|
+
{ label: "Custom Field ID...", value: "__custom__" }
|
|
2371
|
+
];
|
|
2372
|
+
const isCustomAmountField = Boolean(config.amountField) && !candidateAmountFields.some((opt) => opt.value === config.amountField);
|
|
2103
2373
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Payment Settings", children: [
|
|
2104
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2374
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2375
|
+
SelectField,
|
|
2376
|
+
{
|
|
2377
|
+
label: "Provider",
|
|
2378
|
+
value: config.provider ?? "stripe",
|
|
2379
|
+
options: [
|
|
2380
|
+
{ label: "Stripe", value: "stripe" },
|
|
2381
|
+
{ label: "PayPal", value: "paypal" },
|
|
2382
|
+
{ label: "Razorpay", value: "razorpay" }
|
|
2383
|
+
],
|
|
2384
|
+
onChange: (v) => updateConfig({ provider: v })
|
|
2385
|
+
}
|
|
2386
|
+
),
|
|
2387
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2388
|
+
TextField,
|
|
2389
|
+
{
|
|
2390
|
+
label: "Public Key",
|
|
2391
|
+
value: config.publicKey,
|
|
2392
|
+
placeholder: "pk_test_...",
|
|
2393
|
+
onChange: (v) => updateConfig({ publicKey: v || void 0 })
|
|
2394
|
+
}
|
|
2395
|
+
),
|
|
2396
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2397
|
+
TextField,
|
|
2398
|
+
{
|
|
2399
|
+
label: "Server URL",
|
|
2400
|
+
value: config.serverUrl,
|
|
2401
|
+
placeholder: "https://api.example.com/create-intent",
|
|
2402
|
+
onChange: (v) => updateConfig({ serverUrl: v || void 0 })
|
|
2403
|
+
}
|
|
2404
|
+
),
|
|
2405
|
+
candidateAmountFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2406
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2407
|
+
SelectField,
|
|
2408
|
+
{
|
|
2409
|
+
label: "Dynamic Amount Field",
|
|
2410
|
+
value: isCustomAmountField ? "__custom__" : config.amountField ?? "",
|
|
2411
|
+
options: amountFieldOptions,
|
|
2412
|
+
onChange: (v) => {
|
|
2413
|
+
if (v !== "__custom__") {
|
|
2414
|
+
updateConfig({ amountField: v || void 0 });
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
),
|
|
2419
|
+
isCustomAmountField && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2420
|
+
TextField,
|
|
2421
|
+
{
|
|
2422
|
+
label: "Custom Field ID",
|
|
2423
|
+
value: config.amountField,
|
|
2424
|
+
placeholder: "Field ID for dynamic amount",
|
|
2425
|
+
onChange: (v) => updateConfig({ amountField: v || void 0 })
|
|
2426
|
+
}
|
|
2427
|
+
) })
|
|
2428
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2429
|
+
TextField,
|
|
2430
|
+
{
|
|
2431
|
+
label: "Amount Field",
|
|
2432
|
+
value: config.amountField,
|
|
2433
|
+
placeholder: "Field ID for dynamic amount (e.g. total_cost)",
|
|
2434
|
+
onChange: (v) => updateConfig({ amountField: v || void 0 })
|
|
2435
|
+
}
|
|
2436
|
+
),
|
|
2437
|
+
!config.amountField && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2438
|
+
NumberField,
|
|
2439
|
+
{
|
|
2440
|
+
label: "Fixed Amount",
|
|
2441
|
+
value: config.amount,
|
|
2442
|
+
onChange: (v) => updateConfig({ amount: v })
|
|
2443
|
+
}
|
|
2444
|
+
),
|
|
2445
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Currency", value: config.currency ?? "USD", placeholder: "USD", onChange: (v) => updateConfig({ currency: v || "USD" }) }),
|
|
2446
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Description", value: config.description, onChange: (v) => updateConfig({ description: v }) }),
|
|
2447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2448
|
+
TextField,
|
|
2449
|
+
{
|
|
2450
|
+
label: "Client Secret Response Path",
|
|
2451
|
+
value: typeof config.responseMapping?.clientSecretPath === "string" ? config.responseMapping.clientSecretPath : config.responseMapping ?? "",
|
|
2452
|
+
placeholder: "clientSecret",
|
|
2453
|
+
onChange: (v) => updateConfig({
|
|
2454
|
+
responseMapping: v ? { clientSecretPath: v } : void 0
|
|
2455
|
+
})
|
|
2456
|
+
}
|
|
2457
|
+
)
|
|
2110
2458
|
] });
|
|
2459
|
+
}
|
|
2111
2460
|
case "calculated":
|
|
2112
2461
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Calculated Field", children: [
|
|
2113
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Expression", value: config.expression ?? "", placeholder: "e.g. {q1} + {q2}", onChange: (v) => updateConfig(
|
|
2114
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "number", options: [{ label: "Number", value: "number" }, { label: "Currency", value: "currency" }, { label: "Percentage", value: "percentage" }], onChange: (v) => updateConfig(
|
|
2115
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "2", onChange: (v) => updateConfig(
|
|
2116
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, onChange: (v) => updateConfig(
|
|
2117
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, onChange: (v) => updateConfig(
|
|
2118
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Visible to User", checked: config.visible !== false, onChange: (v) => updateConfig(
|
|
2462
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Expression", value: config.expression ?? "", placeholder: "e.g. {q1} + {q2}", onChange: (v) => updateConfig({ expression: v }) }),
|
|
2463
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "number", options: [{ label: "Number", value: "number" }, { label: "Currency", value: "currency" }, { label: "Percentage", value: "percentage" }], onChange: (v) => updateConfig({ format: v }) }),
|
|
2464
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "2", onChange: (v) => updateConfig({ decimalPlaces: v }) }),
|
|
2465
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, onChange: (v) => updateConfig({ prefix: v }) }),
|
|
2466
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, onChange: (v) => updateConfig({ suffix: v }) }),
|
|
2467
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Visible to User", checked: config.visible !== false, onChange: (v) => updateConfig({ visible: v }) })
|
|
2119
2468
|
] });
|
|
2120
2469
|
case "hidden":
|
|
2121
2470
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Hidden Field", children: [
|
|
2122
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Source", value: config.source ?? "static", options: [{ label: "Static Value", value: "static" }, { label: "URL Parameter", value: "url_param" }, { label: "Cookie", value: "cookie" }, { label: "Referrer", value: "referrer" }], onChange: (v) => updateConfig(
|
|
2123
|
-
config.source === "static" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Value", value: config.defaultValue, onChange: (v) => updateConfig(
|
|
2124
|
-
config.source === "url_param" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Parameter Name", value: config.paramName, placeholder: "e.g. utm_source", onChange: (v) => updateConfig(
|
|
2125
|
-
config.source === "cookie" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Cookie Name", value: config.cookieName, onChange: (v) => updateConfig(
|
|
2471
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Source", value: config.source ?? "static", options: [{ label: "Static Value", value: "static" }, { label: "URL Parameter", value: "url_param" }, { label: "Cookie", value: "cookie" }, { label: "Referrer", value: "referrer" }], onChange: (v) => updateConfig({ source: v }) }),
|
|
2472
|
+
config.source === "static" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Value", value: config.defaultValue, onChange: (v) => updateConfig({ defaultValue: v }) }),
|
|
2473
|
+
config.source === "url_param" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Parameter Name", value: config.paramName, placeholder: "e.g. utm_source", onChange: (v) => updateConfig({ paramName: v }) }),
|
|
2474
|
+
config.source === "cookie" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Cookie Name", value: config.cookieName, onChange: (v) => updateConfig({ cookieName: v }) })
|
|
2126
2475
|
] });
|
|
2127
2476
|
case "scoring":
|
|
2128
2477
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Scoring Settings", children: [
|
|
2129
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Score", checked: !!config.showScore, onChange: (v) => updateConfig(
|
|
2130
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScoringOptionsEditor, { options: config.options ?? [], onChange: (v) => updateConfig(
|
|
2131
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScoreRangesEditor, { ranges: config.scoreRanges ?? [], onChange: (v) => updateConfig(
|
|
2478
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Score", checked: !!config.showScore, onChange: (v) => updateConfig({ showScore: v }) }),
|
|
2479
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScoringOptionsEditor, { options: config.options ?? [], onChange: (v) => updateConfig({ options: v }) }),
|
|
2480
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScoreRangesEditor, { ranges: config.scoreRanges ?? [], onChange: (v) => updateConfig({ scoreRanges: v }) })
|
|
2132
2481
|
] });
|
|
2133
2482
|
case "ranking":
|
|
2134
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Ranking Settings", children: /* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Items", items: config.items ?? [], onChange: (v) => updateConfig(
|
|
2483
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Ranking Settings", children: /* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Items", items: config.items ?? [], onChange: (v) => updateConfig({ items: v }) }) });
|
|
2484
|
+
case "phone_international":
|
|
2485
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "International Phone Settings", children: [
|
|
2486
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry ?? "US", placeholder: "e.g. US", onChange: (v) => updateConfig({ defaultCountry: v }) }),
|
|
2487
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Priority Countries", value: config.priorityCountries?.join(", "), placeholder: "e.g. US, GB, CA", onChange: (v) => updateConfig({ priorityCountries: v ? v.split(",").map((s) => s.trim()).filter(Boolean) : void 0 }) })
|
|
2488
|
+
] });
|
|
2135
2489
|
// Types with no additional config
|
|
2136
2490
|
case "email":
|
|
2137
2491
|
case "phone":
|
|
2138
|
-
case "phone_international":
|
|
2139
2492
|
case "url":
|
|
2140
2493
|
return null;
|
|
2141
2494
|
default:
|
|
@@ -2212,11 +2565,12 @@ function NumberField({
|
|
|
2212
2565
|
function ToggleField({
|
|
2213
2566
|
label,
|
|
2214
2567
|
checked,
|
|
2215
|
-
onChange
|
|
2568
|
+
onChange,
|
|
2569
|
+
disabled
|
|
2216
2570
|
}) {
|
|
2217
2571
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2218
2572
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: label }),
|
|
2219
|
-
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Switch, { checked, onCheckedChange: onChange })
|
|
2573
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Switch, { checked, onCheckedChange: onChange, disabled })
|
|
2220
2574
|
] });
|
|
2221
2575
|
}
|
|
2222
2576
|
function SelectField({
|
|
@@ -2227,7 +2581,10 @@ function SelectField({
|
|
|
2227
2581
|
}) {
|
|
2228
2582
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2229
2583
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
2230
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2584
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Select, { value, onValueChange: onChange, children: [
|
|
2585
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: options.find((o) => o.value === value)?.label ?? value }) }),
|
|
2586
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)) })
|
|
2587
|
+
] })
|
|
2231
2588
|
] });
|
|
2232
2589
|
}
|
|
2233
2590
|
function LikertLabelsEditor({
|
|
@@ -2373,6 +2730,59 @@ function ScoringOptionsEditor({
|
|
|
2373
2730
|
] }, index)) })
|
|
2374
2731
|
] });
|
|
2375
2732
|
}
|
|
2733
|
+
function AppointmentSlotsEditor({
|
|
2734
|
+
slots,
|
|
2735
|
+
onChange
|
|
2736
|
+
}) {
|
|
2737
|
+
const handleDateChange = (index, date) => {
|
|
2738
|
+
const updated = slots.map((s, i) => i === index ? { ...s, date } : s);
|
|
2739
|
+
onChange(updated);
|
|
2740
|
+
};
|
|
2741
|
+
const handleTimesChange = (index, timesStr) => {
|
|
2742
|
+
const times = timesStr.split(",").map((t) => t.trim()).filter(Boolean);
|
|
2743
|
+
const updated = slots.map((s, i) => i === index ? { ...s, times } : s);
|
|
2744
|
+
onChange(updated);
|
|
2745
|
+
};
|
|
2746
|
+
const handleAdd = () => {
|
|
2747
|
+
const tomorrow = /* @__PURE__ */ new Date();
|
|
2748
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
2749
|
+
const dateStr = tomorrow.toISOString().split("T")[0];
|
|
2750
|
+
onChange([...slots, { date: dateStr, times: ["09:00", "10:00", "11:00", "14:00", "15:00"] }]);
|
|
2751
|
+
};
|
|
2752
|
+
const handleRemove = (index) => {
|
|
2753
|
+
onChange(slots.filter((_, i) => i !== index));
|
|
2754
|
+
};
|
|
2755
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2756
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
2757
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Slots" }),
|
|
2758
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add Date" })
|
|
2759
|
+
] }),
|
|
2760
|
+
slots.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: "No slots configured. Add a date to get started." }),
|
|
2761
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: slots.map((slot, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 rounded-md border border-border space-y-1.5 group", children: [
|
|
2762
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2763
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2764
|
+
fieldcraftReact.Input,
|
|
2765
|
+
{
|
|
2766
|
+
type: "date",
|
|
2767
|
+
value: slot.date,
|
|
2768
|
+
onChange: (e) => handleDateChange(index, e.target.value),
|
|
2769
|
+
className: "h-7 text-xs flex-1"
|
|
2770
|
+
}
|
|
2771
|
+
),
|
|
2772
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "ghost", size: "icon-xs", onClick: () => handleRemove(index), className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity", children: "x" })
|
|
2773
|
+
] }),
|
|
2774
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2775
|
+
fieldcraftReact.Input,
|
|
2776
|
+
{
|
|
2777
|
+
value: slot.times.join(", "),
|
|
2778
|
+
onChange: (e) => handleTimesChange(index, e.target.value),
|
|
2779
|
+
className: "h-7 text-xs",
|
|
2780
|
+
placeholder: "09:00, 10:00, 14:00, 15:00"
|
|
2781
|
+
}
|
|
2782
|
+
)
|
|
2783
|
+
] }, index)) })
|
|
2784
|
+
] });
|
|
2785
|
+
}
|
|
2376
2786
|
function ScoreRangesEditor({
|
|
2377
2787
|
ranges,
|
|
2378
2788
|
onChange
|
|
@@ -2405,6 +2815,26 @@ function ScoreRangesEditor({
|
|
|
2405
2815
|
] }, index)) })
|
|
2406
2816
|
] });
|
|
2407
2817
|
}
|
|
2818
|
+
var NativeSelect = React.forwardRef(
|
|
2819
|
+
({ className, wrapperClassName, children, ...props }, ref) => {
|
|
2820
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", wrapperClassName), children: [
|
|
2821
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2822
|
+
"select",
|
|
2823
|
+
{
|
|
2824
|
+
ref,
|
|
2825
|
+
className: cn(
|
|
2826
|
+
"flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
2827
|
+
className
|
|
2828
|
+
),
|
|
2829
|
+
...props,
|
|
2830
|
+
children
|
|
2831
|
+
}
|
|
2832
|
+
),
|
|
2833
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" })
|
|
2834
|
+
] });
|
|
2835
|
+
}
|
|
2836
|
+
);
|
|
2837
|
+
NativeSelect.displayName = "NativeSelect";
|
|
2408
2838
|
var RULE_TYPES = [
|
|
2409
2839
|
{ value: "minLength", label: "Min Length", description: "Minimum character count" },
|
|
2410
2840
|
{ value: "maxLength", label: "Max Length", description: "Maximum character count" },
|
|
@@ -2809,7 +3239,7 @@ function FormSettingsPanel({ schema, onUpdate }) {
|
|
|
2809
3239
|
];
|
|
2810
3240
|
const displayMode = settings.displayMode ?? "stepped";
|
|
2811
3241
|
const effectiveDisplayMode = hasConditions && displayMode === "classic" ? "stepped" : displayMode;
|
|
2812
|
-
|
|
3242
|
+
React.useEffect(() => {
|
|
2813
3243
|
if (effectiveDisplayMode !== displayMode) {
|
|
2814
3244
|
onUpdate({ ...schema, settings: { ...settings, displayMode: effectiveDisplayMode } });
|
|
2815
3245
|
}
|
|
@@ -2966,7 +3396,7 @@ function SettingsSelect({
|
|
|
2966
3396
|
}
|
|
2967
3397
|
function PropertiesPanel({ builderState }) {
|
|
2968
3398
|
const { schema, selectedItem } = builderState;
|
|
2969
|
-
const [showSettings, setShowSettings] =
|
|
3399
|
+
const [showSettings, setShowSettings] = React.useState(false);
|
|
2970
3400
|
if (showSettings) {
|
|
2971
3401
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-80 h-full border-l border-border bg-card flex flex-col", children: [
|
|
2972
3402
|
/* @__PURE__ */ jsxRuntime.jsx(PanelHeader, { title: "Form Settings", onClose: () => setShowSettings(false) }),
|
|
@@ -3041,11 +3471,11 @@ function SectionProperties({ section, onUpdate, onClose, onOpenSettings }) {
|
|
|
3041
3471
|
] });
|
|
3042
3472
|
}
|
|
3043
3473
|
function QuestionProperties({ question, sectionId, builderState, onClose, onOpenSettings }) {
|
|
3044
|
-
const [activeTab, setActiveTab] =
|
|
3474
|
+
const [activeTab, setActiveTab] = React.useState("basic");
|
|
3045
3475
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
3046
3476
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
3047
3477
|
const hasOptions = typeInfo?.requiresOptions || question.options && question.options.length > 0;
|
|
3048
|
-
const updateQuestion2 =
|
|
3478
|
+
const updateQuestion2 = React.useCallback(
|
|
3049
3479
|
(updates) => {
|
|
3050
3480
|
builderState.updateQuestion(sectionId, question.id, updates);
|
|
3051
3481
|
},
|
|
@@ -3112,7 +3542,14 @@ function QuestionProperties({ question, sectionId, builderState, onClose, onOpen
|
|
|
3112
3542
|
}
|
|
3113
3543
|
)
|
|
3114
3544
|
] }),
|
|
3115
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3546
|
+
QuestionConfigEditor,
|
|
3547
|
+
{
|
|
3548
|
+
question,
|
|
3549
|
+
schema: builderState.schema,
|
|
3550
|
+
onUpdate: updateQuestion2
|
|
3551
|
+
}
|
|
3552
|
+
),
|
|
3116
3553
|
hasOptions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3117
3554
|
OptionsEditor,
|
|
3118
3555
|
{
|
|
@@ -3220,7 +3657,7 @@ function FieldGroup({ label, children }) {
|
|
|
3220
3657
|
children
|
|
3221
3658
|
] });
|
|
3222
3659
|
}
|
|
3223
|
-
var PreviewErrorBoundary = class extends
|
|
3660
|
+
var PreviewErrorBoundary = class extends React.Component {
|
|
3224
3661
|
state = { error: null };
|
|
3225
3662
|
static getDerivedStateFromError(error) {
|
|
3226
3663
|
return { error };
|
|
@@ -3281,15 +3718,20 @@ function errorsToMarkers(errors) {
|
|
|
3281
3718
|
source: "FieldCraft Schema Validator"
|
|
3282
3719
|
}));
|
|
3283
3720
|
}
|
|
3284
|
-
var Editor =
|
|
3721
|
+
var Editor = React.lazy(() => import('@monaco-editor/react').then((m) => ({ default: m.default })));
|
|
3285
3722
|
function MonacoWrapper({ value, onChange, errors }) {
|
|
3286
|
-
const editorRef =
|
|
3287
|
-
const monacoRef =
|
|
3723
|
+
const editorRef = React.useRef(null);
|
|
3724
|
+
const monacoRef = React.useRef(null);
|
|
3288
3725
|
const handleMount = (editor, monaco) => {
|
|
3289
3726
|
editorRef.current = editor;
|
|
3290
3727
|
monacoRef.current = monaco;
|
|
3291
3728
|
};
|
|
3292
|
-
|
|
3729
|
+
React.useEffect(() => {
|
|
3730
|
+
return () => {
|
|
3731
|
+
editorRef.current?.dispose();
|
|
3732
|
+
};
|
|
3733
|
+
}, []);
|
|
3734
|
+
React.useEffect(() => {
|
|
3293
3735
|
const editor = editorRef.current;
|
|
3294
3736
|
const monaco = monacoRef.current;
|
|
3295
3737
|
if (!editor || !monaco) return;
|
|
@@ -3321,14 +3763,14 @@ function MonacoWrapper({ value, onChange, errors }) {
|
|
|
3321
3763
|
);
|
|
3322
3764
|
}
|
|
3323
3765
|
function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
3324
|
-
const handleChange =
|
|
3766
|
+
const handleChange = React.useCallback(
|
|
3325
3767
|
(newValue) => {
|
|
3326
3768
|
onChange(newValue);
|
|
3327
3769
|
onValidate(newValue);
|
|
3328
3770
|
},
|
|
3329
3771
|
[onChange, onValidate]
|
|
3330
3772
|
);
|
|
3331
|
-
const handleFormat =
|
|
3773
|
+
const handleFormat = React.useCallback(() => {
|
|
3332
3774
|
try {
|
|
3333
3775
|
const formatted = JSON.stringify(JSON.parse(value), null, 2);
|
|
3334
3776
|
onChange(formatted);
|
|
@@ -3361,7 +3803,7 @@ function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
|
3361
3803
|
)
|
|
3362
3804
|
] }),
|
|
3363
3805
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3364
|
-
|
|
3806
|
+
React.Suspense,
|
|
3365
3807
|
{
|
|
3366
3808
|
fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-sm text-muted-foreground", children: "Loading editor..." }),
|
|
3367
3809
|
children: /* @__PURE__ */ jsxRuntime.jsx(MonacoWrapper, { value, onChange: handleChange, errors })
|
|
@@ -3560,7 +4002,7 @@ function SectionNodeInner({ data }) {
|
|
|
3560
4002
|
const d = data;
|
|
3561
4003
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
3562
4004
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group", style: { borderColor: color }, children: [
|
|
3563
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4005
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle fc-flow-handle--section" }),
|
|
3564
4006
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group__header", style: { background: color }, children: [
|
|
3565
4007
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__label", children: d.label.length > 30 ? d.label.slice(0, 30) + "\u2026" : d.label }),
|
|
3566
4008
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "fc-flow-section-group__meta", children: [
|
|
@@ -3571,10 +4013,10 @@ function SectionNodeInner({ data }) {
|
|
|
3571
4013
|
d.hasExitLogic && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__badge fc-flow-section-group__badge--jump", title: "Has onExit jump", children: "\u2934" })
|
|
3572
4014
|
] })
|
|
3573
4015
|
] }),
|
|
3574
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4016
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle fc-flow-handle--section" })
|
|
3575
4017
|
] });
|
|
3576
4018
|
}
|
|
3577
|
-
var SectionNode =
|
|
4019
|
+
var SectionNode = React.memo(SectionNodeInner);
|
|
3578
4020
|
function FieldNodeInner({ data }) {
|
|
3579
4021
|
const d = data;
|
|
3580
4022
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
@@ -3587,18 +4029,18 @@ function FieldNodeInner({ data }) {
|
|
|
3587
4029
|
borderWidth: d.hasCondition ? 2 : 1
|
|
3588
4030
|
},
|
|
3589
4031
|
children: [
|
|
3590
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4032
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle" }),
|
|
3591
4033
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-field__content", children: [
|
|
3592
4034
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__label", children: d.label.length > 26 ? d.label.slice(0, 26) + "\u2026" : d.label }),
|
|
3593
4035
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__type", children: d.fieldType })
|
|
3594
4036
|
] }),
|
|
3595
4037
|
d.hasCondition && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fc-flow-badge", style: { background: color }, title: "Has showIf condition", children: "?" }),
|
|
3596
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4038
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle" })
|
|
3597
4039
|
]
|
|
3598
4040
|
}
|
|
3599
4041
|
);
|
|
3600
4042
|
}
|
|
3601
|
-
var FieldNode =
|
|
4043
|
+
var FieldNode = React.memo(FieldNodeInner);
|
|
3602
4044
|
var logicFlowNodeTypes = {
|
|
3603
4045
|
sectionNode: SectionNode,
|
|
3604
4046
|
fieldNode: FieldNode
|
|
@@ -3616,7 +4058,7 @@ function ConditionEdgeInner({
|
|
|
3616
4058
|
data,
|
|
3617
4059
|
markerEnd
|
|
3618
4060
|
}) {
|
|
3619
|
-
const [edgePath, labelX, labelY] = react
|
|
4061
|
+
const [edgePath, labelX, labelY] = react.getBezierPath({
|
|
3620
4062
|
sourceX,
|
|
3621
4063
|
sourceY,
|
|
3622
4064
|
sourcePosition,
|
|
@@ -3627,7 +4069,7 @@ function ConditionEdgeInner({
|
|
|
3627
4069
|
const isJump = data?.edgeType === "onExit";
|
|
3628
4070
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3629
4071
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3630
|
-
react
|
|
4072
|
+
react.BaseEdge,
|
|
3631
4073
|
{
|
|
3632
4074
|
id,
|
|
3633
4075
|
path: edgePath,
|
|
@@ -3640,7 +4082,7 @@ function ConditionEdgeInner({
|
|
|
3640
4082
|
}
|
|
3641
4083
|
}
|
|
3642
4084
|
),
|
|
3643
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(react
|
|
4085
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(react.EdgeLabelRenderer, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3644
4086
|
"div",
|
|
3645
4087
|
{
|
|
3646
4088
|
className: "fc-flow-edge-label",
|
|
@@ -3653,7 +4095,7 @@ function ConditionEdgeInner({
|
|
|
3653
4095
|
) })
|
|
3654
4096
|
] });
|
|
3655
4097
|
}
|
|
3656
|
-
var ConditionEdge =
|
|
4098
|
+
var ConditionEdge = React.memo(ConditionEdgeInner);
|
|
3657
4099
|
function PipelineEdgeInner({
|
|
3658
4100
|
id,
|
|
3659
4101
|
sourceX,
|
|
@@ -3664,7 +4106,7 @@ function PipelineEdgeInner({
|
|
|
3664
4106
|
targetPosition,
|
|
3665
4107
|
markerEnd
|
|
3666
4108
|
}) {
|
|
3667
|
-
const [edgePath] = react
|
|
4109
|
+
const [edgePath] = react.getBezierPath({
|
|
3668
4110
|
sourceX,
|
|
3669
4111
|
sourceY,
|
|
3670
4112
|
sourcePosition,
|
|
@@ -3673,7 +4115,7 @@ function PipelineEdgeInner({
|
|
|
3673
4115
|
targetPosition
|
|
3674
4116
|
});
|
|
3675
4117
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3676
|
-
react
|
|
4118
|
+
react.BaseEdge,
|
|
3677
4119
|
{
|
|
3678
4120
|
id,
|
|
3679
4121
|
path: edgePath,
|
|
@@ -3686,7 +4128,7 @@ function PipelineEdgeInner({
|
|
|
3686
4128
|
}
|
|
3687
4129
|
);
|
|
3688
4130
|
}
|
|
3689
|
-
var PipelineEdge =
|
|
4131
|
+
var PipelineEdge = React.memo(PipelineEdgeInner);
|
|
3690
4132
|
var logicFlowEdgeTypes = {
|
|
3691
4133
|
conditionEdge: ConditionEdge,
|
|
3692
4134
|
pipelineEdge: PipelineEdge
|
|
@@ -3724,30 +4166,30 @@ function removeConditionForSource(showIf, sourceFieldId) {
|
|
|
3724
4166
|
}
|
|
3725
4167
|
var defaultEdgeOptions = {
|
|
3726
4168
|
markerEnd: {
|
|
3727
|
-
type: react
|
|
4169
|
+
type: react.MarkerType.ArrowClosed,
|
|
3728
4170
|
width: 16,
|
|
3729
4171
|
height: 12
|
|
3730
4172
|
}
|
|
3731
4173
|
};
|
|
3732
4174
|
function LogicFlowEditor({ schema, onChange }) {
|
|
3733
4175
|
const noSections = schema.sections.length === 0;
|
|
3734
|
-
const flowGraph =
|
|
3735
|
-
const [nodes, setNodes, onNodesChange] = react
|
|
3736
|
-
const [edges, setEdges, onEdgesChange] = react
|
|
3737
|
-
const [selectedFieldId, setSelectedFieldId] =
|
|
4176
|
+
const flowGraph = React.useMemo(() => buildReactFlowGraph(schema), [schema]);
|
|
4177
|
+
const [nodes, setNodes, onNodesChange] = react.useNodesState(flowGraph.nodes);
|
|
4178
|
+
const [edges, setEdges, onEdgesChange] = react.useEdgesState(flowGraph.edges);
|
|
4179
|
+
const [selectedFieldId, setSelectedFieldId] = React.useState(null);
|
|
3738
4180
|
const selectedQuestion = selectedFieldId ? findQuestion2(schema, selectedFieldId) : void 0;
|
|
3739
|
-
|
|
4181
|
+
React.useEffect(() => {
|
|
3740
4182
|
setNodes(flowGraph.nodes);
|
|
3741
4183
|
setEdges(flowGraph.edges);
|
|
3742
4184
|
}, [flowGraph, setNodes, setEdges]);
|
|
3743
|
-
const sectionIds =
|
|
4185
|
+
const sectionIds = React.useMemo(() => {
|
|
3744
4186
|
const ids = [];
|
|
3745
4187
|
for (const section of schema.sections) {
|
|
3746
4188
|
ids.push(section.id);
|
|
3747
4189
|
}
|
|
3748
4190
|
return ids;
|
|
3749
4191
|
}, [schema]);
|
|
3750
|
-
const onNodeClick =
|
|
4192
|
+
const onNodeClick = React.useCallback(
|
|
3751
4193
|
(_event, node) => {
|
|
3752
4194
|
if (node.type === "fieldNode") {
|
|
3753
4195
|
setSelectedFieldId(node.id);
|
|
@@ -3755,7 +4197,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3755
4197
|
},
|
|
3756
4198
|
[]
|
|
3757
4199
|
);
|
|
3758
|
-
const onConnect =
|
|
4200
|
+
const onConnect = React.useCallback(
|
|
3759
4201
|
(connection) => {
|
|
3760
4202
|
if (!connection.source || !connection.target) return;
|
|
3761
4203
|
const targetQuestion = findQuestion2(schema, connection.target);
|
|
@@ -3782,7 +4224,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3782
4224
|
},
|
|
3783
4225
|
[schema, onChange]
|
|
3784
4226
|
);
|
|
3785
|
-
const onEdgesDelete =
|
|
4227
|
+
const onEdgesDelete = React.useCallback(
|
|
3786
4228
|
(deletedEdges) => {
|
|
3787
4229
|
let updatedSchema = schema;
|
|
3788
4230
|
for (const edge of deletedEdges) {
|
|
@@ -3807,7 +4249,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3807
4249
|
},
|
|
3808
4250
|
[schema, onChange]
|
|
3809
4251
|
);
|
|
3810
|
-
const handleConditionUpdate =
|
|
4252
|
+
const handleConditionUpdate = React.useCallback(
|
|
3811
4253
|
(updates) => {
|
|
3812
4254
|
if (!selectedFieldId) return;
|
|
3813
4255
|
const updatedSchema = updateQuestionInSchema(schema, selectedFieldId, updates);
|
|
@@ -3821,18 +4263,18 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3821
4263
|
const jumpCount = flowGraph.edges.filter(
|
|
3822
4264
|
(e) => e.data?.edgeType === "onExit"
|
|
3823
4265
|
).length;
|
|
3824
|
-
const totalFields =
|
|
4266
|
+
const totalFields = React.useMemo(
|
|
3825
4267
|
() => schema.sections.reduce((sum, s) => sum + s.questions.length, 0),
|
|
3826
4268
|
[schema]
|
|
3827
4269
|
);
|
|
3828
|
-
const conditionalFields =
|
|
4270
|
+
const conditionalFields = React.useMemo(
|
|
3829
4271
|
() => schema.sections.reduce(
|
|
3830
4272
|
(sum, s) => sum + s.questions.filter((q) => !!q.showIf).length,
|
|
3831
4273
|
0
|
|
3832
4274
|
),
|
|
3833
4275
|
[schema]
|
|
3834
4276
|
);
|
|
3835
|
-
return /* @__PURE__ */ jsxRuntime.jsx(react
|
|
4277
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3836
4278
|
LogicFlowInner,
|
|
3837
4279
|
{
|
|
3838
4280
|
noSections,
|
|
@@ -3876,7 +4318,7 @@ function LogicFlowInner({
|
|
|
3876
4318
|
totalFields,
|
|
3877
4319
|
conditionalFields
|
|
3878
4320
|
}) {
|
|
3879
|
-
const { zoomIn, zoomOut, fitView } = react
|
|
4321
|
+
const { zoomIn, zoomOut, fitView } = react.useReactFlow();
|
|
3880
4322
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: [
|
|
3881
4323
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 h-9 flex items-center justify-between px-4 border-b border-border bg-card/50", children: [
|
|
3882
4324
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
@@ -3904,7 +4346,7 @@ function LogicFlowInner({
|
|
|
3904
4346
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs max-w-xs mx-auto", children: "Switch to Design mode and add sections with fields. Then come back here to visualize and edit branching logic." })
|
|
3905
4347
|
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
3906
4348
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3907
|
-
react
|
|
4349
|
+
react.ReactFlow,
|
|
3908
4350
|
{
|
|
3909
4351
|
nodes,
|
|
3910
4352
|
edges,
|
|
@@ -3921,9 +4363,9 @@ function LogicFlowInner({
|
|
|
3921
4363
|
deleteKeyCode: ["Backspace", "Delete"],
|
|
3922
4364
|
proOptions: { hideAttribution: true },
|
|
3923
4365
|
children: [
|
|
3924
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4366
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Background, { gap: 20, size: 1 }),
|
|
3925
4367
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3926
|
-
react
|
|
4368
|
+
react.MiniMap,
|
|
3927
4369
|
{
|
|
3928
4370
|
nodeColor: (node) => {
|
|
3929
4371
|
const d = node.data;
|
|
@@ -3987,15 +4429,15 @@ function LogicFlowInner({
|
|
|
3987
4429
|
] });
|
|
3988
4430
|
}
|
|
3989
4431
|
function TemplateGallery({ templates, onSelect, onClose }) {
|
|
3990
|
-
const [search, setSearch] =
|
|
3991
|
-
const [activeCategory, setActiveCategory] =
|
|
3992
|
-
const [confirmTemplate, setConfirmTemplate] =
|
|
3993
|
-
const categories =
|
|
4432
|
+
const [search, setSearch] = React.useState("");
|
|
4433
|
+
const [activeCategory, setActiveCategory] = React.useState("all");
|
|
4434
|
+
const [confirmTemplate, setConfirmTemplate] = React.useState(null);
|
|
4435
|
+
const categories = React.useMemo(() => {
|
|
3994
4436
|
const cats = /* @__PURE__ */ new Set();
|
|
3995
4437
|
for (const t of templates) cats.add(t.meta.category);
|
|
3996
4438
|
return ["all", ...Array.from(cats)];
|
|
3997
4439
|
}, [templates]);
|
|
3998
|
-
const filtered =
|
|
4440
|
+
const filtered = React.useMemo(() => {
|
|
3999
4441
|
return templates.filter((t) => {
|
|
4000
4442
|
const matchesCategory = activeCategory === "all" || t.meta.category === activeCategory;
|
|
4001
4443
|
const matchesSearch = !search || t.meta.name.toLowerCase().includes(search.toLowerCase()) || t.meta.description.toLowerCase().includes(search.toLowerCase()) || t.meta.tags?.some((tag) => tag.toLowerCase().includes(search.toLowerCase()));
|
|
@@ -4091,9 +4533,14 @@ function TemplateGallery({ templates, onSelect, onClose }) {
|
|
|
4091
4533
|
] }) });
|
|
4092
4534
|
}
|
|
4093
4535
|
function useDebouncedValidation(delayMs = 500) {
|
|
4094
|
-
const [errors, setErrors] =
|
|
4095
|
-
const timerRef =
|
|
4096
|
-
|
|
4536
|
+
const [errors, setErrors] = React.useState([]);
|
|
4537
|
+
const timerRef = React.useRef(null);
|
|
4538
|
+
React.useEffect(() => {
|
|
4539
|
+
return () => {
|
|
4540
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
4541
|
+
};
|
|
4542
|
+
}, []);
|
|
4543
|
+
const validate = React.useCallback(
|
|
4097
4544
|
(text) => {
|
|
4098
4545
|
if (timerRef.current) {
|
|
4099
4546
|
clearTimeout(timerRef.current);
|
|
@@ -4142,9 +4589,9 @@ function useDebouncedValidation(delayMs = 500) {
|
|
|
4142
4589
|
);
|
|
4143
4590
|
return { errors, validate };
|
|
4144
4591
|
}
|
|
4145
|
-
var ThemeCtx =
|
|
4592
|
+
var ThemeCtx = React.createContext({});
|
|
4146
4593
|
function useBuilderTheme() {
|
|
4147
|
-
return
|
|
4594
|
+
return React.useContext(ThemeCtx);
|
|
4148
4595
|
}
|
|
4149
4596
|
function themeToCssVars(theme) {
|
|
4150
4597
|
const vars = {};
|
|
@@ -4180,10 +4627,10 @@ function themeToCssVars(theme) {
|
|
|
4180
4627
|
}
|
|
4181
4628
|
function FormBuilderThemeProvider({ theme, children }) {
|
|
4182
4629
|
const resolved = theme ?? {};
|
|
4183
|
-
const cssVars =
|
|
4630
|
+
const cssVars = React.useMemo(() => themeToCssVars(resolved), [resolved]);
|
|
4184
4631
|
return /* @__PURE__ */ jsxRuntime.jsx(ThemeCtx.Provider, { value: resolved, children: /* @__PURE__ */ jsxRuntime.jsx("div", { "data-fcb-root": "", style: cssVars, className: "w-full h-full", children }) });
|
|
4185
4632
|
}
|
|
4186
|
-
var FormBuilderErrorBoundary = class extends
|
|
4633
|
+
var FormBuilderErrorBoundary = class extends React.Component {
|
|
4187
4634
|
constructor(props) {
|
|
4188
4635
|
super(props);
|
|
4189
4636
|
this.state = { hasError: false, error: null };
|
|
@@ -4215,30 +4662,30 @@ var FormBuilderErrorBoundary = class extends react.Component {
|
|
|
4215
4662
|
};
|
|
4216
4663
|
function FormBuilderCore(props) {
|
|
4217
4664
|
const { initialSchema = DEFAULT_SCHEMA, onChange, onSave, height = "100vh", theme, className, toolbarExtra, questionTypes, palette, preview, templates, schemaUrl } = props;
|
|
4218
|
-
const [viewMode, setViewMode] =
|
|
4219
|
-
const [jsonText, setJsonText] =
|
|
4220
|
-
const [jsonSwitchError, setJsonSwitchError] =
|
|
4221
|
-
const [showTemplateGallery, setShowTemplateGallery] =
|
|
4222
|
-
const [saveValidationErrors, setSaveValidationErrors] =
|
|
4223
|
-
const [schemaUrlLoading, setSchemaUrlLoading] =
|
|
4224
|
-
const [schemaUrlError, setSchemaUrlError] =
|
|
4665
|
+
const [viewMode, setViewMode] = React.useState("design");
|
|
4666
|
+
const [jsonText, setJsonText] = React.useState("");
|
|
4667
|
+
const [jsonSwitchError, setJsonSwitchError] = React.useState(null);
|
|
4668
|
+
const [showTemplateGallery, setShowTemplateGallery] = React.useState(false);
|
|
4669
|
+
const [saveValidationErrors, setSaveValidationErrors] = React.useState(null);
|
|
4670
|
+
const [schemaUrlLoading, setSchemaUrlLoading] = React.useState(!!schemaUrl);
|
|
4671
|
+
const [schemaUrlError, setSchemaUrlError] = React.useState(null);
|
|
4225
4672
|
const { errors: jsonErrors, validate: validateJson } = useDebouncedValidation(400);
|
|
4226
4673
|
const mergedQuestionTypes = questionTypes ? { ...QUESTION_TYPE_INFO, ...questionTypes } : QUESTION_TYPE_INFO;
|
|
4227
4674
|
const builderState = useBuilderState(initialSchema);
|
|
4228
4675
|
const dragDrop = useDragDrop(builderState);
|
|
4229
|
-
const fileInputRef =
|
|
4230
|
-
const [mobilePanel, setMobilePanel] =
|
|
4231
|
-
|
|
4676
|
+
const fileInputRef = React.useRef(null);
|
|
4677
|
+
const [mobilePanel, setMobilePanel] = React.useState("none");
|
|
4678
|
+
React.useEffect(() => {
|
|
4232
4679
|
if (builderState.selectedItem && window.innerWidth < 768) {
|
|
4233
4680
|
setMobilePanel("properties");
|
|
4234
4681
|
}
|
|
4235
4682
|
}, [builderState.selectedItem]);
|
|
4236
|
-
|
|
4683
|
+
React.useEffect(() => {
|
|
4237
4684
|
if (!dragDrop.activeDragItem && mobilePanel === "palette") {
|
|
4238
4685
|
setMobilePanel("none");
|
|
4239
4686
|
}
|
|
4240
4687
|
}, [dragDrop.activeDragItem]);
|
|
4241
|
-
|
|
4688
|
+
React.useEffect(() => {
|
|
4242
4689
|
if (!schemaUrl) return;
|
|
4243
4690
|
let cancelled = false;
|
|
4244
4691
|
setSchemaUrlLoading(true);
|
|
@@ -4268,12 +4715,12 @@ function FormBuilderCore(props) {
|
|
|
4268
4715
|
cancelled = true;
|
|
4269
4716
|
};
|
|
4270
4717
|
}, [schemaUrl]);
|
|
4271
|
-
|
|
4718
|
+
React.useEffect(() => {
|
|
4272
4719
|
if (onChange && builderState.isDirty) {
|
|
4273
4720
|
onChange(builderState.schema);
|
|
4274
4721
|
}
|
|
4275
4722
|
}, [builderState.schema, builderState.isDirty, onChange]);
|
|
4276
|
-
const handleSave =
|
|
4723
|
+
const handleSave = React.useCallback(() => {
|
|
4277
4724
|
if (!onSave) return;
|
|
4278
4725
|
try {
|
|
4279
4726
|
fieldcraftCore.validateSchema(builderState.schema);
|
|
@@ -4288,7 +4735,7 @@ function FormBuilderCore(props) {
|
|
|
4288
4735
|
}
|
|
4289
4736
|
}
|
|
4290
4737
|
}, [onSave, builderState]);
|
|
4291
|
-
const handleExport =
|
|
4738
|
+
const handleExport = React.useCallback(() => {
|
|
4292
4739
|
const json = JSON.stringify(builderState.schema, null, 2);
|
|
4293
4740
|
const blob = new Blob([json], { type: "application/json" });
|
|
4294
4741
|
const url = URL.createObjectURL(blob);
|
|
@@ -4298,10 +4745,10 @@ function FormBuilderCore(props) {
|
|
|
4298
4745
|
a.click();
|
|
4299
4746
|
URL.revokeObjectURL(url);
|
|
4300
4747
|
}, [builderState.schema]);
|
|
4301
|
-
const handleImport =
|
|
4748
|
+
const handleImport = React.useCallback(() => {
|
|
4302
4749
|
fileInputRef.current?.click();
|
|
4303
4750
|
}, []);
|
|
4304
|
-
const handleFileChange =
|
|
4751
|
+
const handleFileChange = React.useCallback(
|
|
4305
4752
|
(e) => {
|
|
4306
4753
|
const file = e.target.files?.[0];
|
|
4307
4754
|
if (!file) return;
|
|
@@ -4328,7 +4775,7 @@ ${details}`);
|
|
|
4328
4775
|
},
|
|
4329
4776
|
[builderState]
|
|
4330
4777
|
);
|
|
4331
|
-
const handleViewModeChange =
|
|
4778
|
+
const handleViewModeChange = React.useCallback(
|
|
4332
4779
|
(newMode) => {
|
|
4333
4780
|
setJsonSwitchError(null);
|
|
4334
4781
|
if (viewMode === "json" && newMode !== "json") {
|
|
@@ -4354,7 +4801,7 @@ ${details}`);
|
|
|
4354
4801
|
},
|
|
4355
4802
|
[viewMode, jsonText, builderState]
|
|
4356
4803
|
);
|
|
4357
|
-
const handleKeyDown =
|
|
4804
|
+
const handleKeyDown = React.useCallback(
|
|
4358
4805
|
(e) => {
|
|
4359
4806
|
const mod = e.metaKey || e.ctrlKey;
|
|
4360
4807
|
const tag = e.target.tagName;
|
|
@@ -4843,6 +5290,58 @@ function FormBuilderInner(props) {
|
|
|
4843
5290
|
// src/form-builder/components/FormBuilderGated.tsx
|
|
4844
5291
|
var FormBuilder = requireLicense(FormBuilderInner, "FormBuilder");
|
|
4845
5292
|
|
|
5293
|
+
// src/form-builder/theme/presets.ts
|
|
5294
|
+
var squaredrDarkPreset = {
|
|
5295
|
+
background: "#0F1A1F",
|
|
5296
|
+
foreground: "#E8EFF1",
|
|
5297
|
+
card: "#16242A",
|
|
5298
|
+
primary: "#63BDB4",
|
|
5299
|
+
primaryForeground: "#0F1A1F",
|
|
5300
|
+
secondary: "#182F31",
|
|
5301
|
+
secondaryForeground: "#E8EFF1",
|
|
5302
|
+
muted: "#182F31",
|
|
5303
|
+
mutedForeground: "#8CA1A9",
|
|
5304
|
+
accent: "#182F31",
|
|
5305
|
+
accentForeground: "#E8EFF1",
|
|
5306
|
+
destructive: "#E08072",
|
|
5307
|
+
destructiveForeground: "#0F1A1F",
|
|
5308
|
+
border: "#2A3B42",
|
|
5309
|
+
input: "#2A3B42",
|
|
5310
|
+
ring: "#63BDB4",
|
|
5311
|
+
radius: "0px",
|
|
5312
|
+
surface: "#16242A",
|
|
5313
|
+
surfaceHover: "#182F31",
|
|
5314
|
+
canvas: "#0F1A1F",
|
|
5315
|
+
panel: "#16242A",
|
|
5316
|
+
borderStrong: "#2F4F4C",
|
|
5317
|
+
textDim: "#5E7680"
|
|
5318
|
+
};
|
|
5319
|
+
var cleanPreset = {
|
|
5320
|
+
background: "#F4F7F8",
|
|
5321
|
+
foreground: "#12222A",
|
|
5322
|
+
card: "#FFFFFF",
|
|
5323
|
+
primary: "#1F6B6E",
|
|
5324
|
+
primaryForeground: "#FFFFFF",
|
|
5325
|
+
secondary: "#EDF3F2",
|
|
5326
|
+
secondaryForeground: "#12222A",
|
|
5327
|
+
muted: "#EDF3F2",
|
|
5328
|
+
mutedForeground: "#6A7B85",
|
|
5329
|
+
accent: "#EDF3F2",
|
|
5330
|
+
accentForeground: "#12222A",
|
|
5331
|
+
destructive: "#B04A3C",
|
|
5332
|
+
destructiveForeground: "#FFFFFF",
|
|
5333
|
+
border: "#DCE4E8",
|
|
5334
|
+
input: "#DCE4E8",
|
|
5335
|
+
ring: "#1F6B6E",
|
|
5336
|
+
radius: "0px",
|
|
5337
|
+
surface: "#FAFCFC",
|
|
5338
|
+
surfaceHover: "#EDF3F2",
|
|
5339
|
+
canvas: "#F4F7F8",
|
|
5340
|
+
panel: "#FFFFFF",
|
|
5341
|
+
borderStrong: "#B9D1CF",
|
|
5342
|
+
textDim: "#6A7B85"
|
|
5343
|
+
};
|
|
5344
|
+
|
|
4846
5345
|
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|
|
4847
5346
|
exports.DEFAULT_SCHEMA = DEFAULT_SCHEMA;
|
|
4848
5347
|
exports.FormBuilder = FormBuilder;
|
|
@@ -4851,6 +5350,7 @@ exports.QUESTION_TYPE_INFO = QUESTION_TYPE_INFO;
|
|
|
4851
5350
|
exports.addOption = addOption;
|
|
4852
5351
|
exports.addQuestion = addQuestion;
|
|
4853
5352
|
exports.addSection = addSection;
|
|
5353
|
+
exports.cleanPreset = cleanPreset;
|
|
4854
5354
|
exports.cn = cn;
|
|
4855
5355
|
exports.duplicateQuestion = duplicateQuestion;
|
|
4856
5356
|
exports.duplicateSection = duplicateSection;
|
|
@@ -4866,6 +5366,7 @@ exports.moveSection = moveSection;
|
|
|
4866
5366
|
exports.removeOption = removeOption;
|
|
4867
5367
|
exports.removeQuestion = removeQuestion;
|
|
4868
5368
|
exports.removeSection = removeSection;
|
|
5369
|
+
exports.squaredrDarkPreset = squaredrDarkPreset;
|
|
4869
5370
|
exports.updateOption = updateOption;
|
|
4870
5371
|
exports.updateQuestion = updateQuestion;
|
|
4871
5372
|
exports.updateSection = updateSection;
|