@squaredr/fieldcraft-pro 1.7.0 → 1.8.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-4TN6YJDF.mjs → chunk-CYXJGOQH.mjs} +903 -205
- package/dist/{chunk-J5V6OVZO.mjs → chunk-GXKQCXIB.mjs} +344 -174
- package/dist/{chunk-VEP3DOCQ.mjs → chunk-IW654Z3M.mjs} +13 -16
- package/dist/{chunk-GZIV2XAD.mjs → chunk-MLP5EDWP.mjs} +166 -177
- package/dist/form-builder/index.d.mts +1 -1
- package/dist/form-builder/index.d.ts +1 -1
- package/dist/form-builder/index.js +480 -290
- package/dist/form-builder/index.mjs +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1967 -893
- package/dist/index.mjs +326 -121
- package/dist/response-viewer/index.d.mts +1 -1
- package/dist/response-viewer/index.d.ts +1 -1
- package/dist/response-viewer/index.js +165 -177
- package/dist/response-viewer/index.mjs +1 -1
- package/dist/styles.css +1 -1
- package/dist/templates/index.js +13 -16
- package/dist/templates/index.mjs +1 -1
- package/dist/theme-editor/index.d.mts +11 -5
- package/dist/theme-editor/index.d.ts +11 -5
- package/dist/theme-editor/index.js +903 -205
- package/dist/theme-editor/index.mjs +1 -1
- package/package.json +18 -7
- package/theme-editor/styles.css +468 -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,41 @@ 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);
|
|
339
|
+
const currentIndexRef = React.useRef(currentIndex);
|
|
340
|
+
currentIndexRef.current = currentIndex;
|
|
317
341
|
const canUndo = currentIndex > 0;
|
|
318
342
|
const canRedo = currentIndex < historyRef.current.length - 1;
|
|
319
|
-
const push =
|
|
343
|
+
const push = React.useCallback(
|
|
320
344
|
(schema) => {
|
|
321
|
-
|
|
345
|
+
const idx = currentIndexRef.current;
|
|
346
|
+
historyRef.current = historyRef.current.slice(0, idx + 1);
|
|
322
347
|
historyRef.current.push(schema);
|
|
323
348
|
if (historyRef.current.length > MAX_HISTORY) {
|
|
324
349
|
historyRef.current.shift();
|
|
325
350
|
setCurrentIndex(historyRef.current.length - 1);
|
|
326
351
|
} else {
|
|
327
|
-
setCurrentIndex(
|
|
352
|
+
setCurrentIndex(idx + 1);
|
|
328
353
|
}
|
|
329
354
|
},
|
|
330
|
-
[
|
|
355
|
+
[]
|
|
331
356
|
);
|
|
332
|
-
const undo =
|
|
357
|
+
const undo = React.useCallback(() => {
|
|
333
358
|
if (currentIndex > 0) {
|
|
334
359
|
const newIndex = currentIndex - 1;
|
|
335
360
|
setCurrentIndex(newIndex);
|
|
336
361
|
setSchema(historyRef.current[newIndex]);
|
|
337
362
|
}
|
|
338
363
|
}, [currentIndex, setSchema]);
|
|
339
|
-
const redo =
|
|
364
|
+
const redo = React.useCallback(() => {
|
|
340
365
|
if (currentIndex < historyRef.current.length - 1) {
|
|
341
366
|
const newIndex = currentIndex + 1;
|
|
342
367
|
setCurrentIndex(newIndex);
|
|
343
368
|
setSchema(historyRef.current[newIndex]);
|
|
344
369
|
}
|
|
345
370
|
}, [currentIndex, setSchema]);
|
|
346
|
-
const clear =
|
|
371
|
+
const clear = React.useCallback(() => {
|
|
347
372
|
historyRef.current = [currentSchema];
|
|
348
373
|
setCurrentIndex(0);
|
|
349
374
|
}, [currentSchema]);
|
|
@@ -572,16 +597,16 @@ function findSection(schema, sectionId) {
|
|
|
572
597
|
|
|
573
598
|
// src/form-builder/hooks/use-builder-state.ts
|
|
574
599
|
function useBuilderState(initialSchema) {
|
|
575
|
-
const [schema, setSchema] =
|
|
576
|
-
const [selectedItem, setSelectedItem] =
|
|
577
|
-
const [isDirty, setIsDirty] =
|
|
578
|
-
const schemaRef =
|
|
600
|
+
const [schema, setSchema] = React.useState(initialSchema);
|
|
601
|
+
const [selectedItem, setSelectedItem] = React.useState(null);
|
|
602
|
+
const [isDirty, setIsDirty] = React.useState(false);
|
|
603
|
+
const schemaRef = React.useRef(schema);
|
|
579
604
|
schemaRef.current = schema;
|
|
580
605
|
const undoRedo = useUndoRedo(schema, (newSchema) => {
|
|
581
606
|
setSchema(newSchema);
|
|
582
607
|
setIsDirty(true);
|
|
583
608
|
});
|
|
584
|
-
const updateSchema =
|
|
609
|
+
const updateSchema = React.useCallback(
|
|
585
610
|
(newSchema) => {
|
|
586
611
|
setSchema(newSchema);
|
|
587
612
|
undoRedo.push(newSchema);
|
|
@@ -589,20 +614,20 @@ function useBuilderState(initialSchema) {
|
|
|
589
614
|
},
|
|
590
615
|
[undoRedo]
|
|
591
616
|
);
|
|
592
|
-
const applyMutation =
|
|
617
|
+
const applyMutation = React.useCallback(
|
|
593
618
|
(mutate) => {
|
|
594
619
|
const result = mutate(schemaRef.current);
|
|
595
620
|
updateSchema(result);
|
|
596
621
|
},
|
|
597
622
|
[updateSchema]
|
|
598
623
|
);
|
|
599
|
-
const addSection2 =
|
|
624
|
+
const addSection2 = React.useCallback(
|
|
600
625
|
(section, index) => {
|
|
601
626
|
applyMutation((s) => addSection(s, section, index));
|
|
602
627
|
},
|
|
603
628
|
[applyMutation]
|
|
604
629
|
);
|
|
605
|
-
const removeSection2 =
|
|
630
|
+
const removeSection2 = React.useCallback(
|
|
606
631
|
(sectionId) => {
|
|
607
632
|
applyMutation((s) => removeSection(s, sectionId));
|
|
608
633
|
setSelectedItem((prev) => {
|
|
@@ -612,31 +637,31 @@ function useBuilderState(initialSchema) {
|
|
|
612
637
|
},
|
|
613
638
|
[applyMutation]
|
|
614
639
|
);
|
|
615
|
-
const updateSection2 =
|
|
640
|
+
const updateSection2 = React.useCallback(
|
|
616
641
|
(sectionId, updates) => {
|
|
617
642
|
applyMutation((s) => updateSection(s, sectionId, updates));
|
|
618
643
|
},
|
|
619
644
|
[applyMutation]
|
|
620
645
|
);
|
|
621
|
-
const moveSection2 =
|
|
646
|
+
const moveSection2 = React.useCallback(
|
|
622
647
|
(sectionId, newIndex) => {
|
|
623
648
|
applyMutation((s) => moveSection(s, sectionId, newIndex));
|
|
624
649
|
},
|
|
625
650
|
[applyMutation]
|
|
626
651
|
);
|
|
627
|
-
const duplicateSection2 =
|
|
652
|
+
const duplicateSection2 = React.useCallback(
|
|
628
653
|
(sectionId) => {
|
|
629
654
|
applyMutation((s) => duplicateSection(s, sectionId));
|
|
630
655
|
},
|
|
631
656
|
[applyMutation]
|
|
632
657
|
);
|
|
633
|
-
const addQuestion2 =
|
|
658
|
+
const addQuestion2 = React.useCallback(
|
|
634
659
|
(sectionId, question, index) => {
|
|
635
660
|
applyMutation((s) => addQuestion(s, sectionId, question, index));
|
|
636
661
|
},
|
|
637
662
|
[applyMutation]
|
|
638
663
|
);
|
|
639
|
-
const removeQuestion2 =
|
|
664
|
+
const removeQuestion2 = React.useCallback(
|
|
640
665
|
(sectionId, questionId) => {
|
|
641
666
|
applyMutation((s) => removeQuestion(s, sectionId, questionId));
|
|
642
667
|
setSelectedItem((prev) => {
|
|
@@ -648,34 +673,34 @@ function useBuilderState(initialSchema) {
|
|
|
648
673
|
},
|
|
649
674
|
[applyMutation]
|
|
650
675
|
);
|
|
651
|
-
const updateQuestion2 =
|
|
676
|
+
const updateQuestion2 = React.useCallback(
|
|
652
677
|
(sectionId, questionId, updates) => {
|
|
653
678
|
applyMutation((s) => updateQuestion(s, sectionId, questionId, updates));
|
|
654
679
|
},
|
|
655
680
|
[applyMutation]
|
|
656
681
|
);
|
|
657
|
-
const moveQuestion2 =
|
|
682
|
+
const moveQuestion2 = React.useCallback(
|
|
658
683
|
(sectionId, questionId, targetSectionId, newIndex) => {
|
|
659
684
|
applyMutation((s) => moveQuestion(s, sectionId, questionId, targetSectionId, newIndex));
|
|
660
685
|
},
|
|
661
686
|
[applyMutation]
|
|
662
687
|
);
|
|
663
|
-
const duplicateQuestion2 =
|
|
688
|
+
const duplicateQuestion2 = React.useCallback(
|
|
664
689
|
(sectionId, questionId) => {
|
|
665
690
|
applyMutation((s) => duplicateQuestion(s, sectionId, questionId));
|
|
666
691
|
},
|
|
667
692
|
[applyMutation]
|
|
668
693
|
);
|
|
669
|
-
const selectQuestion =
|
|
694
|
+
const selectQuestion = React.useCallback((sectionId, questionId) => {
|
|
670
695
|
setSelectedItem({ type: "question", sectionId, questionId });
|
|
671
696
|
}, []);
|
|
672
|
-
const selectSection =
|
|
697
|
+
const selectSection = React.useCallback((sectionId) => {
|
|
673
698
|
setSelectedItem({ type: "section", sectionId });
|
|
674
699
|
}, []);
|
|
675
|
-
const clearSelection =
|
|
700
|
+
const clearSelection = React.useCallback(() => {
|
|
676
701
|
setSelectedItem(null);
|
|
677
702
|
}, []);
|
|
678
|
-
const resetSchema =
|
|
703
|
+
const resetSchema = React.useCallback(
|
|
679
704
|
(newSchema) => {
|
|
680
705
|
setSchema(newSchema);
|
|
681
706
|
undoRedo.clear();
|
|
@@ -684,7 +709,7 @@ function useBuilderState(initialSchema) {
|
|
|
684
709
|
},
|
|
685
710
|
[undoRedo]
|
|
686
711
|
);
|
|
687
|
-
const markClean =
|
|
712
|
+
const markClean = React.useCallback(() => {
|
|
688
713
|
setIsDirty(false);
|
|
689
714
|
}, []);
|
|
690
715
|
return {
|
|
@@ -945,7 +970,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
945
970
|
category: "advanced",
|
|
946
971
|
icon: "ListPlus",
|
|
947
972
|
description: "Repeatable group of fields",
|
|
948
|
-
defaultConfig: { type: "repeater", fields: [],
|
|
973
|
+
defaultConfig: { type: "repeater", fields: [], minEntries: 1, maxEntries: 10 }
|
|
949
974
|
},
|
|
950
975
|
likert: {
|
|
951
976
|
type: "likert",
|
|
@@ -956,13 +981,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
956
981
|
requiresOptions: true,
|
|
957
982
|
defaultConfig: {
|
|
958
983
|
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
|
-
]
|
|
984
|
+
labels: ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]
|
|
966
985
|
}
|
|
967
986
|
},
|
|
968
987
|
scoring: {
|
|
@@ -1015,7 +1034,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
1015
1034
|
category: "advanced",
|
|
1016
1035
|
icon: "CreditCard",
|
|
1017
1036
|
description: "Collect payment via Stripe",
|
|
1018
|
-
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
|
|
1037
|
+
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD", serverUrl: "" }
|
|
1019
1038
|
},
|
|
1020
1039
|
// ── Structural ──
|
|
1021
1040
|
section_header: {
|
|
@@ -1162,7 +1181,7 @@ var DEFAULT_PALETTE = [
|
|
|
1162
1181
|
|
|
1163
1182
|
// src/form-builder/hooks/use-drag-drop.ts
|
|
1164
1183
|
function useDragDrop(builderState) {
|
|
1165
|
-
const [activeDragItem, setActiveDragItem] =
|
|
1184
|
+
const [activeDragItem, setActiveDragItem] = React.useState(null);
|
|
1166
1185
|
const sensors = core.useSensors(
|
|
1167
1186
|
core.useSensor(core.MouseSensor, {
|
|
1168
1187
|
activationConstraint: {
|
|
@@ -1212,11 +1231,11 @@ function useDragDrop(builderState) {
|
|
|
1212
1231
|
}
|
|
1213
1232
|
return null;
|
|
1214
1233
|
};
|
|
1215
|
-
const handleDragStart =
|
|
1234
|
+
const handleDragStart = React.useCallback((event) => {
|
|
1216
1235
|
const item = parseDragItem(event.active);
|
|
1217
1236
|
setActiveDragItem(item);
|
|
1218
1237
|
}, []);
|
|
1219
|
-
const handleDragCancel =
|
|
1238
|
+
const handleDragCancel = React.useCallback(() => {
|
|
1220
1239
|
setActiveDragItem(null);
|
|
1221
1240
|
}, []);
|
|
1222
1241
|
const handleDragEnd = (event) => {
|
|
@@ -1386,9 +1405,9 @@ function PaletteItem({ questionType, typeInfo }) {
|
|
|
1386
1405
|
);
|
|
1387
1406
|
}
|
|
1388
1407
|
function QuestionPalette({ questionTypes, palette }) {
|
|
1389
|
-
const [collapsed, setCollapsed] =
|
|
1390
|
-
const [search, setSearch] =
|
|
1391
|
-
const mergedPalette =
|
|
1408
|
+
const [collapsed, setCollapsed] = React.useState({});
|
|
1409
|
+
const [search, setSearch] = React.useState("");
|
|
1410
|
+
const mergedPalette = React.useMemo(
|
|
1392
1411
|
() => palette ? [...DEFAULT_PALETTE, ...palette] : DEFAULT_PALETTE,
|
|
1393
1412
|
[palette]
|
|
1394
1413
|
);
|
|
@@ -1469,13 +1488,13 @@ function QuestionBlock({
|
|
|
1469
1488
|
}) {
|
|
1470
1489
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
1471
1490
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
1472
|
-
const [isEditing, setIsEditing] =
|
|
1473
|
-
const [editValue, setEditValue] =
|
|
1474
|
-
const inputRef =
|
|
1475
|
-
|
|
1491
|
+
const [isEditing, setIsEditing] = React.useState(false);
|
|
1492
|
+
const [editValue, setEditValue] = React.useState(question.label);
|
|
1493
|
+
const inputRef = React.useRef(null);
|
|
1494
|
+
React.useEffect(() => {
|
|
1476
1495
|
if (!isEditing) setEditValue(question.label);
|
|
1477
1496
|
}, [question.label, isEditing]);
|
|
1478
|
-
|
|
1497
|
+
React.useEffect(() => {
|
|
1479
1498
|
if (isEditing && inputRef.current) {
|
|
1480
1499
|
inputRef.current.focus();
|
|
1481
1500
|
inputRef.current.select();
|
|
@@ -1632,7 +1651,7 @@ function ConfirmDialog({ open, title, message, onConfirm, onCancel }) {
|
|
|
1632
1651
|
);
|
|
1633
1652
|
}
|
|
1634
1653
|
function SectionBlock({ section, builderState }) {
|
|
1635
|
-
const [confirmDelete, setConfirmDelete] =
|
|
1654
|
+
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
|
1636
1655
|
const { setNodeRef } = core.useDroppable({
|
|
1637
1656
|
id: `section-end-${section.id}`,
|
|
1638
1657
|
data: { type: "section", sectionId: section.id, index: section.questions.length }
|
|
@@ -1813,30 +1832,71 @@ function FormCanvas({ builderState }) {
|
|
|
1813
1832
|
] })
|
|
1814
1833
|
] }) });
|
|
1815
1834
|
}
|
|
1816
|
-
var
|
|
1817
|
-
|
|
1818
|
-
|
|
1835
|
+
var Select = SelectPrimitive__namespace.Root;
|
|
1836
|
+
var SelectTrigger = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1837
|
+
SelectPrimitive__namespace.Trigger,
|
|
1838
|
+
{
|
|
1839
|
+
ref,
|
|
1840
|
+
className: cn(
|
|
1841
|
+
"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",
|
|
1842
|
+
className
|
|
1843
|
+
),
|
|
1844
|
+
...props,
|
|
1845
|
+
children: [
|
|
1846
|
+
children,
|
|
1847
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Icon, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4 text-muted-foreground" }) })
|
|
1848
|
+
]
|
|
1849
|
+
}
|
|
1850
|
+
));
|
|
1851
|
+
SelectTrigger.displayName = "SelectTrigger";
|
|
1852
|
+
var SelectContent = React__namespace.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.Portal, { children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1853
|
+
SelectPrimitive__namespace.Content,
|
|
1854
|
+
{
|
|
1855
|
+
ref,
|
|
1856
|
+
className: cn(
|
|
1857
|
+
"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",
|
|
1858
|
+
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",
|
|
1859
|
+
className
|
|
1860
|
+
),
|
|
1861
|
+
position,
|
|
1862
|
+
...props,
|
|
1863
|
+
children: [
|
|
1864
|
+
/* @__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
1865
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1820
|
-
|
|
1866
|
+
SelectPrimitive__namespace.Viewport,
|
|
1821
1867
|
{
|
|
1822
|
-
ref,
|
|
1823
1868
|
className: cn(
|
|
1824
|
-
"
|
|
1825
|
-
|
|
1869
|
+
"p-1",
|
|
1870
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
1826
1871
|
),
|
|
1827
|
-
...props,
|
|
1828
1872
|
children
|
|
1829
1873
|
}
|
|
1830
1874
|
),
|
|
1831
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1832
|
-
]
|
|
1875
|
+
/* @__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" }) })
|
|
1876
|
+
]
|
|
1833
1877
|
}
|
|
1834
|
-
);
|
|
1835
|
-
|
|
1878
|
+
) }));
|
|
1879
|
+
SelectContent.displayName = "SelectContent";
|
|
1880
|
+
var SelectItem = React__namespace.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1881
|
+
SelectPrimitive__namespace.Item,
|
|
1882
|
+
{
|
|
1883
|
+
ref,
|
|
1884
|
+
className: cn(
|
|
1885
|
+
"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",
|
|
1886
|
+
className
|
|
1887
|
+
),
|
|
1888
|
+
...props,
|
|
1889
|
+
children: [
|
|
1890
|
+
/* @__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" }) }) }),
|
|
1891
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectPrimitive__namespace.ItemText, { children })
|
|
1892
|
+
]
|
|
1893
|
+
}
|
|
1894
|
+
));
|
|
1895
|
+
SelectItem.displayName = "SelectItem";
|
|
1836
1896
|
function useConfigUpdater(question, onUpdate) {
|
|
1837
|
-
return (
|
|
1897
|
+
return (updates) => {
|
|
1838
1898
|
const current = question.config ?? {};
|
|
1839
|
-
onUpdate({ config: { ...current, type: question.type,
|
|
1899
|
+
onUpdate({ config: { ...current, type: question.type, ...updates } });
|
|
1840
1900
|
};
|
|
1841
1901
|
}
|
|
1842
1902
|
function QuestionConfigEditor({ question, onUpdate }) {
|
|
@@ -1846,226 +1906,274 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
1846
1906
|
// ── Text ──
|
|
1847
1907
|
case "short_text":
|
|
1848
1908
|
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(
|
|
1909
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "255", onChange: (v) => updateConfig({ maxLength: v }) }),
|
|
1910
|
+
/* @__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 }) }),
|
|
1911
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig({ prefix: v }) }),
|
|
1912
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. USD", onChange: (v) => updateConfig({ suffix: v }) })
|
|
1853
1913
|
] });
|
|
1854
1914
|
case "long_text":
|
|
1855
1915
|
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(
|
|
1916
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "No limit", onChange: (v) => updateConfig({ maxLength: v }) }),
|
|
1917
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Rows", value: config.rows, placeholder: "4", onChange: (v) => updateConfig({ rows: v }) }),
|
|
1918
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Character Count", checked: !!config.showCharCount, onChange: (v) => updateConfig({ showCharCount: v }) })
|
|
1859
1919
|
] });
|
|
1860
1920
|
case "legal_name":
|
|
1861
1921
|
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(
|
|
1922
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Middle Name", checked: !!config.showMiddleName, onChange: (v) => updateConfig({ showMiddleName: v }) }),
|
|
1923
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Suffix", checked: !!config.showSuffix, onChange: (v) => updateConfig({ showSuffix: v }) })
|
|
1864
1924
|
] });
|
|
1865
1925
|
// ── Numeric ──
|
|
1866
1926
|
case "number":
|
|
1867
1927
|
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(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "0", onChange: (v) => updateConfig(
|
|
1872
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig(
|
|
1873
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. kg", onChange: (v) => updateConfig(
|
|
1928
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, onChange: (v) => updateConfig({ min: v }) }),
|
|
1929
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, onChange: (v) => updateConfig({ max: v }) }),
|
|
1930
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v }) }),
|
|
1931
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "0", onChange: (v) => updateConfig({ decimalPlaces: v }) }),
|
|
1932
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig({ prefix: v }) }),
|
|
1933
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. kg", onChange: (v) => updateConfig({ suffix: v }) })
|
|
1874
1934
|
] });
|
|
1875
1935
|
case "slider":
|
|
1876
1936
|
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(ToggleField, { label: "Show Value", checked: !!config.showValue, onChange: (v) => updateConfig(
|
|
1881
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig(
|
|
1882
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, onChange: (v) => updateConfig(
|
|
1937
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "0", onChange: (v) => updateConfig({ min: v }) }),
|
|
1938
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "100", onChange: (v) => updateConfig({ max: v }) }),
|
|
1939
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v }) }),
|
|
1940
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Value", checked: !!config.showValue, onChange: (v) => updateConfig({ showValue: v }) }),
|
|
1941
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig({ minLabel: v }) }),
|
|
1942
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, onChange: (v) => updateConfig({ maxLabel: v }) })
|
|
1883
1943
|
] });
|
|
1884
1944
|
case "rating":
|
|
1885
1945
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rating Settings", children: [
|
|
1886
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Stars", value: config.max, placeholder: "5", onChange: (v) => updateConfig(
|
|
1887
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "Circle", value: "circle" }], onChange: (v) => updateConfig(
|
|
1888
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Labels", checked: !!config.showLabels, onChange: (v) => updateConfig(
|
|
1946
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Stars", value: config.max, placeholder: "5", onChange: (v) => updateConfig({ max: v }) }),
|
|
1947
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "Circle", value: "circle" }], onChange: (v) => updateConfig({ icon: v }) }),
|
|
1948
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Labels", checked: !!config.showLabels, onChange: (v) => updateConfig({ showLabels: v }) })
|
|
1889
1949
|
] });
|
|
1890
1950
|
case "nps":
|
|
1891
1951
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "NPS Settings", children: [
|
|
1892
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Low Label", value: config.lowLabel ?? "Not likely", onChange: (v) => updateConfig(
|
|
1893
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "High Label", value: config.highLabel ?? "Very likely", onChange: (v) => updateConfig(
|
|
1952
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Low Label", value: config.lowLabel ?? "Not likely", onChange: (v) => updateConfig({ lowLabel: v }) }),
|
|
1953
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "High Label", value: config.highLabel ?? "Very likely", onChange: (v) => updateConfig({ highLabel: v }) })
|
|
1894
1954
|
] });
|
|
1895
1955
|
case "opinion_scale":
|
|
1896
1956
|
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(
|
|
1957
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "1", onChange: (v) => updateConfig({ min: v }) }),
|
|
1958
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "5", onChange: (v) => updateConfig({ max: v }) }),
|
|
1959
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v }) }),
|
|
1960
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig({ minLabel: v }) }),
|
|
1961
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, onChange: (v) => updateConfig({ maxLabel: v }) })
|
|
1902
1962
|
] });
|
|
1903
1963
|
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(
|
|
1964
|
+
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
1965
|
// ── Selection ──
|
|
1906
1966
|
case "single_select":
|
|
1907
1967
|
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(
|
|
1968
|
+
/* @__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 }) }),
|
|
1969
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => v ? updateConfig({ allowOther: true }) : updateConfig({ allowOther: false, otherLabel: void 0 }) }),
|
|
1970
|
+
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig({ otherLabel: v }) })
|
|
1911
1971
|
] });
|
|
1912
1972
|
case "multi_select":
|
|
1913
1973
|
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(
|
|
1974
|
+
/* @__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 }) }),
|
|
1975
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Selections", value: config.minSelections, onChange: (v) => updateConfig({ minSelections: v }) }),
|
|
1976
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Selections", value: config.maxSelections, onChange: (v) => updateConfig({ maxSelections: v }) }),
|
|
1977
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => v ? updateConfig({ allowOther: true }) : updateConfig({ allowOther: false, otherLabel: void 0 }) }),
|
|
1978
|
+
!!config.allowOther && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Other Label", value: config.otherLabel ?? "Other", onChange: (v) => updateConfig({ otherLabel: v }) })
|
|
1919
1979
|
] });
|
|
1920
1980
|
case "dropdown":
|
|
1921
1981
|
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(
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Searchable", checked: !!config.searchable, onChange: (v) => updateConfig({ searchable: v }) }),
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig({ allowOther: v }) }),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Multiple", checked: !!config.multiple, onChange: (v) => updateConfig({ multiple: v }) })
|
|
1925
1985
|
] });
|
|
1926
1986
|
case "boolean":
|
|
1927
1987
|
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(
|
|
1988
|
+
/* @__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 }) }),
|
|
1989
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "True Label", value: config.trueLabel ?? "Yes", onChange: (v) => updateConfig({ trueLabel: v }) }),
|
|
1990
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "False Label", value: config.falseLabel ?? "No", onChange: (v) => updateConfig({ falseLabel: v }) })
|
|
1931
1991
|
] });
|
|
1932
1992
|
case "country_select":
|
|
1933
1993
|
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(
|
|
1994
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Flags", checked: config.showFlags !== false, onChange: (v) => updateConfig({ showFlags: v }) }),
|
|
1995
|
+
/* @__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 }) }),
|
|
1996
|
+
/* @__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
1997
|
] });
|
|
1938
1998
|
// ── Date/Time ──
|
|
1939
1999
|
case "date":
|
|
1940
2000
|
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(
|
|
2001
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ minDate: v }) }),
|
|
2002
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ maxDate: v }) }),
|
|
2003
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Past Dates", checked: !!config.disablePast, onChange: (v) => updateConfig({ disablePast: v }) }),
|
|
2004
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Future Dates", checked: !!config.disableFuture, onChange: (v) => updateConfig({ disableFuture: v }) }),
|
|
2005
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Format", value: config.format, placeholder: "e.g. MM/DD/YYYY", onChange: (v) => updateConfig({ format: v }) })
|
|
1946
2006
|
] });
|
|
1947
2007
|
case "time":
|
|
1948
2008
|
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(
|
|
2009
|
+
/* @__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 }) }),
|
|
2010
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Minute Step", value: config.minuteStep, placeholder: "1", onChange: (v) => updateConfig({ minuteStep: v }) })
|
|
1951
2011
|
] });
|
|
1952
2012
|
case "date_range":
|
|
1953
2013
|
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(
|
|
2014
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ minDate: v }) }),
|
|
2015
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig({ maxDate: v }) }),
|
|
2016
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Range (days)", value: config.maxRangeDays, onChange: (v) => updateConfig({ maxRangeDays: v }) })
|
|
1957
2017
|
] });
|
|
1958
|
-
case "appointment":
|
|
2018
|
+
case "appointment": {
|
|
2019
|
+
const appointmentMode = typeof config.embedUrl === "string" ? "embed" : typeof config.slotsUrl === "string" ? "url" : "static";
|
|
1959
2020
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Appointment Settings", children: [
|
|
1960
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1961
|
-
|
|
1962
|
-
|
|
2021
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2022
|
+
SelectField,
|
|
2023
|
+
{
|
|
2024
|
+
label: "Mode",
|
|
2025
|
+
value: appointmentMode,
|
|
2026
|
+
options: [
|
|
2027
|
+
{ label: "Static Slots", value: "static" },
|
|
2028
|
+
{ label: "API Endpoint", value: "url" },
|
|
2029
|
+
{ label: "Embed (Calendly / Cal.com)", value: "embed" }
|
|
2030
|
+
],
|
|
2031
|
+
onChange: (v) => {
|
|
2032
|
+
if (v === "static") {
|
|
2033
|
+
updateConfig({ slotsUrl: void 0, embedUrl: void 0, embedProvider: void 0 });
|
|
2034
|
+
} else if (v === "url") {
|
|
2035
|
+
updateConfig({ slotsUrl: "", embedUrl: void 0, embedProvider: void 0, slots: void 0 });
|
|
2036
|
+
} else if (v === "embed") {
|
|
2037
|
+
updateConfig({ embedUrl: "", slotsUrl: void 0, slots: void 0 });
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
),
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Duration (min)", value: config.duration ?? 30, onChange: (v) => updateConfig({ duration: v }) }),
|
|
2043
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Timezone", value: config.timezone, placeholder: "e.g. America/New_York", onChange: (v) => updateConfig({ timezone: v }) }),
|
|
2044
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Timezone Field", value: config.timezoneField, placeholder: "Field ID for dynamic timezone", onChange: (v) => updateConfig({ timezoneField: v }) }),
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Date Format", value: config.dateFormat, placeholder: "Locale-aware (default)", onChange: (v) => updateConfig({ dateFormat: v }) }),
|
|
2046
|
+
appointmentMode === "url" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Slots URL", value: config.slotsUrl, placeholder: "https://api.example.com/slots", onChange: (v) => updateConfig({ slotsUrl: v }) }),
|
|
2047
|
+
appointmentMode === "embed" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2048
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Embed URL", value: config.embedUrl, placeholder: "https://calendly.com/your-name/30min", onChange: (v) => updateConfig({ embedUrl: v }) }),
|
|
2049
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2050
|
+
SelectField,
|
|
2051
|
+
{
|
|
2052
|
+
label: "Embed Provider",
|
|
2053
|
+
value: config.embedProvider ?? "custom",
|
|
2054
|
+
options: [
|
|
2055
|
+
{ label: "Calendly", value: "calendly" },
|
|
2056
|
+
{ label: "Cal.com", value: "cal_com" },
|
|
2057
|
+
{ label: "Custom", value: "custom" }
|
|
2058
|
+
],
|
|
2059
|
+
onChange: (v) => updateConfig({ embedProvider: v })
|
|
2060
|
+
}
|
|
2061
|
+
)
|
|
2062
|
+
] }),
|
|
2063
|
+
appointmentMode === "static" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2064
|
+
AppointmentSlotsEditor,
|
|
2065
|
+
{
|
|
2066
|
+
slots: config.slots ?? [],
|
|
2067
|
+
onChange: (v) => updateConfig({ slots: v })
|
|
2068
|
+
}
|
|
2069
|
+
)
|
|
1963
2070
|
] });
|
|
2071
|
+
}
|
|
1964
2072
|
// ── Media ──
|
|
1965
2073
|
case "file_upload":
|
|
1966
2074
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Upload Settings", children: [
|
|
1967
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Files", value: config.maxFiles ?? 1, onChange: (v) => updateConfig(
|
|
1968
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb ?? 10, onChange: (v) => updateConfig(
|
|
1969
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Accepted Types", value: config.accept?.join(", "), placeholder: "e.g. .pdf, .jpg, .png", onChange: (v) => updateConfig(
|
|
1970
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Upload URL", value: config.uploadUrl, placeholder: "Server upload endpoint", onChange: (v) => updateConfig(
|
|
2075
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Files", value: config.maxFiles ?? 1, onChange: (v) => updateConfig({ maxFiles: v }) }),
|
|
2076
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb ?? 10, onChange: (v) => updateConfig({ maxSizeMb: v }) }),
|
|
2077
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Accepted Types", value: config.accept?.join(", "), placeholder: "e.g. .pdf, .jpg, .png", onChange: (v) => updateConfig({ accept: v ? v.split(",").map((s) => s.trim()) : void 0 }) }),
|
|
2078
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Upload URL", value: config.uploadUrl, placeholder: "Server upload endpoint", onChange: (v) => updateConfig({ uploadUrl: v }) })
|
|
1971
2079
|
] });
|
|
1972
2080
|
case "signature":
|
|
1973
2081
|
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(
|
|
2082
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Pen Color", value: config.penColor, placeholder: "#000000", onChange: (v) => updateConfig({ penColor: v }) }),
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Background", value: config.backgroundColor, placeholder: "#ffffff", onChange: (v) => updateConfig({ backgroundColor: v }) }),
|
|
2084
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Width (px)", value: config.width, onChange: (v) => updateConfig({ width: v }) }),
|
|
2085
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Height (px)", value: config.height, onChange: (v) => updateConfig({ height: v }) })
|
|
1978
2086
|
] });
|
|
1979
2087
|
case "image_capture":
|
|
1980
2088
|
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(
|
|
2089
|
+
/* @__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 }) }),
|
|
2090
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb, onChange: (v) => updateConfig({ maxSizeMb: v }) }),
|
|
2091
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Gallery", checked: config.allowGallery !== false, onChange: (v) => updateConfig({ allowGallery: v }) })
|
|
1984
2092
|
] });
|
|
1985
2093
|
// ── Content & Visual ──
|
|
1986
2094
|
case "welcome-screen":
|
|
1987
2095
|
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(
|
|
2096
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Welcome", onChange: (v) => updateConfig({ heading: v }) }),
|
|
2097
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description, onChange: (v) => updateConfig({ description: v }) }),
|
|
2098
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Button Text", value: config.buttonText ?? "Start", onChange: (v) => updateConfig({ buttonText: v }) }),
|
|
2099
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig({ imageUrl: v }) }),
|
|
2100
|
+
/* @__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
2101
|
] });
|
|
1994
2102
|
case "thank-you-screen":
|
|
1995
2103
|
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(
|
|
2104
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Thank You!", onChange: (v) => updateConfig({ heading: v }) }),
|
|
2105
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description ?? "", onChange: (v) => updateConfig({ description: v }) }),
|
|
2106
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig({ imageUrl: v }) }),
|
|
2107
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Redirect URL", value: config.redirectUrl, placeholder: "https://...", onChange: (v) => updateConfig({ redirectUrl: v }) }),
|
|
2108
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Redirect Delay (s)", value: config.redirectDelay, placeholder: "0", onChange: (v) => updateConfig({ redirectDelay: v }) }),
|
|
2109
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Response Summary", checked: !!config.showSummary, onChange: (v) => updateConfig({ showSummary: v }) })
|
|
2002
2110
|
] });
|
|
2003
2111
|
case "rich-text":
|
|
2004
2112
|
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(
|
|
2113
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 6, onChange: (v) => updateConfig({ content: v }) }),
|
|
2114
|
+
/* @__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
2115
|
] });
|
|
2008
2116
|
case "image":
|
|
2009
2117
|
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(
|
|
2118
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "https://...", onChange: (v) => updateConfig({ src: v }) }),
|
|
2119
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Alt Text", value: config.alt ?? "", onChange: (v) => updateConfig({ alt: v }) }),
|
|
2120
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Caption", value: config.caption, onChange: (v) => updateConfig({ caption: v }) }),
|
|
2121
|
+
/* @__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 }) }),
|
|
2122
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 300px", onChange: (v) => updateConfig({ width: v }) }),
|
|
2123
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Link URL", value: config.link, placeholder: "Click opens this URL", onChange: (v) => updateConfig({ link: v }) })
|
|
2016
2124
|
] });
|
|
2017
2125
|
case "video":
|
|
2018
2126
|
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(
|
|
2127
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "YouTube/Vimeo URL", onChange: (v) => updateConfig({ src: v }) }),
|
|
2128
|
+
/* @__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 }) }),
|
|
2129
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Autoplay", checked: !!config.autoplay, onChange: (v) => updateConfig({ autoplay: v }) }),
|
|
2130
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Muted", checked: !!config.muted, onChange: (v) => updateConfig({ muted: v }) }),
|
|
2131
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 640px", onChange: (v) => updateConfig({ width: v }) }),
|
|
2132
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Height", value: config.height, placeholder: "e.g. 360px", onChange: (v) => updateConfig({ height: v }) })
|
|
2025
2133
|
] });
|
|
2026
2134
|
case "divider":
|
|
2027
2135
|
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(
|
|
2136
|
+
/* @__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 }) }),
|
|
2137
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Color", value: config.color, placeholder: "#e5e7eb", onChange: (v) => updateConfig({ color: v }) }),
|
|
2138
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Thickness (px)", value: config.thickness, placeholder: "1", onChange: (v) => updateConfig({ thickness: v }) }),
|
|
2139
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Spacing (px)", value: config.spacing, placeholder: "16", onChange: (v) => updateConfig({ spacing: v }) })
|
|
2032
2140
|
] });
|
|
2033
2141
|
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(
|
|
2142
|
+
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
2143
|
// ── Structural ──
|
|
2036
2144
|
case "section_header":
|
|
2037
2145
|
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(
|
|
2146
|
+
/* @__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 }) }),
|
|
2147
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Divider", checked: !!config.showDivider, onChange: (v) => updateConfig({ showDivider: v }) })
|
|
2040
2148
|
] });
|
|
2041
2149
|
case "info_block":
|
|
2042
2150
|
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(
|
|
2151
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 4, onChange: (v) => updateConfig({ content: v }) }),
|
|
2152
|
+
/* @__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
2153
|
] });
|
|
2046
2154
|
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(
|
|
2155
|
+
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
2156
|
case "consent":
|
|
2049
2157
|
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(
|
|
2158
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Consent Text", value: config.text ?? "", rows: 4, onChange: (v) => updateConfig({ text: v }) }),
|
|
2159
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Checkbox Label", value: config.checkboxLabel ?? "I agree", onChange: (v) => updateConfig({ checkboxLabel: v }) }),
|
|
2160
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Expandable Text", value: config.expandableText, rows: 3, placeholder: "Additional text shown on expand", onChange: (v) => updateConfig({ expandableText: v }) })
|
|
2053
2161
|
] });
|
|
2054
2162
|
// ── Advanced ──
|
|
2055
2163
|
case "matrix":
|
|
2056
2164
|
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(
|
|
2165
|
+
/* @__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 }) }),
|
|
2166
|
+
/* @__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 }) }),
|
|
2167
|
+
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Rows", items: config.rows ?? [], onChange: (v) => updateConfig({ rows: v }) }),
|
|
2168
|
+
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Columns", items: config.columns ?? [], onChange: (v) => updateConfig({ columns: v }) })
|
|
2061
2169
|
] });
|
|
2062
2170
|
case "repeater":
|
|
2063
2171
|
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(
|
|
2172
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Entries", value: config.minEntries, placeholder: "1", onChange: (v) => updateConfig({ minEntries: v }) }),
|
|
2173
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Entries", value: config.maxEntries, onChange: (v) => updateConfig({ maxEntries: v }) }),
|
|
2174
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Default Entries", value: config.defaultEntries, placeholder: "1", onChange: (v) => updateConfig({ defaultEntries: v }) }),
|
|
2175
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Add Button Label", value: config.addLabel, placeholder: "Add Entry", onChange: (v) => updateConfig({ addLabel: v }) }),
|
|
2176
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Remove Button Label", value: config.removeLabel, placeholder: "Remove", onChange: (v) => updateConfig({ removeLabel: v }) }),
|
|
2069
2177
|
/* @__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
2178
|
] });
|
|
2071
2179
|
case "address": {
|
|
@@ -2079,9 +2187,9 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2079
2187
|
];
|
|
2080
2188
|
const activeFields = config.fields ?? ["street", "city", "state", "zip", "country"];
|
|
2081
2189
|
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(
|
|
2190
|
+
/* @__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 }) }),
|
|
2191
|
+
config.provider !== "none" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "API Key", value: config.apiKey, placeholder: "Provider API key", onChange: (v) => updateConfig({ apiKey: v }) }),
|
|
2192
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry, placeholder: "e.g. US", onChange: (v) => updateConfig({ defaultCountry: v }) }),
|
|
2085
2193
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2086
2194
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-2 block", children: "Fields" }),
|
|
2087
2195
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2091,7 +2199,7 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2091
2199
|
checked: activeFields.includes(f.value),
|
|
2092
2200
|
onChange: (checked) => {
|
|
2093
2201
|
const next = checked ? [...activeFields, f.value] : activeFields.filter((v) => v !== f.value);
|
|
2094
|
-
updateConfig(
|
|
2202
|
+
updateConfig({ fields: next.length > 0 ? next : void 0 });
|
|
2095
2203
|
}
|
|
2096
2204
|
},
|
|
2097
2205
|
f.value
|
|
@@ -2101,41 +2209,47 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2101
2209
|
}
|
|
2102
2210
|
case "payment":
|
|
2103
2211
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Payment Settings", children: [
|
|
2104
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "stripe", options: [{ label: "Stripe", value: "stripe" }, { label: "PayPal", value: "paypal" }], onChange: (v) => updateConfig(
|
|
2105
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Public Key", value: config.publicKey ?? "", placeholder: "Provider public/client key", onChange: (v) => updateConfig(
|
|
2106
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2107
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
2108
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2109
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
2212
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "stripe", options: [{ label: "Stripe", value: "stripe" }, { label: "PayPal", value: "paypal" }], onChange: (v) => updateConfig({ provider: v }) }),
|
|
2213
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Public Key", value: config.publicKey ?? "", placeholder: "Provider public/client key", onChange: (v) => updateConfig({ publicKey: v }) }),
|
|
2214
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Server URL", value: config.serverUrl ?? "", placeholder: "https://api.example.com/create-intent", onChange: (v) => updateConfig({ serverUrl: v || void 0 }) }),
|
|
2215
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Client Secret Path", value: config.responseMapping?.clientSecretPath ?? "", placeholder: "clientSecret", onChange: (v) => updateConfig({ responseMapping: v ? { clientSecretPath: v } : void 0 }) }),
|
|
2216
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Amount", value: config.amount, onChange: (v) => updateConfig({ amount: v }) }),
|
|
2217
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Amount Field", value: config.amountField, placeholder: "Field ID for dynamic amount", onChange: (v) => updateConfig({ amountField: v }) }),
|
|
2218
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Currency", value: config.currency, placeholder: "USD", onChange: (v) => updateConfig({ currency: v }) }),
|
|
2219
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Description", value: config.description, onChange: (v) => updateConfig({ description: v }) })
|
|
2110
2220
|
] });
|
|
2111
2221
|
case "calculated":
|
|
2112
2222
|
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(
|
|
2223
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Expression", value: config.expression ?? "", placeholder: "e.g. {q1} + {q2}", onChange: (v) => updateConfig({ expression: v }) }),
|
|
2224
|
+
/* @__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 }) }),
|
|
2225
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "2", onChange: (v) => updateConfig({ decimalPlaces: v }) }),
|
|
2226
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, onChange: (v) => updateConfig({ prefix: v }) }),
|
|
2227
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, onChange: (v) => updateConfig({ suffix: v }) }),
|
|
2228
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Visible to User", checked: config.visible !== false, onChange: (v) => updateConfig({ visible: v }) })
|
|
2119
2229
|
] });
|
|
2120
2230
|
case "hidden":
|
|
2121
2231
|
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(
|
|
2232
|
+
/* @__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 }) }),
|
|
2233
|
+
config.source === "static" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Value", value: config.defaultValue, onChange: (v) => updateConfig({ defaultValue: v }) }),
|
|
2234
|
+
config.source === "url_param" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Parameter Name", value: config.paramName, placeholder: "e.g. utm_source", onChange: (v) => updateConfig({ paramName: v }) }),
|
|
2235
|
+
config.source === "cookie" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Cookie Name", value: config.cookieName, onChange: (v) => updateConfig({ cookieName: v }) })
|
|
2126
2236
|
] });
|
|
2127
2237
|
case "scoring":
|
|
2128
2238
|
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(
|
|
2239
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Score", checked: !!config.showScore, onChange: (v) => updateConfig({ showScore: v }) }),
|
|
2240
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScoringOptionsEditor, { options: config.options ?? [], onChange: (v) => updateConfig({ options: v }) }),
|
|
2241
|
+
/* @__PURE__ */ jsxRuntime.jsx(ScoreRangesEditor, { ranges: config.scoreRanges ?? [], onChange: (v) => updateConfig({ scoreRanges: v }) })
|
|
2132
2242
|
] });
|
|
2133
2243
|
case "ranking":
|
|
2134
|
-
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Ranking Settings", children: /* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Items", items: config.items ?? [], onChange: (v) => updateConfig(
|
|
2244
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ConfigSection, { title: "Ranking Settings", children: /* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Items", items: config.items ?? [], onChange: (v) => updateConfig({ items: v }) }) });
|
|
2245
|
+
case "phone_international":
|
|
2246
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "International Phone Settings", children: [
|
|
2247
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry ?? "US", placeholder: "e.g. US", onChange: (v) => updateConfig({ defaultCountry: v }) }),
|
|
2248
|
+
/* @__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 }) })
|
|
2249
|
+
] });
|
|
2135
2250
|
// Types with no additional config
|
|
2136
2251
|
case "email":
|
|
2137
2252
|
case "phone":
|
|
2138
|
-
case "phone_international":
|
|
2139
2253
|
case "url":
|
|
2140
2254
|
return null;
|
|
2141
2255
|
default:
|
|
@@ -2227,7 +2341,10 @@ function SelectField({
|
|
|
2227
2341
|
}) {
|
|
2228
2342
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2229
2343
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
2230
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2344
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Select, { value, onValueChange: onChange, children: [
|
|
2345
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectTrigger, { children: /* @__PURE__ */ jsxRuntime.jsx("span", { children: options.find((o) => o.value === value)?.label ?? value }) }),
|
|
2346
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectContent, { children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)) })
|
|
2347
|
+
] })
|
|
2231
2348
|
] });
|
|
2232
2349
|
}
|
|
2233
2350
|
function LikertLabelsEditor({
|
|
@@ -2373,6 +2490,59 @@ function ScoringOptionsEditor({
|
|
|
2373
2490
|
] }, index)) })
|
|
2374
2491
|
] });
|
|
2375
2492
|
}
|
|
2493
|
+
function AppointmentSlotsEditor({
|
|
2494
|
+
slots,
|
|
2495
|
+
onChange
|
|
2496
|
+
}) {
|
|
2497
|
+
const handleDateChange = (index, date) => {
|
|
2498
|
+
const updated = slots.map((s, i) => i === index ? { ...s, date } : s);
|
|
2499
|
+
onChange(updated);
|
|
2500
|
+
};
|
|
2501
|
+
const handleTimesChange = (index, timesStr) => {
|
|
2502
|
+
const times = timesStr.split(",").map((t) => t.trim()).filter(Boolean);
|
|
2503
|
+
const updated = slots.map((s, i) => i === index ? { ...s, times } : s);
|
|
2504
|
+
onChange(updated);
|
|
2505
|
+
};
|
|
2506
|
+
const handleAdd = () => {
|
|
2507
|
+
const tomorrow = /* @__PURE__ */ new Date();
|
|
2508
|
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
|
2509
|
+
const dateStr = tomorrow.toISOString().split("T")[0];
|
|
2510
|
+
onChange([...slots, { date: dateStr, times: ["09:00", "10:00", "11:00", "14:00", "15:00"] }]);
|
|
2511
|
+
};
|
|
2512
|
+
const handleRemove = (index) => {
|
|
2513
|
+
onChange(slots.filter((_, i) => i !== index));
|
|
2514
|
+
};
|
|
2515
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2516
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
2517
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Slots" }),
|
|
2518
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add Date" })
|
|
2519
|
+
] }),
|
|
2520
|
+
slots.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-muted-foreground", children: "No slots configured. Add a date to get started." }),
|
|
2521
|
+
/* @__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: [
|
|
2522
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2523
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2524
|
+
fieldcraftReact.Input,
|
|
2525
|
+
{
|
|
2526
|
+
type: "date",
|
|
2527
|
+
value: slot.date,
|
|
2528
|
+
onChange: (e) => handleDateChange(index, e.target.value),
|
|
2529
|
+
className: "h-7 text-xs flex-1"
|
|
2530
|
+
}
|
|
2531
|
+
),
|
|
2532
|
+
/* @__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" })
|
|
2533
|
+
] }),
|
|
2534
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2535
|
+
fieldcraftReact.Input,
|
|
2536
|
+
{
|
|
2537
|
+
value: slot.times.join(", "),
|
|
2538
|
+
onChange: (e) => handleTimesChange(index, e.target.value),
|
|
2539
|
+
className: "h-7 text-xs",
|
|
2540
|
+
placeholder: "09:00, 10:00, 14:00, 15:00"
|
|
2541
|
+
}
|
|
2542
|
+
)
|
|
2543
|
+
] }, index)) })
|
|
2544
|
+
] });
|
|
2545
|
+
}
|
|
2376
2546
|
function ScoreRangesEditor({
|
|
2377
2547
|
ranges,
|
|
2378
2548
|
onChange
|
|
@@ -2405,6 +2575,26 @@ function ScoreRangesEditor({
|
|
|
2405
2575
|
] }, index)) })
|
|
2406
2576
|
] });
|
|
2407
2577
|
}
|
|
2578
|
+
var NativeSelect = React.forwardRef(
|
|
2579
|
+
({ className, wrapperClassName, children, ...props }, ref) => {
|
|
2580
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", wrapperClassName), children: [
|
|
2581
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2582
|
+
"select",
|
|
2583
|
+
{
|
|
2584
|
+
ref,
|
|
2585
|
+
className: cn(
|
|
2586
|
+
"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",
|
|
2587
|
+
className
|
|
2588
|
+
),
|
|
2589
|
+
...props,
|
|
2590
|
+
children
|
|
2591
|
+
}
|
|
2592
|
+
),
|
|
2593
|
+
/* @__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" })
|
|
2594
|
+
] });
|
|
2595
|
+
}
|
|
2596
|
+
);
|
|
2597
|
+
NativeSelect.displayName = "NativeSelect";
|
|
2408
2598
|
var RULE_TYPES = [
|
|
2409
2599
|
{ value: "minLength", label: "Min Length", description: "Minimum character count" },
|
|
2410
2600
|
{ value: "maxLength", label: "Max Length", description: "Maximum character count" },
|
|
@@ -2809,7 +2999,7 @@ function FormSettingsPanel({ schema, onUpdate }) {
|
|
|
2809
2999
|
];
|
|
2810
3000
|
const displayMode = settings.displayMode ?? "stepped";
|
|
2811
3001
|
const effectiveDisplayMode = hasConditions && displayMode === "classic" ? "stepped" : displayMode;
|
|
2812
|
-
|
|
3002
|
+
React.useEffect(() => {
|
|
2813
3003
|
if (effectiveDisplayMode !== displayMode) {
|
|
2814
3004
|
onUpdate({ ...schema, settings: { ...settings, displayMode: effectiveDisplayMode } });
|
|
2815
3005
|
}
|
|
@@ -2966,7 +3156,7 @@ function SettingsSelect({
|
|
|
2966
3156
|
}
|
|
2967
3157
|
function PropertiesPanel({ builderState }) {
|
|
2968
3158
|
const { schema, selectedItem } = builderState;
|
|
2969
|
-
const [showSettings, setShowSettings] =
|
|
3159
|
+
const [showSettings, setShowSettings] = React.useState(false);
|
|
2970
3160
|
if (showSettings) {
|
|
2971
3161
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-80 h-full border-l border-border bg-card flex flex-col", children: [
|
|
2972
3162
|
/* @__PURE__ */ jsxRuntime.jsx(PanelHeader, { title: "Form Settings", onClose: () => setShowSettings(false) }),
|
|
@@ -3041,11 +3231,11 @@ function SectionProperties({ section, onUpdate, onClose, onOpenSettings }) {
|
|
|
3041
3231
|
] });
|
|
3042
3232
|
}
|
|
3043
3233
|
function QuestionProperties({ question, sectionId, builderState, onClose, onOpenSettings }) {
|
|
3044
|
-
const [activeTab, setActiveTab] =
|
|
3234
|
+
const [activeTab, setActiveTab] = React.useState("basic");
|
|
3045
3235
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
3046
3236
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
3047
3237
|
const hasOptions = typeInfo?.requiresOptions || question.options && question.options.length > 0;
|
|
3048
|
-
const updateQuestion2 =
|
|
3238
|
+
const updateQuestion2 = React.useCallback(
|
|
3049
3239
|
(updates) => {
|
|
3050
3240
|
builderState.updateQuestion(sectionId, question.id, updates);
|
|
3051
3241
|
},
|
|
@@ -3220,7 +3410,7 @@ function FieldGroup({ label, children }) {
|
|
|
3220
3410
|
children
|
|
3221
3411
|
] });
|
|
3222
3412
|
}
|
|
3223
|
-
var PreviewErrorBoundary = class extends
|
|
3413
|
+
var PreviewErrorBoundary = class extends React.Component {
|
|
3224
3414
|
state = { error: null };
|
|
3225
3415
|
static getDerivedStateFromError(error) {
|
|
3226
3416
|
return { error };
|
|
@@ -3281,15 +3471,15 @@ function errorsToMarkers(errors) {
|
|
|
3281
3471
|
source: "FieldCraft Schema Validator"
|
|
3282
3472
|
}));
|
|
3283
3473
|
}
|
|
3284
|
-
var Editor =
|
|
3474
|
+
var Editor = React.lazy(() => import('@monaco-editor/react').then((m) => ({ default: m.default })));
|
|
3285
3475
|
function MonacoWrapper({ value, onChange, errors }) {
|
|
3286
|
-
const editorRef =
|
|
3287
|
-
const monacoRef =
|
|
3476
|
+
const editorRef = React.useRef(null);
|
|
3477
|
+
const monacoRef = React.useRef(null);
|
|
3288
3478
|
const handleMount = (editor, monaco) => {
|
|
3289
3479
|
editorRef.current = editor;
|
|
3290
3480
|
monacoRef.current = monaco;
|
|
3291
3481
|
};
|
|
3292
|
-
|
|
3482
|
+
React.useEffect(() => {
|
|
3293
3483
|
const editor = editorRef.current;
|
|
3294
3484
|
const monaco = monacoRef.current;
|
|
3295
3485
|
if (!editor || !monaco) return;
|
|
@@ -3321,14 +3511,14 @@ function MonacoWrapper({ value, onChange, errors }) {
|
|
|
3321
3511
|
);
|
|
3322
3512
|
}
|
|
3323
3513
|
function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
3324
|
-
const handleChange =
|
|
3514
|
+
const handleChange = React.useCallback(
|
|
3325
3515
|
(newValue) => {
|
|
3326
3516
|
onChange(newValue);
|
|
3327
3517
|
onValidate(newValue);
|
|
3328
3518
|
},
|
|
3329
3519
|
[onChange, onValidate]
|
|
3330
3520
|
);
|
|
3331
|
-
const handleFormat =
|
|
3521
|
+
const handleFormat = React.useCallback(() => {
|
|
3332
3522
|
try {
|
|
3333
3523
|
const formatted = JSON.stringify(JSON.parse(value), null, 2);
|
|
3334
3524
|
onChange(formatted);
|
|
@@ -3361,7 +3551,7 @@ function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
|
3361
3551
|
)
|
|
3362
3552
|
] }),
|
|
3363
3553
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3364
|
-
|
|
3554
|
+
React.Suspense,
|
|
3365
3555
|
{
|
|
3366
3556
|
fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-sm text-muted-foreground", children: "Loading editor..." }),
|
|
3367
3557
|
children: /* @__PURE__ */ jsxRuntime.jsx(MonacoWrapper, { value, onChange: handleChange, errors })
|
|
@@ -3560,7 +3750,7 @@ function SectionNodeInner({ data }) {
|
|
|
3560
3750
|
const d = data;
|
|
3561
3751
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
3562
3752
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group", style: { borderColor: color }, children: [
|
|
3563
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3753
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle fc-flow-handle--section" }),
|
|
3564
3754
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group__header", style: { background: color }, children: [
|
|
3565
3755
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__label", children: d.label.length > 30 ? d.label.slice(0, 30) + "\u2026" : d.label }),
|
|
3566
3756
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "fc-flow-section-group__meta", children: [
|
|
@@ -3571,10 +3761,10 @@ function SectionNodeInner({ data }) {
|
|
|
3571
3761
|
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
3762
|
] })
|
|
3573
3763
|
] }),
|
|
3574
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3764
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle fc-flow-handle--section" })
|
|
3575
3765
|
] });
|
|
3576
3766
|
}
|
|
3577
|
-
var SectionNode =
|
|
3767
|
+
var SectionNode = React.memo(SectionNodeInner);
|
|
3578
3768
|
function FieldNodeInner({ data }) {
|
|
3579
3769
|
const d = data;
|
|
3580
3770
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
@@ -3587,18 +3777,18 @@ function FieldNodeInner({ data }) {
|
|
|
3587
3777
|
borderWidth: d.hasCondition ? 2 : 1
|
|
3588
3778
|
},
|
|
3589
3779
|
children: [
|
|
3590
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3780
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle" }),
|
|
3591
3781
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-field__content", children: [
|
|
3592
3782
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__label", children: d.label.length > 26 ? d.label.slice(0, 26) + "\u2026" : d.label }),
|
|
3593
3783
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__type", children: d.fieldType })
|
|
3594
3784
|
] }),
|
|
3595
3785
|
d.hasCondition && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fc-flow-badge", style: { background: color }, title: "Has showIf condition", children: "?" }),
|
|
3596
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3786
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle" })
|
|
3597
3787
|
]
|
|
3598
3788
|
}
|
|
3599
3789
|
);
|
|
3600
3790
|
}
|
|
3601
|
-
var FieldNode =
|
|
3791
|
+
var FieldNode = React.memo(FieldNodeInner);
|
|
3602
3792
|
var logicFlowNodeTypes = {
|
|
3603
3793
|
sectionNode: SectionNode,
|
|
3604
3794
|
fieldNode: FieldNode
|
|
@@ -3616,7 +3806,7 @@ function ConditionEdgeInner({
|
|
|
3616
3806
|
data,
|
|
3617
3807
|
markerEnd
|
|
3618
3808
|
}) {
|
|
3619
|
-
const [edgePath, labelX, labelY] = react
|
|
3809
|
+
const [edgePath, labelX, labelY] = react.getBezierPath({
|
|
3620
3810
|
sourceX,
|
|
3621
3811
|
sourceY,
|
|
3622
3812
|
sourcePosition,
|
|
@@ -3627,7 +3817,7 @@ function ConditionEdgeInner({
|
|
|
3627
3817
|
const isJump = data?.edgeType === "onExit";
|
|
3628
3818
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3629
3819
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3630
|
-
react
|
|
3820
|
+
react.BaseEdge,
|
|
3631
3821
|
{
|
|
3632
3822
|
id,
|
|
3633
3823
|
path: edgePath,
|
|
@@ -3640,7 +3830,7 @@ function ConditionEdgeInner({
|
|
|
3640
3830
|
}
|
|
3641
3831
|
}
|
|
3642
3832
|
),
|
|
3643
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(react
|
|
3833
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(react.EdgeLabelRenderer, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3644
3834
|
"div",
|
|
3645
3835
|
{
|
|
3646
3836
|
className: "fc-flow-edge-label",
|
|
@@ -3653,7 +3843,7 @@ function ConditionEdgeInner({
|
|
|
3653
3843
|
) })
|
|
3654
3844
|
] });
|
|
3655
3845
|
}
|
|
3656
|
-
var ConditionEdge =
|
|
3846
|
+
var ConditionEdge = React.memo(ConditionEdgeInner);
|
|
3657
3847
|
function PipelineEdgeInner({
|
|
3658
3848
|
id,
|
|
3659
3849
|
sourceX,
|
|
@@ -3664,7 +3854,7 @@ function PipelineEdgeInner({
|
|
|
3664
3854
|
targetPosition,
|
|
3665
3855
|
markerEnd
|
|
3666
3856
|
}) {
|
|
3667
|
-
const [edgePath] = react
|
|
3857
|
+
const [edgePath] = react.getBezierPath({
|
|
3668
3858
|
sourceX,
|
|
3669
3859
|
sourceY,
|
|
3670
3860
|
sourcePosition,
|
|
@@ -3673,7 +3863,7 @@ function PipelineEdgeInner({
|
|
|
3673
3863
|
targetPosition
|
|
3674
3864
|
});
|
|
3675
3865
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3676
|
-
react
|
|
3866
|
+
react.BaseEdge,
|
|
3677
3867
|
{
|
|
3678
3868
|
id,
|
|
3679
3869
|
path: edgePath,
|
|
@@ -3686,7 +3876,7 @@ function PipelineEdgeInner({
|
|
|
3686
3876
|
}
|
|
3687
3877
|
);
|
|
3688
3878
|
}
|
|
3689
|
-
var PipelineEdge =
|
|
3879
|
+
var PipelineEdge = React.memo(PipelineEdgeInner);
|
|
3690
3880
|
var logicFlowEdgeTypes = {
|
|
3691
3881
|
conditionEdge: ConditionEdge,
|
|
3692
3882
|
pipelineEdge: PipelineEdge
|
|
@@ -3724,30 +3914,30 @@ function removeConditionForSource(showIf, sourceFieldId) {
|
|
|
3724
3914
|
}
|
|
3725
3915
|
var defaultEdgeOptions = {
|
|
3726
3916
|
markerEnd: {
|
|
3727
|
-
type: react
|
|
3917
|
+
type: react.MarkerType.ArrowClosed,
|
|
3728
3918
|
width: 16,
|
|
3729
3919
|
height: 12
|
|
3730
3920
|
}
|
|
3731
3921
|
};
|
|
3732
3922
|
function LogicFlowEditor({ schema, onChange }) {
|
|
3733
3923
|
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] =
|
|
3924
|
+
const flowGraph = React.useMemo(() => buildReactFlowGraph(schema), [schema]);
|
|
3925
|
+
const [nodes, setNodes, onNodesChange] = react.useNodesState(flowGraph.nodes);
|
|
3926
|
+
const [edges, setEdges, onEdgesChange] = react.useEdgesState(flowGraph.edges);
|
|
3927
|
+
const [selectedFieldId, setSelectedFieldId] = React.useState(null);
|
|
3738
3928
|
const selectedQuestion = selectedFieldId ? findQuestion2(schema, selectedFieldId) : void 0;
|
|
3739
|
-
|
|
3929
|
+
React.useEffect(() => {
|
|
3740
3930
|
setNodes(flowGraph.nodes);
|
|
3741
3931
|
setEdges(flowGraph.edges);
|
|
3742
3932
|
}, [flowGraph, setNodes, setEdges]);
|
|
3743
|
-
const sectionIds =
|
|
3933
|
+
const sectionIds = React.useMemo(() => {
|
|
3744
3934
|
const ids = [];
|
|
3745
3935
|
for (const section of schema.sections) {
|
|
3746
3936
|
ids.push(section.id);
|
|
3747
3937
|
}
|
|
3748
3938
|
return ids;
|
|
3749
3939
|
}, [schema]);
|
|
3750
|
-
const onNodeClick =
|
|
3940
|
+
const onNodeClick = React.useCallback(
|
|
3751
3941
|
(_event, node) => {
|
|
3752
3942
|
if (node.type === "fieldNode") {
|
|
3753
3943
|
setSelectedFieldId(node.id);
|
|
@@ -3755,7 +3945,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3755
3945
|
},
|
|
3756
3946
|
[]
|
|
3757
3947
|
);
|
|
3758
|
-
const onConnect =
|
|
3948
|
+
const onConnect = React.useCallback(
|
|
3759
3949
|
(connection) => {
|
|
3760
3950
|
if (!connection.source || !connection.target) return;
|
|
3761
3951
|
const targetQuestion = findQuestion2(schema, connection.target);
|
|
@@ -3782,7 +3972,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3782
3972
|
},
|
|
3783
3973
|
[schema, onChange]
|
|
3784
3974
|
);
|
|
3785
|
-
const onEdgesDelete =
|
|
3975
|
+
const onEdgesDelete = React.useCallback(
|
|
3786
3976
|
(deletedEdges) => {
|
|
3787
3977
|
let updatedSchema = schema;
|
|
3788
3978
|
for (const edge of deletedEdges) {
|
|
@@ -3807,7 +3997,7 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3807
3997
|
},
|
|
3808
3998
|
[schema, onChange]
|
|
3809
3999
|
);
|
|
3810
|
-
const handleConditionUpdate =
|
|
4000
|
+
const handleConditionUpdate = React.useCallback(
|
|
3811
4001
|
(updates) => {
|
|
3812
4002
|
if (!selectedFieldId) return;
|
|
3813
4003
|
const updatedSchema = updateQuestionInSchema(schema, selectedFieldId, updates);
|
|
@@ -3821,18 +4011,18 @@ function LogicFlowEditor({ schema, onChange }) {
|
|
|
3821
4011
|
const jumpCount = flowGraph.edges.filter(
|
|
3822
4012
|
(e) => e.data?.edgeType === "onExit"
|
|
3823
4013
|
).length;
|
|
3824
|
-
const totalFields =
|
|
4014
|
+
const totalFields = React.useMemo(
|
|
3825
4015
|
() => schema.sections.reduce((sum, s) => sum + s.questions.length, 0),
|
|
3826
4016
|
[schema]
|
|
3827
4017
|
);
|
|
3828
|
-
const conditionalFields =
|
|
4018
|
+
const conditionalFields = React.useMemo(
|
|
3829
4019
|
() => schema.sections.reduce(
|
|
3830
4020
|
(sum, s) => sum + s.questions.filter((q) => !!q.showIf).length,
|
|
3831
4021
|
0
|
|
3832
4022
|
),
|
|
3833
4023
|
[schema]
|
|
3834
4024
|
);
|
|
3835
|
-
return /* @__PURE__ */ jsxRuntime.jsx(react
|
|
4025
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3836
4026
|
LogicFlowInner,
|
|
3837
4027
|
{
|
|
3838
4028
|
noSections,
|
|
@@ -3876,7 +4066,7 @@ function LogicFlowInner({
|
|
|
3876
4066
|
totalFields,
|
|
3877
4067
|
conditionalFields
|
|
3878
4068
|
}) {
|
|
3879
|
-
const { zoomIn, zoomOut, fitView } = react
|
|
4069
|
+
const { zoomIn, zoomOut, fitView } = react.useReactFlow();
|
|
3880
4070
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: [
|
|
3881
4071
|
/* @__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
4072
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
@@ -3904,7 +4094,7 @@ function LogicFlowInner({
|
|
|
3904
4094
|
/* @__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
4095
|
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
3906
4096
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3907
|
-
react
|
|
4097
|
+
react.ReactFlow,
|
|
3908
4098
|
{
|
|
3909
4099
|
nodes,
|
|
3910
4100
|
edges,
|
|
@@ -3921,9 +4111,9 @@ function LogicFlowInner({
|
|
|
3921
4111
|
deleteKeyCode: ["Backspace", "Delete"],
|
|
3922
4112
|
proOptions: { hideAttribution: true },
|
|
3923
4113
|
children: [
|
|
3924
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
4114
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Background, { gap: 20, size: 1 }),
|
|
3925
4115
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3926
|
-
react
|
|
4116
|
+
react.MiniMap,
|
|
3927
4117
|
{
|
|
3928
4118
|
nodeColor: (node) => {
|
|
3929
4119
|
const d = node.data;
|
|
@@ -3987,15 +4177,15 @@ function LogicFlowInner({
|
|
|
3987
4177
|
] });
|
|
3988
4178
|
}
|
|
3989
4179
|
function TemplateGallery({ templates, onSelect, onClose }) {
|
|
3990
|
-
const [search, setSearch] =
|
|
3991
|
-
const [activeCategory, setActiveCategory] =
|
|
3992
|
-
const [confirmTemplate, setConfirmTemplate] =
|
|
3993
|
-
const categories =
|
|
4180
|
+
const [search, setSearch] = React.useState("");
|
|
4181
|
+
const [activeCategory, setActiveCategory] = React.useState("all");
|
|
4182
|
+
const [confirmTemplate, setConfirmTemplate] = React.useState(null);
|
|
4183
|
+
const categories = React.useMemo(() => {
|
|
3994
4184
|
const cats = /* @__PURE__ */ new Set();
|
|
3995
4185
|
for (const t of templates) cats.add(t.meta.category);
|
|
3996
4186
|
return ["all", ...Array.from(cats)];
|
|
3997
4187
|
}, [templates]);
|
|
3998
|
-
const filtered =
|
|
4188
|
+
const filtered = React.useMemo(() => {
|
|
3999
4189
|
return templates.filter((t) => {
|
|
4000
4190
|
const matchesCategory = activeCategory === "all" || t.meta.category === activeCategory;
|
|
4001
4191
|
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 +4281,9 @@ function TemplateGallery({ templates, onSelect, onClose }) {
|
|
|
4091
4281
|
] }) });
|
|
4092
4282
|
}
|
|
4093
4283
|
function useDebouncedValidation(delayMs = 500) {
|
|
4094
|
-
const [errors, setErrors] =
|
|
4095
|
-
const timerRef =
|
|
4096
|
-
const validate =
|
|
4284
|
+
const [errors, setErrors] = React.useState([]);
|
|
4285
|
+
const timerRef = React.useRef(null);
|
|
4286
|
+
const validate = React.useCallback(
|
|
4097
4287
|
(text) => {
|
|
4098
4288
|
if (timerRef.current) {
|
|
4099
4289
|
clearTimeout(timerRef.current);
|
|
@@ -4142,9 +4332,9 @@ function useDebouncedValidation(delayMs = 500) {
|
|
|
4142
4332
|
);
|
|
4143
4333
|
return { errors, validate };
|
|
4144
4334
|
}
|
|
4145
|
-
var ThemeCtx =
|
|
4335
|
+
var ThemeCtx = React.createContext({});
|
|
4146
4336
|
function useBuilderTheme() {
|
|
4147
|
-
return
|
|
4337
|
+
return React.useContext(ThemeCtx);
|
|
4148
4338
|
}
|
|
4149
4339
|
function themeToCssVars(theme) {
|
|
4150
4340
|
const vars = {};
|
|
@@ -4180,10 +4370,10 @@ function themeToCssVars(theme) {
|
|
|
4180
4370
|
}
|
|
4181
4371
|
function FormBuilderThemeProvider({ theme, children }) {
|
|
4182
4372
|
const resolved = theme ?? {};
|
|
4183
|
-
const cssVars =
|
|
4373
|
+
const cssVars = React.useMemo(() => themeToCssVars(resolved), [resolved]);
|
|
4184
4374
|
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
4375
|
}
|
|
4186
|
-
var FormBuilderErrorBoundary = class extends
|
|
4376
|
+
var FormBuilderErrorBoundary = class extends React.Component {
|
|
4187
4377
|
constructor(props) {
|
|
4188
4378
|
super(props);
|
|
4189
4379
|
this.state = { hasError: false, error: null };
|
|
@@ -4215,30 +4405,30 @@ var FormBuilderErrorBoundary = class extends react.Component {
|
|
|
4215
4405
|
};
|
|
4216
4406
|
function FormBuilderCore(props) {
|
|
4217
4407
|
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] =
|
|
4408
|
+
const [viewMode, setViewMode] = React.useState("design");
|
|
4409
|
+
const [jsonText, setJsonText] = React.useState("");
|
|
4410
|
+
const [jsonSwitchError, setJsonSwitchError] = React.useState(null);
|
|
4411
|
+
const [showTemplateGallery, setShowTemplateGallery] = React.useState(false);
|
|
4412
|
+
const [saveValidationErrors, setSaveValidationErrors] = React.useState(null);
|
|
4413
|
+
const [schemaUrlLoading, setSchemaUrlLoading] = React.useState(!!schemaUrl);
|
|
4414
|
+
const [schemaUrlError, setSchemaUrlError] = React.useState(null);
|
|
4225
4415
|
const { errors: jsonErrors, validate: validateJson } = useDebouncedValidation(400);
|
|
4226
4416
|
const mergedQuestionTypes = questionTypes ? { ...QUESTION_TYPE_INFO, ...questionTypes } : QUESTION_TYPE_INFO;
|
|
4227
4417
|
const builderState = useBuilderState(initialSchema);
|
|
4228
4418
|
const dragDrop = useDragDrop(builderState);
|
|
4229
|
-
const fileInputRef =
|
|
4230
|
-
const [mobilePanel, setMobilePanel] =
|
|
4231
|
-
|
|
4419
|
+
const fileInputRef = React.useRef(null);
|
|
4420
|
+
const [mobilePanel, setMobilePanel] = React.useState("none");
|
|
4421
|
+
React.useEffect(() => {
|
|
4232
4422
|
if (builderState.selectedItem && window.innerWidth < 768) {
|
|
4233
4423
|
setMobilePanel("properties");
|
|
4234
4424
|
}
|
|
4235
4425
|
}, [builderState.selectedItem]);
|
|
4236
|
-
|
|
4426
|
+
React.useEffect(() => {
|
|
4237
4427
|
if (!dragDrop.activeDragItem && mobilePanel === "palette") {
|
|
4238
4428
|
setMobilePanel("none");
|
|
4239
4429
|
}
|
|
4240
4430
|
}, [dragDrop.activeDragItem]);
|
|
4241
|
-
|
|
4431
|
+
React.useEffect(() => {
|
|
4242
4432
|
if (!schemaUrl) return;
|
|
4243
4433
|
let cancelled = false;
|
|
4244
4434
|
setSchemaUrlLoading(true);
|
|
@@ -4268,12 +4458,12 @@ function FormBuilderCore(props) {
|
|
|
4268
4458
|
cancelled = true;
|
|
4269
4459
|
};
|
|
4270
4460
|
}, [schemaUrl]);
|
|
4271
|
-
|
|
4461
|
+
React.useEffect(() => {
|
|
4272
4462
|
if (onChange && builderState.isDirty) {
|
|
4273
4463
|
onChange(builderState.schema);
|
|
4274
4464
|
}
|
|
4275
4465
|
}, [builderState.schema, builderState.isDirty, onChange]);
|
|
4276
|
-
const handleSave =
|
|
4466
|
+
const handleSave = React.useCallback(() => {
|
|
4277
4467
|
if (!onSave) return;
|
|
4278
4468
|
try {
|
|
4279
4469
|
fieldcraftCore.validateSchema(builderState.schema);
|
|
@@ -4288,7 +4478,7 @@ function FormBuilderCore(props) {
|
|
|
4288
4478
|
}
|
|
4289
4479
|
}
|
|
4290
4480
|
}, [onSave, builderState]);
|
|
4291
|
-
const handleExport =
|
|
4481
|
+
const handleExport = React.useCallback(() => {
|
|
4292
4482
|
const json = JSON.stringify(builderState.schema, null, 2);
|
|
4293
4483
|
const blob = new Blob([json], { type: "application/json" });
|
|
4294
4484
|
const url = URL.createObjectURL(blob);
|
|
@@ -4298,10 +4488,10 @@ function FormBuilderCore(props) {
|
|
|
4298
4488
|
a.click();
|
|
4299
4489
|
URL.revokeObjectURL(url);
|
|
4300
4490
|
}, [builderState.schema]);
|
|
4301
|
-
const handleImport =
|
|
4491
|
+
const handleImport = React.useCallback(() => {
|
|
4302
4492
|
fileInputRef.current?.click();
|
|
4303
4493
|
}, []);
|
|
4304
|
-
const handleFileChange =
|
|
4494
|
+
const handleFileChange = React.useCallback(
|
|
4305
4495
|
(e) => {
|
|
4306
4496
|
const file = e.target.files?.[0];
|
|
4307
4497
|
if (!file) return;
|
|
@@ -4328,7 +4518,7 @@ ${details}`);
|
|
|
4328
4518
|
},
|
|
4329
4519
|
[builderState]
|
|
4330
4520
|
);
|
|
4331
|
-
const handleViewModeChange =
|
|
4521
|
+
const handleViewModeChange = React.useCallback(
|
|
4332
4522
|
(newMode) => {
|
|
4333
4523
|
setJsonSwitchError(null);
|
|
4334
4524
|
if (viewMode === "json" && newMode !== "json") {
|
|
@@ -4354,7 +4544,7 @@ ${details}`);
|
|
|
4354
4544
|
},
|
|
4355
4545
|
[viewMode, jsonText, builderState]
|
|
4356
4546
|
);
|
|
4357
|
-
const handleKeyDown =
|
|
4547
|
+
const handleKeyDown = React.useCallback(
|
|
4358
4548
|
(e) => {
|
|
4359
4549
|
const mod = e.metaKey || e.ctrlKey;
|
|
4360
4550
|
const tag = e.target.tagName;
|