@squaredr/fieldcraft-pro 1.6.4 → 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-VECQKSWS.mjs → chunk-4MMKB2EW.mjs} +60 -86
- package/dist/{chunk-CFVT2R42.mjs → chunk-CYXJGOQH.mjs} +904 -206
- package/dist/{chunk-ANBMT5AW.mjs → chunk-GXKQCXIB.mjs} +470 -228
- package/dist/chunk-IW654Z3M.mjs +1108 -0
- package/dist/{chunk-5LKGCZAW.mjs → chunk-MLP5EDWP.mjs} +167 -178
- package/dist/form-builder/index.d.mts +176 -6
- package/dist/form-builder/index.d.ts +176 -6
- package/dist/form-builder/index.js +604 -365
- package/dist/form-builder/index.mjs +2 -2
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3221 -984
- package/dist/index.mjs +332 -125
- package/dist/response-viewer/index.d.mts +1 -1
- package/dist/response-viewer/index.d.ts +1 -1
- package/dist/response-viewer/index.js +169 -204
- package/dist/response-viewer/index.mjs +2 -2
- package/dist/styles.css +1 -1
- package/dist/templates/index.d.mts +43 -0
- package/dist/templates/index.d.ts +43 -0
- package/dist/templates/index.js +1116 -0
- package/dist/templates/index.mjs +1 -0
- package/dist/theme-editor/index.d.mts +11 -5
- package/dist/theme-editor/index.d.ts +11 -5
- package/dist/theme-editor/index.js +907 -232
- package/dist/theme-editor/index.mjs +2 -2
- package/dist/types-bFHsZT1n.d.mts +217 -0
- package/dist/types-bFHsZT1n.d.ts +217 -0
- package/package.json +23 -11
- package/theme-editor/styles.css +468 -466
- package/dist/index-D19524df.d.mts +0 -387
- package/dist/index-D19524df.d.ts +0 -387
|
@@ -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,31 +8,32 @@ 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
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
business: ALL_FEATURES,
|
|
31
|
-
enterprise: ALL_FEATURES
|
|
32
|
-
};
|
|
33
|
-
function tierHasFeature(tier, featureName) {
|
|
34
|
-
return TIER_FEATURES[tier]?.includes(featureName) ?? false;
|
|
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);
|
|
35
31
|
}
|
|
32
|
+
|
|
33
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
34
|
+
var SelectPrimitive__namespace = /*#__PURE__*/_interopNamespace(SelectPrimitive);
|
|
35
|
+
|
|
36
|
+
// ../license/dist/index.mjs
|
|
36
37
|
var DEV_HOSTNAMES = /* @__PURE__ */ new Set([
|
|
37
38
|
"localhost",
|
|
38
39
|
"127.0.0.1",
|
|
@@ -104,10 +105,11 @@ function isProductionEnvironment() {
|
|
|
104
105
|
}
|
|
105
106
|
return false;
|
|
106
107
|
}
|
|
107
|
-
|
|
108
|
-
var
|
|
108
|
+
typeof process !== "undefined" && process.env?.NEXT_PUBLIC_FCPRO_PING_URL || "https://fieldcraft.dev/api/license/ping";
|
|
109
|
+
var defaultContext = { status: "validating" };
|
|
110
|
+
var LicenseCtx = React.createContext(defaultContext);
|
|
109
111
|
function useLicense() {
|
|
110
|
-
return
|
|
112
|
+
return React.useContext(LicenseCtx);
|
|
111
113
|
}
|
|
112
114
|
function UnlicensedOverlay({ featureName, reason, children }) {
|
|
113
115
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { position: "relative", minHeight: "200px" }, children: [
|
|
@@ -304,7 +306,7 @@ function UnlicensedOverlay({ featureName, reason, children }) {
|
|
|
304
306
|
}
|
|
305
307
|
function requireLicense(Component3, featureName) {
|
|
306
308
|
function LicenseGated(props) {
|
|
307
|
-
const { status
|
|
309
|
+
const { status } = useLicense();
|
|
308
310
|
const isProduction = isProductionEnvironment();
|
|
309
311
|
if (!isProduction) {
|
|
310
312
|
return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
|
|
@@ -312,8 +314,7 @@ function requireLicense(Component3, featureName) {
|
|
|
312
314
|
if (status === "validating") {
|
|
313
315
|
return null;
|
|
314
316
|
}
|
|
315
|
-
|
|
316
|
-
if (isLicensed) {
|
|
317
|
+
if (status === "valid") {
|
|
317
318
|
return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
|
|
318
319
|
}
|
|
319
320
|
let reason = "A valid license is required for production use.";
|
|
@@ -325,8 +326,6 @@ function requireLicense(Component3, featureName) {
|
|
|
325
326
|
reason = "This license key has been revoked. Please contact support or purchase a new license.";
|
|
326
327
|
} else if (status === "domain_mismatch") {
|
|
327
328
|
reason = "This license key is registered to a different domain. Each key can only be used on one production domain. Please purchase a new license for this domain.";
|
|
328
|
-
} else if (!tier || !tierHasFeature(tier, featureName)) {
|
|
329
|
-
reason = "Your license does not include this feature. Please upgrade your plan.";
|
|
330
329
|
}
|
|
331
330
|
return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props }) });
|
|
332
331
|
}
|
|
@@ -335,38 +334,41 @@ function requireLicense(Component3, featureName) {
|
|
|
335
334
|
}
|
|
336
335
|
var MAX_HISTORY = 50;
|
|
337
336
|
function useUndoRedo(currentSchema, setSchema) {
|
|
338
|
-
const historyRef =
|
|
339
|
-
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;
|
|
340
341
|
const canUndo = currentIndex > 0;
|
|
341
342
|
const canRedo = currentIndex < historyRef.current.length - 1;
|
|
342
|
-
const push =
|
|
343
|
+
const push = React.useCallback(
|
|
343
344
|
(schema) => {
|
|
344
|
-
|
|
345
|
+
const idx = currentIndexRef.current;
|
|
346
|
+
historyRef.current = historyRef.current.slice(0, idx + 1);
|
|
345
347
|
historyRef.current.push(schema);
|
|
346
348
|
if (historyRef.current.length > MAX_HISTORY) {
|
|
347
349
|
historyRef.current.shift();
|
|
348
350
|
setCurrentIndex(historyRef.current.length - 1);
|
|
349
351
|
} else {
|
|
350
|
-
setCurrentIndex(
|
|
352
|
+
setCurrentIndex(idx + 1);
|
|
351
353
|
}
|
|
352
354
|
},
|
|
353
|
-
[
|
|
355
|
+
[]
|
|
354
356
|
);
|
|
355
|
-
const undo =
|
|
357
|
+
const undo = React.useCallback(() => {
|
|
356
358
|
if (currentIndex > 0) {
|
|
357
359
|
const newIndex = currentIndex - 1;
|
|
358
360
|
setCurrentIndex(newIndex);
|
|
359
361
|
setSchema(historyRef.current[newIndex]);
|
|
360
362
|
}
|
|
361
363
|
}, [currentIndex, setSchema]);
|
|
362
|
-
const redo =
|
|
364
|
+
const redo = React.useCallback(() => {
|
|
363
365
|
if (currentIndex < historyRef.current.length - 1) {
|
|
364
366
|
const newIndex = currentIndex + 1;
|
|
365
367
|
setCurrentIndex(newIndex);
|
|
366
368
|
setSchema(historyRef.current[newIndex]);
|
|
367
369
|
}
|
|
368
370
|
}, [currentIndex, setSchema]);
|
|
369
|
-
const clear =
|
|
371
|
+
const clear = React.useCallback(() => {
|
|
370
372
|
historyRef.current = [currentSchema];
|
|
371
373
|
setCurrentIndex(0);
|
|
372
374
|
}, [currentSchema]);
|
|
@@ -595,16 +597,16 @@ function findSection(schema, sectionId) {
|
|
|
595
597
|
|
|
596
598
|
// src/form-builder/hooks/use-builder-state.ts
|
|
597
599
|
function useBuilderState(initialSchema) {
|
|
598
|
-
const [schema, setSchema] =
|
|
599
|
-
const [selectedItem, setSelectedItem] =
|
|
600
|
-
const [isDirty, setIsDirty] =
|
|
601
|
-
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);
|
|
602
604
|
schemaRef.current = schema;
|
|
603
605
|
const undoRedo = useUndoRedo(schema, (newSchema) => {
|
|
604
606
|
setSchema(newSchema);
|
|
605
607
|
setIsDirty(true);
|
|
606
608
|
});
|
|
607
|
-
const updateSchema =
|
|
609
|
+
const updateSchema = React.useCallback(
|
|
608
610
|
(newSchema) => {
|
|
609
611
|
setSchema(newSchema);
|
|
610
612
|
undoRedo.push(newSchema);
|
|
@@ -612,20 +614,20 @@ function useBuilderState(initialSchema) {
|
|
|
612
614
|
},
|
|
613
615
|
[undoRedo]
|
|
614
616
|
);
|
|
615
|
-
const applyMutation =
|
|
617
|
+
const applyMutation = React.useCallback(
|
|
616
618
|
(mutate) => {
|
|
617
619
|
const result = mutate(schemaRef.current);
|
|
618
620
|
updateSchema(result);
|
|
619
621
|
},
|
|
620
622
|
[updateSchema]
|
|
621
623
|
);
|
|
622
|
-
const addSection2 =
|
|
624
|
+
const addSection2 = React.useCallback(
|
|
623
625
|
(section, index) => {
|
|
624
626
|
applyMutation((s) => addSection(s, section, index));
|
|
625
627
|
},
|
|
626
628
|
[applyMutation]
|
|
627
629
|
);
|
|
628
|
-
const removeSection2 =
|
|
630
|
+
const removeSection2 = React.useCallback(
|
|
629
631
|
(sectionId) => {
|
|
630
632
|
applyMutation((s) => removeSection(s, sectionId));
|
|
631
633
|
setSelectedItem((prev) => {
|
|
@@ -635,31 +637,31 @@ function useBuilderState(initialSchema) {
|
|
|
635
637
|
},
|
|
636
638
|
[applyMutation]
|
|
637
639
|
);
|
|
638
|
-
const updateSection2 =
|
|
640
|
+
const updateSection2 = React.useCallback(
|
|
639
641
|
(sectionId, updates) => {
|
|
640
642
|
applyMutation((s) => updateSection(s, sectionId, updates));
|
|
641
643
|
},
|
|
642
644
|
[applyMutation]
|
|
643
645
|
);
|
|
644
|
-
const moveSection2 =
|
|
646
|
+
const moveSection2 = React.useCallback(
|
|
645
647
|
(sectionId, newIndex) => {
|
|
646
648
|
applyMutation((s) => moveSection(s, sectionId, newIndex));
|
|
647
649
|
},
|
|
648
650
|
[applyMutation]
|
|
649
651
|
);
|
|
650
|
-
const duplicateSection2 =
|
|
652
|
+
const duplicateSection2 = React.useCallback(
|
|
651
653
|
(sectionId) => {
|
|
652
654
|
applyMutation((s) => duplicateSection(s, sectionId));
|
|
653
655
|
},
|
|
654
656
|
[applyMutation]
|
|
655
657
|
);
|
|
656
|
-
const addQuestion2 =
|
|
658
|
+
const addQuestion2 = React.useCallback(
|
|
657
659
|
(sectionId, question, index) => {
|
|
658
660
|
applyMutation((s) => addQuestion(s, sectionId, question, index));
|
|
659
661
|
},
|
|
660
662
|
[applyMutation]
|
|
661
663
|
);
|
|
662
|
-
const removeQuestion2 =
|
|
664
|
+
const removeQuestion2 = React.useCallback(
|
|
663
665
|
(sectionId, questionId) => {
|
|
664
666
|
applyMutation((s) => removeQuestion(s, sectionId, questionId));
|
|
665
667
|
setSelectedItem((prev) => {
|
|
@@ -671,34 +673,34 @@ function useBuilderState(initialSchema) {
|
|
|
671
673
|
},
|
|
672
674
|
[applyMutation]
|
|
673
675
|
);
|
|
674
|
-
const updateQuestion2 =
|
|
676
|
+
const updateQuestion2 = React.useCallback(
|
|
675
677
|
(sectionId, questionId, updates) => {
|
|
676
678
|
applyMutation((s) => updateQuestion(s, sectionId, questionId, updates));
|
|
677
679
|
},
|
|
678
680
|
[applyMutation]
|
|
679
681
|
);
|
|
680
|
-
const moveQuestion2 =
|
|
682
|
+
const moveQuestion2 = React.useCallback(
|
|
681
683
|
(sectionId, questionId, targetSectionId, newIndex) => {
|
|
682
684
|
applyMutation((s) => moveQuestion(s, sectionId, questionId, targetSectionId, newIndex));
|
|
683
685
|
},
|
|
684
686
|
[applyMutation]
|
|
685
687
|
);
|
|
686
|
-
const duplicateQuestion2 =
|
|
688
|
+
const duplicateQuestion2 = React.useCallback(
|
|
687
689
|
(sectionId, questionId) => {
|
|
688
690
|
applyMutation((s) => duplicateQuestion(s, sectionId, questionId));
|
|
689
691
|
},
|
|
690
692
|
[applyMutation]
|
|
691
693
|
);
|
|
692
|
-
const selectQuestion =
|
|
694
|
+
const selectQuestion = React.useCallback((sectionId, questionId) => {
|
|
693
695
|
setSelectedItem({ type: "question", sectionId, questionId });
|
|
694
696
|
}, []);
|
|
695
|
-
const selectSection =
|
|
697
|
+
const selectSection = React.useCallback((sectionId) => {
|
|
696
698
|
setSelectedItem({ type: "section", sectionId });
|
|
697
699
|
}, []);
|
|
698
|
-
const clearSelection =
|
|
700
|
+
const clearSelection = React.useCallback(() => {
|
|
699
701
|
setSelectedItem(null);
|
|
700
702
|
}, []);
|
|
701
|
-
const resetSchema =
|
|
703
|
+
const resetSchema = React.useCallback(
|
|
702
704
|
(newSchema) => {
|
|
703
705
|
setSchema(newSchema);
|
|
704
706
|
undoRedo.clear();
|
|
@@ -707,7 +709,7 @@ function useBuilderState(initialSchema) {
|
|
|
707
709
|
},
|
|
708
710
|
[undoRedo]
|
|
709
711
|
);
|
|
710
|
-
const markClean =
|
|
712
|
+
const markClean = React.useCallback(() => {
|
|
711
713
|
setIsDirty(false);
|
|
712
714
|
}, []);
|
|
713
715
|
return {
|
|
@@ -968,7 +970,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
968
970
|
category: "advanced",
|
|
969
971
|
icon: "ListPlus",
|
|
970
972
|
description: "Repeatable group of fields",
|
|
971
|
-
defaultConfig: { type: "repeater", fields: [],
|
|
973
|
+
defaultConfig: { type: "repeater", fields: [], minEntries: 1, maxEntries: 10 }
|
|
972
974
|
},
|
|
973
975
|
likert: {
|
|
974
976
|
type: "likert",
|
|
@@ -979,13 +981,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
979
981
|
requiresOptions: true,
|
|
980
982
|
defaultConfig: {
|
|
981
983
|
type: "likert",
|
|
982
|
-
|
|
983
|
-
{ label: "Strongly Disagree", value: "1" },
|
|
984
|
-
{ label: "Disagree", value: "2" },
|
|
985
|
-
{ label: "Neutral", value: "3" },
|
|
986
|
-
{ label: "Agree", value: "4" },
|
|
987
|
-
{ label: "Strongly Agree", value: "5" }
|
|
988
|
-
]
|
|
984
|
+
labels: ["Strongly Disagree", "Disagree", "Neutral", "Agree", "Strongly Agree"]
|
|
989
985
|
}
|
|
990
986
|
},
|
|
991
987
|
scoring: {
|
|
@@ -1038,7 +1034,7 @@ var QUESTION_TYPE_INFO = {
|
|
|
1038
1034
|
category: "advanced",
|
|
1039
1035
|
icon: "CreditCard",
|
|
1040
1036
|
description: "Collect payment via Stripe",
|
|
1041
|
-
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
|
|
1037
|
+
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD", serverUrl: "" }
|
|
1042
1038
|
},
|
|
1043
1039
|
// ── Structural ──
|
|
1044
1040
|
section_header: {
|
|
@@ -1185,7 +1181,7 @@ var DEFAULT_PALETTE = [
|
|
|
1185
1181
|
|
|
1186
1182
|
// src/form-builder/hooks/use-drag-drop.ts
|
|
1187
1183
|
function useDragDrop(builderState) {
|
|
1188
|
-
const [activeDragItem, setActiveDragItem] =
|
|
1184
|
+
const [activeDragItem, setActiveDragItem] = React.useState(null);
|
|
1189
1185
|
const sensors = core.useSensors(
|
|
1190
1186
|
core.useSensor(core.MouseSensor, {
|
|
1191
1187
|
activationConstraint: {
|
|
@@ -1235,11 +1231,11 @@ function useDragDrop(builderState) {
|
|
|
1235
1231
|
}
|
|
1236
1232
|
return null;
|
|
1237
1233
|
};
|
|
1238
|
-
const handleDragStart =
|
|
1234
|
+
const handleDragStart = React.useCallback((event) => {
|
|
1239
1235
|
const item = parseDragItem(event.active);
|
|
1240
1236
|
setActiveDragItem(item);
|
|
1241
1237
|
}, []);
|
|
1242
|
-
const handleDragCancel =
|
|
1238
|
+
const handleDragCancel = React.useCallback(() => {
|
|
1243
1239
|
setActiveDragItem(null);
|
|
1244
1240
|
}, []);
|
|
1245
1241
|
const handleDragEnd = (event) => {
|
|
@@ -1409,9 +1405,9 @@ function PaletteItem({ questionType, typeInfo }) {
|
|
|
1409
1405
|
);
|
|
1410
1406
|
}
|
|
1411
1407
|
function QuestionPalette({ questionTypes, palette }) {
|
|
1412
|
-
const [collapsed, setCollapsed] =
|
|
1413
|
-
const [search, setSearch] =
|
|
1414
|
-
const mergedPalette =
|
|
1408
|
+
const [collapsed, setCollapsed] = React.useState({});
|
|
1409
|
+
const [search, setSearch] = React.useState("");
|
|
1410
|
+
const mergedPalette = React.useMemo(
|
|
1415
1411
|
() => palette ? [...DEFAULT_PALETTE, ...palette] : DEFAULT_PALETTE,
|
|
1416
1412
|
[palette]
|
|
1417
1413
|
);
|
|
@@ -1492,13 +1488,13 @@ function QuestionBlock({
|
|
|
1492
1488
|
}) {
|
|
1493
1489
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
1494
1490
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
1495
|
-
const [isEditing, setIsEditing] =
|
|
1496
|
-
const [editValue, setEditValue] =
|
|
1497
|
-
const inputRef =
|
|
1498
|
-
|
|
1491
|
+
const [isEditing, setIsEditing] = React.useState(false);
|
|
1492
|
+
const [editValue, setEditValue] = React.useState(question.label);
|
|
1493
|
+
const inputRef = React.useRef(null);
|
|
1494
|
+
React.useEffect(() => {
|
|
1499
1495
|
if (!isEditing) setEditValue(question.label);
|
|
1500
1496
|
}, [question.label, isEditing]);
|
|
1501
|
-
|
|
1497
|
+
React.useEffect(() => {
|
|
1502
1498
|
if (isEditing && inputRef.current) {
|
|
1503
1499
|
inputRef.current.focus();
|
|
1504
1500
|
inputRef.current.select();
|
|
@@ -1655,7 +1651,7 @@ function ConfirmDialog({ open, title, message, onConfirm, onCancel }) {
|
|
|
1655
1651
|
);
|
|
1656
1652
|
}
|
|
1657
1653
|
function SectionBlock({ section, builderState }) {
|
|
1658
|
-
const [confirmDelete, setConfirmDelete] =
|
|
1654
|
+
const [confirmDelete, setConfirmDelete] = React.useState(false);
|
|
1659
1655
|
const { setNodeRef } = core.useDroppable({
|
|
1660
1656
|
id: `section-end-${section.id}`,
|
|
1661
1657
|
data: { type: "section", sectionId: section.id, index: section.questions.length }
|
|
@@ -1836,30 +1832,71 @@ function FormCanvas({ builderState }) {
|
|
|
1836
1832
|
] })
|
|
1837
1833
|
] }) });
|
|
1838
1834
|
}
|
|
1839
|
-
var
|
|
1840
|
-
|
|
1841
|
-
|
|
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" }) }),
|
|
1842
1865
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1843
|
-
|
|
1866
|
+
SelectPrimitive__namespace.Viewport,
|
|
1844
1867
|
{
|
|
1845
|
-
ref,
|
|
1846
1868
|
className: cn(
|
|
1847
|
-
"
|
|
1848
|
-
|
|
1869
|
+
"p-1",
|
|
1870
|
+
position === "popper" && "h-[var(--radix-select-trigger-height)] w-full min-w-[var(--radix-select-trigger-width)]"
|
|
1849
1871
|
),
|
|
1850
|
-
...props,
|
|
1851
1872
|
children
|
|
1852
1873
|
}
|
|
1853
1874
|
),
|
|
1854
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1855
|
-
]
|
|
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
|
+
]
|
|
1856
1877
|
}
|
|
1857
|
-
);
|
|
1858
|
-
|
|
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";
|
|
1859
1896
|
function useConfigUpdater(question, onUpdate) {
|
|
1860
|
-
return (
|
|
1897
|
+
return (updates) => {
|
|
1861
1898
|
const current = question.config ?? {};
|
|
1862
|
-
onUpdate({ config: { ...current, type: question.type,
|
|
1899
|
+
onUpdate({ config: { ...current, type: question.type, ...updates } });
|
|
1863
1900
|
};
|
|
1864
1901
|
}
|
|
1865
1902
|
function QuestionConfigEditor({ question, onUpdate }) {
|
|
@@ -1869,226 +1906,274 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
1869
1906
|
// ── Text ──
|
|
1870
1907
|
case "short_text":
|
|
1871
1908
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Text Settings", children: [
|
|
1872
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "255", onChange: (v) => updateConfig(
|
|
1873
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Input Type", value: config.inputType ?? "text", options: [{ label: "Text", value: "text" }, { label: "Password", value: "password" }], onChange: (v) => updateConfig(
|
|
1874
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig(
|
|
1875
|
-
/* @__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 }) })
|
|
1876
1913
|
] });
|
|
1877
1914
|
case "long_text":
|
|
1878
1915
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Text Settings", children: [
|
|
1879
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Length", value: config.maxLength, placeholder: "No limit", onChange: (v) => updateConfig(
|
|
1880
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Rows", value: config.rows, placeholder: "4", onChange: (v) => updateConfig(
|
|
1881
|
-
/* @__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 }) })
|
|
1882
1919
|
] });
|
|
1883
1920
|
case "legal_name":
|
|
1884
1921
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Name Fields", children: [
|
|
1885
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Middle Name", checked: !!config.showMiddleName, onChange: (v) => updateConfig(
|
|
1886
|
-
/* @__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 }) })
|
|
1887
1924
|
] });
|
|
1888
1925
|
// ── Numeric ──
|
|
1889
1926
|
case "number":
|
|
1890
1927
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Number Settings", children: [
|
|
1891
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, onChange: (v) => updateConfig(
|
|
1892
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, onChange: (v) => updateConfig(
|
|
1893
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1894
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "0", onChange: (v) => updateConfig(
|
|
1895
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig(
|
|
1896
|
-
/* @__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 }) })
|
|
1897
1934
|
] });
|
|
1898
1935
|
case "slider":
|
|
1899
1936
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Slider Settings", children: [
|
|
1900
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "0", onChange: (v) => updateConfig(
|
|
1901
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "100", onChange: (v) => updateConfig(
|
|
1902
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1903
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Value", checked: !!config.showValue, onChange: (v) => updateConfig(
|
|
1904
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig(
|
|
1905
|
-
/* @__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 }) })
|
|
1906
1943
|
] });
|
|
1907
1944
|
case "rating":
|
|
1908
1945
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rating Settings", children: [
|
|
1909
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Stars", value: config.max, placeholder: "5", onChange: (v) => updateConfig(
|
|
1910
|
-
/* @__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(
|
|
1911
|
-
/* @__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 }) })
|
|
1912
1949
|
] });
|
|
1913
1950
|
case "nps":
|
|
1914
1951
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "NPS Settings", children: [
|
|
1915
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Low Label", value: config.lowLabel ?? "Not likely", onChange: (v) => updateConfig(
|
|
1916
|
-
/* @__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 }) })
|
|
1917
1954
|
] });
|
|
1918
1955
|
case "opinion_scale":
|
|
1919
1956
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Scale Settings", children: [
|
|
1920
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min", value: config.min, placeholder: "1", onChange: (v) => updateConfig(
|
|
1921
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max", value: config.max, placeholder: "5", onChange: (v) => updateConfig(
|
|
1922
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig(
|
|
1923
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, onChange: (v) => updateConfig(
|
|
1924
|
-
/* @__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 }) })
|
|
1925
1962
|
] });
|
|
1926
1963
|
case "likert":
|
|
1927
|
-
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 }) }) });
|
|
1928
1965
|
// ── Selection ──
|
|
1929
1966
|
case "single_select":
|
|
1930
1967
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Select Settings", children: [
|
|
1931
|
-
/* @__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(
|
|
1932
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1933
|
-
!!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 }) })
|
|
1934
1971
|
] });
|
|
1935
1972
|
case "multi_select":
|
|
1936
1973
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Multi-Select Settings", children: [
|
|
1937
|
-
/* @__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(
|
|
1938
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Selections", value: config.minSelections, onChange: (v) => updateConfig(
|
|
1939
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Selections", value: config.maxSelections, onChange: (v) => updateConfig(
|
|
1940
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1941
|
-
!!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 }) })
|
|
1942
1979
|
] });
|
|
1943
1980
|
case "dropdown":
|
|
1944
1981
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Dropdown Settings", children: [
|
|
1945
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Searchable", checked: !!config.searchable, onChange: (v) => updateConfig(
|
|
1946
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Other", checked: !!config.allowOther, onChange: (v) => updateConfig(
|
|
1947
|
-
/* @__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 }) })
|
|
1948
1985
|
] });
|
|
1949
1986
|
case "boolean":
|
|
1950
1987
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Yes/No Settings", children: [
|
|
1951
|
-
/* @__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(
|
|
1952
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "True Label", value: config.trueLabel ?? "Yes", onChange: (v) => updateConfig(
|
|
1953
|
-
/* @__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 }) })
|
|
1954
1991
|
] });
|
|
1955
1992
|
case "country_select":
|
|
1956
1993
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Country Settings", children: [
|
|
1957
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Flags", checked: config.showFlags !== false, onChange: (v) => updateConfig(
|
|
1958
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Priority Countries", value: config.priorityCountries?.join(", "), placeholder: "e.g. US, GB, CA", onChange: (v) => updateConfig(
|
|
1959
|
-
/* @__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 }) })
|
|
1960
1997
|
] });
|
|
1961
1998
|
// ── Date/Time ──
|
|
1962
1999
|
case "date":
|
|
1963
2000
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Date Settings", children: [
|
|
1964
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1965
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1966
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Past Dates", checked: !!config.disablePast, onChange: (v) => updateConfig(
|
|
1967
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Disable Future Dates", checked: !!config.disableFuture, onChange: (v) => updateConfig(
|
|
1968
|
-
/* @__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 }) })
|
|
1969
2006
|
] });
|
|
1970
2007
|
case "time":
|
|
1971
2008
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Time Settings", children: [
|
|
1972
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Format", value: config.format ?? "12h", options: [{ label: "12 Hour", value: "12h" }, { label: "24 Hour", value: "24h" }], onChange: (v) => updateConfig(
|
|
1973
|
-
/* @__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 }) })
|
|
1974
2011
|
] });
|
|
1975
2012
|
case "date_range":
|
|
1976
2013
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Date Range Settings", children: [
|
|
1977
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Date", value: config.minDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1978
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Date", value: config.maxDate, placeholder: "YYYY-MM-DD", onChange: (v) => updateConfig(
|
|
1979
|
-
/* @__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 }) })
|
|
1980
2017
|
] });
|
|
1981
|
-
case "appointment":
|
|
2018
|
+
case "appointment": {
|
|
2019
|
+
const appointmentMode = typeof config.embedUrl === "string" ? "embed" : typeof config.slotsUrl === "string" ? "url" : "static";
|
|
1982
2020
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Appointment Settings", children: [
|
|
1983
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1984
|
-
|
|
1985
|
-
|
|
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
|
+
)
|
|
1986
2070
|
] });
|
|
2071
|
+
}
|
|
1987
2072
|
// ── Media ──
|
|
1988
2073
|
case "file_upload":
|
|
1989
2074
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Upload Settings", children: [
|
|
1990
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Files", value: config.maxFiles ?? 1, onChange: (v) => updateConfig(
|
|
1991
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb ?? 10, onChange: (v) => updateConfig(
|
|
1992
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Accepted Types", value: config.accept?.join(", "), placeholder: "e.g. .pdf, .jpg, .png", onChange: (v) => updateConfig(
|
|
1993
|
-
/* @__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 }) })
|
|
1994
2079
|
] });
|
|
1995
2080
|
case "signature":
|
|
1996
2081
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Signature Settings", children: [
|
|
1997
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Pen Color", value: config.penColor, placeholder: "#000000", onChange: (v) => updateConfig(
|
|
1998
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Background", value: config.backgroundColor, placeholder: "#ffffff", onChange: (v) => updateConfig(
|
|
1999
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Width (px)", value: config.width, onChange: (v) => updateConfig(
|
|
2000
|
-
/* @__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 }) })
|
|
2001
2086
|
] });
|
|
2002
2087
|
case "image_capture":
|
|
2003
2088
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Camera Settings", children: [
|
|
2004
|
-
/* @__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(
|
|
2005
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb, onChange: (v) => updateConfig(
|
|
2006
|
-
/* @__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 }) })
|
|
2007
2092
|
] });
|
|
2008
2093
|
// ── Content & Visual ──
|
|
2009
2094
|
case "welcome-screen":
|
|
2010
2095
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Welcome Screen", children: [
|
|
2011
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Welcome", onChange: (v) => updateConfig(
|
|
2012
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description, onChange: (v) => updateConfig(
|
|
2013
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Button Text", value: config.buttonText ?? "Start", onChange: (v) => updateConfig(
|
|
2014
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2015
|
-
/* @__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 }) })
|
|
2016
2101
|
] });
|
|
2017
2102
|
case "thank-you-screen":
|
|
2018
2103
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Thank You Screen", children: [
|
|
2019
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Heading", value: config.heading ?? "Thank You!", onChange: (v) => updateConfig(
|
|
2020
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Description", value: config.description ?? "", onChange: (v) => updateConfig(
|
|
2021
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Image URL", value: config.imageUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2022
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Redirect URL", value: config.redirectUrl, placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2023
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Redirect Delay (s)", value: config.redirectDelay, placeholder: "0", onChange: (v) => updateConfig(
|
|
2024
|
-
/* @__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 }) })
|
|
2025
2110
|
] });
|
|
2026
2111
|
case "rich-text":
|
|
2027
2112
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rich Text", children: [
|
|
2028
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 6, onChange: (v) => updateConfig(
|
|
2029
|
-
/* @__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 }) })
|
|
2030
2115
|
] });
|
|
2031
2116
|
case "image":
|
|
2032
2117
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Image Settings", children: [
|
|
2033
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "https://...", onChange: (v) => updateConfig(
|
|
2034
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Alt Text", value: config.alt ?? "", onChange: (v) => updateConfig(
|
|
2035
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Caption", value: config.caption, onChange: (v) => updateConfig(
|
|
2036
|
-
/* @__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(
|
|
2037
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 300px", onChange: (v) => updateConfig(
|
|
2038
|
-
/* @__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 }) })
|
|
2039
2124
|
] });
|
|
2040
2125
|
case "video":
|
|
2041
2126
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Video Settings", children: [
|
|
2042
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Source URL", value: config.src ?? "", placeholder: "YouTube/Vimeo URL", onChange: (v) => updateConfig(
|
|
2043
|
-
/* @__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(
|
|
2044
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Autoplay", checked: !!config.autoplay, onChange: (v) => updateConfig(
|
|
2045
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Muted", checked: !!config.muted, onChange: (v) => updateConfig(
|
|
2046
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Width", value: config.width, placeholder: "e.g. 100% or 640px", onChange: (v) => updateConfig(
|
|
2047
|
-
/* @__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 }) })
|
|
2048
2133
|
] });
|
|
2049
2134
|
case "divider":
|
|
2050
2135
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Divider Settings", children: [
|
|
2051
|
-
/* @__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(
|
|
2052
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Color", value: config.color, placeholder: "#e5e7eb", onChange: (v) => updateConfig(
|
|
2053
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Thickness (px)", value: config.thickness, placeholder: "1", onChange: (v) => updateConfig(
|
|
2054
|
-
/* @__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 }) })
|
|
2055
2140
|
] });
|
|
2056
2141
|
case "spacer":
|
|
2057
|
-
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 }) }) });
|
|
2058
2143
|
// ── Structural ──
|
|
2059
2144
|
case "section_header":
|
|
2060
2145
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Header Settings", children: [
|
|
2061
|
-
/* @__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(
|
|
2062
|
-
/* @__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 }) })
|
|
2063
2148
|
] });
|
|
2064
2149
|
case "info_block":
|
|
2065
2150
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Info Block", children: [
|
|
2066
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Content", value: config.content ?? "", rows: 4, onChange: (v) => updateConfig(
|
|
2067
|
-
/* @__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 }) })
|
|
2068
2153
|
] });
|
|
2069
2154
|
case "page_break":
|
|
2070
|
-
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 }) }) });
|
|
2071
2156
|
case "consent":
|
|
2072
2157
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Consent Settings", children: [
|
|
2073
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextareaField, { label: "Consent Text", value: config.text ?? "", rows: 4, onChange: (v) => updateConfig(
|
|
2074
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Checkbox Label", value: config.checkboxLabel ?? "I agree", onChange: (v) => updateConfig(
|
|
2075
|
-
/* @__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 }) })
|
|
2076
2161
|
] });
|
|
2077
2162
|
// ── Advanced ──
|
|
2078
2163
|
case "matrix":
|
|
2079
2164
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Matrix Settings", children: [
|
|
2080
|
-
/* @__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(
|
|
2081
|
-
/* @__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(
|
|
2082
|
-
/* @__PURE__ */ jsxRuntime.jsx(MatrixItemsEditor, { label: "Rows", items: config.rows ?? [], onChange: (v) => updateConfig(
|
|
2083
|
-
/* @__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 }) })
|
|
2084
2169
|
] });
|
|
2085
2170
|
case "repeater":
|
|
2086
2171
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Repeater Settings", children: [
|
|
2087
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Entries", value: config.minEntries, placeholder: "1", onChange: (v) => updateConfig(
|
|
2088
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Entries", value: config.maxEntries, onChange: (v) => updateConfig(
|
|
2089
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Default Entries", value: config.defaultEntries, placeholder: "1", onChange: (v) => updateConfig(
|
|
2090
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Add Button Label", value: config.addLabel, placeholder: "Add Entry", onChange: (v) => updateConfig(
|
|
2091
|
-
/* @__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 }) }),
|
|
2092
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." })
|
|
2093
2178
|
] });
|
|
2094
2179
|
case "address": {
|
|
@@ -2102,9 +2187,9 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2102
2187
|
];
|
|
2103
2188
|
const activeFields = config.fields ?? ["street", "city", "state", "zip", "country"];
|
|
2104
2189
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Address Settings", children: [
|
|
2105
|
-
/* @__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(
|
|
2106
|
-
config.provider !== "none" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "API Key", value: config.apiKey, placeholder: "Provider API key", onChange: (v) => updateConfig(
|
|
2107
|
-
/* @__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 }) }),
|
|
2108
2193
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2109
2194
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-2 block", children: "Fields" }),
|
|
2110
2195
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2114,7 +2199,7 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2114
2199
|
checked: activeFields.includes(f.value),
|
|
2115
2200
|
onChange: (checked) => {
|
|
2116
2201
|
const next = checked ? [...activeFields, f.value] : activeFields.filter((v) => v !== f.value);
|
|
2117
|
-
updateConfig(
|
|
2202
|
+
updateConfig({ fields: next.length > 0 ? next : void 0 });
|
|
2118
2203
|
}
|
|
2119
2204
|
},
|
|
2120
2205
|
f.value
|
|
@@ -2124,41 +2209,47 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2124
2209
|
}
|
|
2125
2210
|
case "payment":
|
|
2126
2211
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Payment Settings", children: [
|
|
2127
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Provider", value: config.provider ?? "stripe", options: [{ label: "Stripe", value: "stripe" }, { label: "PayPal", value: "paypal" }], onChange: (v) => updateConfig(
|
|
2128
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Public Key", value: config.publicKey ?? "", placeholder: "Provider public/client key", onChange: (v) => updateConfig(
|
|
2129
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2130
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
2131
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2132
|
-
/* @__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 }) })
|
|
2133
2220
|
] });
|
|
2134
2221
|
case "calculated":
|
|
2135
2222
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Calculated Field", children: [
|
|
2136
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Expression", value: config.expression ?? "", placeholder: "e.g. {q1} + {q2}", onChange: (v) => updateConfig(
|
|
2137
|
-
/* @__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(
|
|
2138
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Decimal Places", value: config.decimalPlaces, placeholder: "2", onChange: (v) => updateConfig(
|
|
2139
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, onChange: (v) => updateConfig(
|
|
2140
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, onChange: (v) => updateConfig(
|
|
2141
|
-
/* @__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 }) })
|
|
2142
2229
|
] });
|
|
2143
2230
|
case "hidden":
|
|
2144
2231
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Hidden Field", children: [
|
|
2145
|
-
/* @__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(
|
|
2146
|
-
config.source === "static" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Value", value: config.defaultValue, onChange: (v) => updateConfig(
|
|
2147
|
-
config.source === "url_param" && /* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Parameter Name", value: config.paramName, placeholder: "e.g. utm_source", onChange: (v) => updateConfig(
|
|
2148
|
-
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 }) })
|
|
2149
2236
|
] });
|
|
2150
2237
|
case "scoring":
|
|
2151
2238
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Scoring Settings", children: [
|
|
2152
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Score", checked: !!config.showScore, onChange: (v) => updateConfig(
|
|
2153
|
-
/* @__PURE__ */ jsxRuntime.jsx(ScoringOptionsEditor, { options: config.options ?? [], onChange: (v) => updateConfig(
|
|
2154
|
-
/* @__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 }) })
|
|
2155
2242
|
] });
|
|
2156
2243
|
case "ranking":
|
|
2157
|
-
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
|
+
] });
|
|
2158
2250
|
// Types with no additional config
|
|
2159
2251
|
case "email":
|
|
2160
2252
|
case "phone":
|
|
2161
|
-
case "phone_international":
|
|
2162
2253
|
case "url":
|
|
2163
2254
|
return null;
|
|
2164
2255
|
default:
|
|
@@ -2250,7 +2341,10 @@ function SelectField({
|
|
|
2250
2341
|
}) {
|
|
2251
2342
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2252
2343
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
2253
|
-
/* @__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
|
+
] })
|
|
2254
2348
|
] });
|
|
2255
2349
|
}
|
|
2256
2350
|
function LikertLabelsEditor({
|
|
@@ -2396,6 +2490,59 @@ function ScoringOptionsEditor({
|
|
|
2396
2490
|
] }, index)) })
|
|
2397
2491
|
] });
|
|
2398
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
|
+
}
|
|
2399
2546
|
function ScoreRangesEditor({
|
|
2400
2547
|
ranges,
|
|
2401
2548
|
onChange
|
|
@@ -2428,6 +2575,26 @@ function ScoreRangesEditor({
|
|
|
2428
2575
|
] }, index)) })
|
|
2429
2576
|
] });
|
|
2430
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";
|
|
2431
2598
|
var RULE_TYPES = [
|
|
2432
2599
|
{ value: "minLength", label: "Min Length", description: "Minimum character count" },
|
|
2433
2600
|
{ value: "maxLength", label: "Max Length", description: "Maximum character count" },
|
|
@@ -2832,7 +2999,7 @@ function FormSettingsPanel({ schema, onUpdate }) {
|
|
|
2832
2999
|
];
|
|
2833
3000
|
const displayMode = settings.displayMode ?? "stepped";
|
|
2834
3001
|
const effectiveDisplayMode = hasConditions && displayMode === "classic" ? "stepped" : displayMode;
|
|
2835
|
-
|
|
3002
|
+
React.useEffect(() => {
|
|
2836
3003
|
if (effectiveDisplayMode !== displayMode) {
|
|
2837
3004
|
onUpdate({ ...schema, settings: { ...settings, displayMode: effectiveDisplayMode } });
|
|
2838
3005
|
}
|
|
@@ -2989,7 +3156,7 @@ function SettingsSelect({
|
|
|
2989
3156
|
}
|
|
2990
3157
|
function PropertiesPanel({ builderState }) {
|
|
2991
3158
|
const { schema, selectedItem } = builderState;
|
|
2992
|
-
const [showSettings, setShowSettings] =
|
|
3159
|
+
const [showSettings, setShowSettings] = React.useState(false);
|
|
2993
3160
|
if (showSettings) {
|
|
2994
3161
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-80 h-full border-l border-border bg-card flex flex-col", children: [
|
|
2995
3162
|
/* @__PURE__ */ jsxRuntime.jsx(PanelHeader, { title: "Form Settings", onClose: () => setShowSettings(false) }),
|
|
@@ -3064,11 +3231,11 @@ function SectionProperties({ section, onUpdate, onClose, onOpenSettings }) {
|
|
|
3064
3231
|
] });
|
|
3065
3232
|
}
|
|
3066
3233
|
function QuestionProperties({ question, sectionId, builderState, onClose, onOpenSettings }) {
|
|
3067
|
-
const [activeTab, setActiveTab] =
|
|
3234
|
+
const [activeTab, setActiveTab] = React.useState("basic");
|
|
3068
3235
|
const typeInfo = QUESTION_TYPE_INFO[question.type];
|
|
3069
3236
|
const IconComponent = typeInfo ? getIcon(typeInfo.icon) : null;
|
|
3070
3237
|
const hasOptions = typeInfo?.requiresOptions || question.options && question.options.length > 0;
|
|
3071
|
-
const updateQuestion2 =
|
|
3238
|
+
const updateQuestion2 = React.useCallback(
|
|
3072
3239
|
(updates) => {
|
|
3073
3240
|
builderState.updateQuestion(sectionId, question.id, updates);
|
|
3074
3241
|
},
|
|
@@ -3243,7 +3410,7 @@ function FieldGroup({ label, children }) {
|
|
|
3243
3410
|
children
|
|
3244
3411
|
] });
|
|
3245
3412
|
}
|
|
3246
|
-
var PreviewErrorBoundary = class extends
|
|
3413
|
+
var PreviewErrorBoundary = class extends React.Component {
|
|
3247
3414
|
state = { error: null };
|
|
3248
3415
|
static getDerivedStateFromError(error) {
|
|
3249
3416
|
return { error };
|
|
@@ -3304,15 +3471,15 @@ function errorsToMarkers(errors) {
|
|
|
3304
3471
|
source: "FieldCraft Schema Validator"
|
|
3305
3472
|
}));
|
|
3306
3473
|
}
|
|
3307
|
-
var Editor =
|
|
3474
|
+
var Editor = React.lazy(() => import('@monaco-editor/react').then((m) => ({ default: m.default })));
|
|
3308
3475
|
function MonacoWrapper({ value, onChange, errors }) {
|
|
3309
|
-
const editorRef =
|
|
3310
|
-
const monacoRef =
|
|
3476
|
+
const editorRef = React.useRef(null);
|
|
3477
|
+
const monacoRef = React.useRef(null);
|
|
3311
3478
|
const handleMount = (editor, monaco) => {
|
|
3312
3479
|
editorRef.current = editor;
|
|
3313
3480
|
monacoRef.current = monaco;
|
|
3314
3481
|
};
|
|
3315
|
-
|
|
3482
|
+
React.useEffect(() => {
|
|
3316
3483
|
const editor = editorRef.current;
|
|
3317
3484
|
const monaco = monacoRef.current;
|
|
3318
3485
|
if (!editor || !monaco) return;
|
|
@@ -3344,14 +3511,14 @@ function MonacoWrapper({ value, onChange, errors }) {
|
|
|
3344
3511
|
);
|
|
3345
3512
|
}
|
|
3346
3513
|
function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
3347
|
-
const handleChange =
|
|
3514
|
+
const handleChange = React.useCallback(
|
|
3348
3515
|
(newValue) => {
|
|
3349
3516
|
onChange(newValue);
|
|
3350
3517
|
onValidate(newValue);
|
|
3351
3518
|
},
|
|
3352
3519
|
[onChange, onValidate]
|
|
3353
3520
|
);
|
|
3354
|
-
const handleFormat =
|
|
3521
|
+
const handleFormat = React.useCallback(() => {
|
|
3355
3522
|
try {
|
|
3356
3523
|
const formatted = JSON.stringify(JSON.parse(value), null, 2);
|
|
3357
3524
|
onChange(formatted);
|
|
@@ -3384,7 +3551,7 @@ function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
|
3384
3551
|
)
|
|
3385
3552
|
] }),
|
|
3386
3553
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3387
|
-
|
|
3554
|
+
React.Suspense,
|
|
3388
3555
|
{
|
|
3389
3556
|
fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-sm text-muted-foreground", children: "Loading editor..." }),
|
|
3390
3557
|
children: /* @__PURE__ */ jsxRuntime.jsx(MonacoWrapper, { value, onChange: handleChange, errors })
|
|
@@ -3583,7 +3750,7 @@ function SectionNodeInner({ data }) {
|
|
|
3583
3750
|
const d = data;
|
|
3584
3751
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
3585
3752
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group", style: { borderColor: color }, children: [
|
|
3586
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3753
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle fc-flow-handle--section" }),
|
|
3587
3754
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group__header", style: { background: color }, children: [
|
|
3588
3755
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__label", children: d.label.length > 30 ? d.label.slice(0, 30) + "\u2026" : d.label }),
|
|
3589
3756
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "fc-flow-section-group__meta", children: [
|
|
@@ -3594,10 +3761,10 @@ function SectionNodeInner({ data }) {
|
|
|
3594
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" })
|
|
3595
3762
|
] })
|
|
3596
3763
|
] }),
|
|
3597
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3764
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle fc-flow-handle--section" })
|
|
3598
3765
|
] });
|
|
3599
3766
|
}
|
|
3600
|
-
var SectionNode =
|
|
3767
|
+
var SectionNode = React.memo(SectionNodeInner);
|
|
3601
3768
|
function FieldNodeInner({ data }) {
|
|
3602
3769
|
const d = data;
|
|
3603
3770
|
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
@@ -3610,18 +3777,18 @@ function FieldNodeInner({ data }) {
|
|
|
3610
3777
|
borderWidth: d.hasCondition ? 2 : 1
|
|
3611
3778
|
},
|
|
3612
3779
|
children: [
|
|
3613
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3780
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "target", position: react.Position.Left, className: "fc-flow-handle" }),
|
|
3614
3781
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-field__content", children: [
|
|
3615
3782
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__label", children: d.label.length > 26 ? d.label.slice(0, 26) + "\u2026" : d.label }),
|
|
3616
3783
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__type", children: d.fieldType })
|
|
3617
3784
|
] }),
|
|
3618
3785
|
d.hasCondition && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fc-flow-badge", style: { background: color }, title: "Has showIf condition", children: "?" }),
|
|
3619
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3786
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Handle, { type: "source", position: react.Position.Right, className: "fc-flow-handle" })
|
|
3620
3787
|
]
|
|
3621
3788
|
}
|
|
3622
3789
|
);
|
|
3623
3790
|
}
|
|
3624
|
-
var FieldNode =
|
|
3791
|
+
var FieldNode = React.memo(FieldNodeInner);
|
|
3625
3792
|
var logicFlowNodeTypes = {
|
|
3626
3793
|
sectionNode: SectionNode,
|
|
3627
3794
|
fieldNode: FieldNode
|
|
@@ -3639,7 +3806,7 @@ function ConditionEdgeInner({
|
|
|
3639
3806
|
data,
|
|
3640
3807
|
markerEnd
|
|
3641
3808
|
}) {
|
|
3642
|
-
const [edgePath, labelX, labelY] = react
|
|
3809
|
+
const [edgePath, labelX, labelY] = react.getBezierPath({
|
|
3643
3810
|
sourceX,
|
|
3644
3811
|
sourceY,
|
|
3645
3812
|
sourcePosition,
|
|
@@ -3650,7 +3817,7 @@ function ConditionEdgeInner({
|
|
|
3650
3817
|
const isJump = data?.edgeType === "onExit";
|
|
3651
3818
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3652
3819
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3653
|
-
react
|
|
3820
|
+
react.BaseEdge,
|
|
3654
3821
|
{
|
|
3655
3822
|
id,
|
|
3656
3823
|
path: edgePath,
|
|
@@ -3663,7 +3830,7 @@ function ConditionEdgeInner({
|
|
|
3663
3830
|
}
|
|
3664
3831
|
}
|
|
3665
3832
|
),
|
|
3666
|
-
label && /* @__PURE__ */ jsxRuntime.jsx(react
|
|
3833
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(react.EdgeLabelRenderer, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3667
3834
|
"div",
|
|
3668
3835
|
{
|
|
3669
3836
|
className: "fc-flow-edge-label",
|
|
@@ -3676,7 +3843,7 @@ function ConditionEdgeInner({
|
|
|
3676
3843
|
) })
|
|
3677
3844
|
] });
|
|
3678
3845
|
}
|
|
3679
|
-
var ConditionEdge =
|
|
3846
|
+
var ConditionEdge = React.memo(ConditionEdgeInner);
|
|
3680
3847
|
function PipelineEdgeInner({
|
|
3681
3848
|
id,
|
|
3682
3849
|
sourceX,
|
|
@@ -3687,7 +3854,7 @@ function PipelineEdgeInner({
|
|
|
3687
3854
|
targetPosition,
|
|
3688
3855
|
markerEnd
|
|
3689
3856
|
}) {
|
|
3690
|
-
const [edgePath] = react
|
|
3857
|
+
const [edgePath] = react.getBezierPath({
|
|
3691
3858
|
sourceX,
|
|
3692
3859
|
sourceY,
|
|
3693
3860
|
sourcePosition,
|
|
@@ -3696,7 +3863,7 @@ function PipelineEdgeInner({
|
|
|
3696
3863
|
targetPosition
|
|
3697
3864
|
});
|
|
3698
3865
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3699
|
-
react
|
|
3866
|
+
react.BaseEdge,
|
|
3700
3867
|
{
|
|
3701
3868
|
id,
|
|
3702
3869
|
path: edgePath,
|
|
@@ -3709,7 +3876,7 @@ function PipelineEdgeInner({
|
|
|
3709
3876
|
}
|
|
3710
3877
|
);
|
|
3711
3878
|
}
|
|
3712
|
-
var PipelineEdge =
|
|
3879
|
+
var PipelineEdge = React.memo(PipelineEdgeInner);
|
|
3713
3880
|
var logicFlowEdgeTypes = {
|
|
3714
3881
|
conditionEdge: ConditionEdge,
|
|
3715
3882
|
pipelineEdge: PipelineEdge
|
|
@@ -3747,30 +3914,30 @@ function removeConditionForSource(showIf, sourceFieldId) {
|
|
|
3747
3914
|
}
|
|
3748
3915
|
var defaultEdgeOptions = {
|
|
3749
3916
|
markerEnd: {
|
|
3750
|
-
type: react
|
|
3917
|
+
type: react.MarkerType.ArrowClosed,
|
|
3751
3918
|
width: 16,
|
|
3752
3919
|
height: 12
|
|
3753
3920
|
}
|
|
3754
3921
|
};
|
|
3755
|
-
function LogicFlowEditor({ schema, onChange
|
|
3922
|
+
function LogicFlowEditor({ schema, onChange }) {
|
|
3756
3923
|
const noSections = schema.sections.length === 0;
|
|
3757
|
-
const flowGraph =
|
|
3758
|
-
const [nodes, setNodes, onNodesChange] = react
|
|
3759
|
-
const [edges, setEdges, onEdgesChange] = react
|
|
3760
|
-
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);
|
|
3761
3928
|
const selectedQuestion = selectedFieldId ? findQuestion2(schema, selectedFieldId) : void 0;
|
|
3762
|
-
|
|
3929
|
+
React.useEffect(() => {
|
|
3763
3930
|
setNodes(flowGraph.nodes);
|
|
3764
3931
|
setEdges(flowGraph.edges);
|
|
3765
3932
|
}, [flowGraph, setNodes, setEdges]);
|
|
3766
|
-
const sectionIds =
|
|
3933
|
+
const sectionIds = React.useMemo(() => {
|
|
3767
3934
|
const ids = [];
|
|
3768
3935
|
for (const section of schema.sections) {
|
|
3769
3936
|
ids.push(section.id);
|
|
3770
3937
|
}
|
|
3771
3938
|
return ids;
|
|
3772
3939
|
}, [schema]);
|
|
3773
|
-
const onNodeClick =
|
|
3940
|
+
const onNodeClick = React.useCallback(
|
|
3774
3941
|
(_event, node) => {
|
|
3775
3942
|
if (node.type === "fieldNode") {
|
|
3776
3943
|
setSelectedFieldId(node.id);
|
|
@@ -3778,7 +3945,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3778
3945
|
},
|
|
3779
3946
|
[]
|
|
3780
3947
|
);
|
|
3781
|
-
const onConnect =
|
|
3948
|
+
const onConnect = React.useCallback(
|
|
3782
3949
|
(connection) => {
|
|
3783
3950
|
if (!connection.source || !connection.target) return;
|
|
3784
3951
|
const targetQuestion = findQuestion2(schema, connection.target);
|
|
@@ -3805,7 +3972,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3805
3972
|
},
|
|
3806
3973
|
[schema, onChange]
|
|
3807
3974
|
);
|
|
3808
|
-
const onEdgesDelete =
|
|
3975
|
+
const onEdgesDelete = React.useCallback(
|
|
3809
3976
|
(deletedEdges) => {
|
|
3810
3977
|
let updatedSchema = schema;
|
|
3811
3978
|
for (const edge of deletedEdges) {
|
|
@@ -3830,7 +3997,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3830
3997
|
},
|
|
3831
3998
|
[schema, onChange]
|
|
3832
3999
|
);
|
|
3833
|
-
const handleConditionUpdate =
|
|
4000
|
+
const handleConditionUpdate = React.useCallback(
|
|
3834
4001
|
(updates) => {
|
|
3835
4002
|
if (!selectedFieldId) return;
|
|
3836
4003
|
const updatedSchema = updateQuestionInSchema(schema, selectedFieldId, updates);
|
|
@@ -3844,34 +4011,90 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3844
4011
|
const jumpCount = flowGraph.edges.filter(
|
|
3845
4012
|
(e) => e.data?.edgeType === "onExit"
|
|
3846
4013
|
).length;
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
|
|
3860
|
-
|
|
3861
|
-
|
|
3862
|
-
|
|
4014
|
+
const totalFields = React.useMemo(
|
|
4015
|
+
() => schema.sections.reduce((sum, s) => sum + s.questions.length, 0),
|
|
4016
|
+
[schema]
|
|
4017
|
+
);
|
|
4018
|
+
const conditionalFields = React.useMemo(
|
|
4019
|
+
() => schema.sections.reduce(
|
|
4020
|
+
(sum, s) => sum + s.questions.filter((q) => !!q.showIf).length,
|
|
4021
|
+
0
|
|
4022
|
+
),
|
|
4023
|
+
[schema]
|
|
4024
|
+
);
|
|
4025
|
+
return /* @__PURE__ */ jsxRuntime.jsx(react.ReactFlowProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4026
|
+
LogicFlowInner,
|
|
4027
|
+
{
|
|
4028
|
+
noSections,
|
|
4029
|
+
nodes,
|
|
4030
|
+
edges,
|
|
4031
|
+
onNodesChange,
|
|
4032
|
+
onEdgesChange,
|
|
4033
|
+
onNodeClick,
|
|
4034
|
+
onConnect,
|
|
4035
|
+
onEdgesDelete,
|
|
4036
|
+
selectedFieldId,
|
|
4037
|
+
selectedQuestion,
|
|
4038
|
+
setSelectedFieldId,
|
|
4039
|
+
handleConditionUpdate,
|
|
4040
|
+
schema,
|
|
4041
|
+
sectionIds,
|
|
4042
|
+
showIfCount,
|
|
4043
|
+
jumpCount,
|
|
4044
|
+
totalFields,
|
|
4045
|
+
conditionalFields
|
|
4046
|
+
}
|
|
4047
|
+
) });
|
|
4048
|
+
}
|
|
4049
|
+
function LogicFlowInner({
|
|
4050
|
+
noSections,
|
|
4051
|
+
nodes,
|
|
4052
|
+
edges,
|
|
4053
|
+
onNodesChange,
|
|
4054
|
+
onEdgesChange,
|
|
4055
|
+
onNodeClick,
|
|
4056
|
+
onConnect,
|
|
4057
|
+
onEdgesDelete,
|
|
4058
|
+
selectedFieldId,
|
|
4059
|
+
selectedQuestion,
|
|
4060
|
+
setSelectedFieldId,
|
|
4061
|
+
handleConditionUpdate,
|
|
4062
|
+
schema,
|
|
4063
|
+
sectionIds,
|
|
4064
|
+
showIfCount,
|
|
4065
|
+
jumpCount,
|
|
4066
|
+
totalFields,
|
|
4067
|
+
conditionalFields
|
|
4068
|
+
}) {
|
|
4069
|
+
const { zoomIn, zoomOut, fitView } = react.useReactFlow();
|
|
4070
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col bg-background min-h-0", children: [
|
|
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: [
|
|
4072
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
4073
|
+
sectionIds.length,
|
|
4074
|
+
" section",
|
|
4075
|
+
sectionIds.length !== 1 ? "s" : "",
|
|
4076
|
+
" \xB7 ",
|
|
4077
|
+
totalFields,
|
|
4078
|
+
" field",
|
|
4079
|
+
totalFields !== 1 ? "s" : "",
|
|
4080
|
+
conditionalFields > 0 && ` \xB7 ${conditionalFields} conditional`,
|
|
4081
|
+
showIfCount > 0 && ` \xB7 ${showIfCount} rule${showIfCount !== 1 ? "s" : ""}`,
|
|
4082
|
+
jumpCount > 0 && ` \xB7 ${jumpCount} jump${jumpCount !== 1 ? "s" : ""}`
|
|
4083
|
+
] }) }),
|
|
3863
4084
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
|
|
3864
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground mr-2", children: "Drag between nodes to create conditions \xB7 Select edges
|
|
3865
|
-
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-
|
|
4085
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground mr-2 hidden md:inline", children: "Drag between nodes to create conditions \xB7 Select edges + Delete to remove" }),
|
|
4086
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => zoomOut(), title: "Zoom out", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { size: 14, strokeWidth: 1.75 }) }),
|
|
4087
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => zoomIn(), title: "Zoom in", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { size: 14, strokeWidth: 1.75 }) }),
|
|
4088
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-xs", onClick: () => fitView({ padding: 0.2 }), title: "Fit to view", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize, { size: 14, strokeWidth: 1.75 }) })
|
|
3866
4089
|
] })
|
|
3867
4090
|
] }),
|
|
3868
|
-
noSections ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-
|
|
3869
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size:
|
|
3870
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No
|
|
3871
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs max-w-xs", children: "
|
|
3872
|
-
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex", children: [
|
|
3873
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3874
|
-
react
|
|
4091
|
+
noSections ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex items-center justify-center text-muted-foreground text-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center space-y-3", children: [
|
|
4092
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 40, className: "mx-auto opacity-30" }),
|
|
4093
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No logic to display" }),
|
|
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." })
|
|
4095
|
+
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
4096
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4097
|
+
react.ReactFlow,
|
|
3875
4098
|
{
|
|
3876
4099
|
nodes,
|
|
3877
4100
|
edges,
|
|
@@ -3888,10 +4111,9 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3888
4111
|
deleteKeyCode: ["Backspace", "Delete"],
|
|
3889
4112
|
proOptions: { hideAttribution: true },
|
|
3890
4113
|
children: [
|
|
3891
|
-
/* @__PURE__ */ jsxRuntime.jsx(react
|
|
3892
|
-
/* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false }),
|
|
4114
|
+
/* @__PURE__ */ jsxRuntime.jsx(react.Background, { gap: 20, size: 1 }),
|
|
3893
4115
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3894
|
-
react
|
|
4116
|
+
react.MiniMap,
|
|
3895
4117
|
{
|
|
3896
4118
|
nodeColor: (node) => {
|
|
3897
4119
|
const d = node.data;
|
|
@@ -3904,9 +4126,9 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3904
4126
|
]
|
|
3905
4127
|
}
|
|
3906
4128
|
) }),
|
|
3907
|
-
selectedFieldId && selectedQuestion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 border-l border-border bg-card overflow-auto", children: [
|
|
4129
|
+
selectedFieldId && selectedQuestion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 shrink-0 border-l border-border bg-card overflow-auto", children: [
|
|
3908
4130
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-3 py-3 border-b border-border flex items-center justify-between", children: [
|
|
3909
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
4131
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0", children: [
|
|
3910
4132
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold truncate", children: selectedQuestion.label || selectedQuestion.id }),
|
|
3911
4133
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: selectedQuestion.type })
|
|
3912
4134
|
] }),
|
|
@@ -3917,7 +4139,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3917
4139
|
size: "icon-xs",
|
|
3918
4140
|
onClick: () => setSelectedFieldId(null),
|
|
3919
4141
|
title: "Close panel",
|
|
3920
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4142
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs", children: "\xD7" })
|
|
3921
4143
|
}
|
|
3922
4144
|
)
|
|
3923
4145
|
] }),
|
|
@@ -3931,7 +4153,7 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3931
4153
|
) })
|
|
3932
4154
|
] })
|
|
3933
4155
|
] }),
|
|
3934
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-
|
|
4156
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-1.5 border-t border-border bg-card/50 flex items-center gap-4 text-[11px] text-muted-foreground flex-wrap", children: [
|
|
3935
4157
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3936
4158
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-0.5 rounded", style: { background: "var(--muted-foreground)", opacity: 0.4 } }),
|
|
3937
4159
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "flow" })
|
|
@@ -3955,15 +4177,15 @@ function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
|
3955
4177
|
] });
|
|
3956
4178
|
}
|
|
3957
4179
|
function TemplateGallery({ templates, onSelect, onClose }) {
|
|
3958
|
-
const [search, setSearch] =
|
|
3959
|
-
const [activeCategory, setActiveCategory] =
|
|
3960
|
-
const [confirmTemplate, setConfirmTemplate] =
|
|
3961
|
-
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(() => {
|
|
3962
4184
|
const cats = /* @__PURE__ */ new Set();
|
|
3963
4185
|
for (const t of templates) cats.add(t.meta.category);
|
|
3964
4186
|
return ["all", ...Array.from(cats)];
|
|
3965
4187
|
}, [templates]);
|
|
3966
|
-
const filtered =
|
|
4188
|
+
const filtered = React.useMemo(() => {
|
|
3967
4189
|
return templates.filter((t) => {
|
|
3968
4190
|
const matchesCategory = activeCategory === "all" || t.meta.category === activeCategory;
|
|
3969
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()));
|
|
@@ -4059,9 +4281,9 @@ function TemplateGallery({ templates, onSelect, onClose }) {
|
|
|
4059
4281
|
] }) });
|
|
4060
4282
|
}
|
|
4061
4283
|
function useDebouncedValidation(delayMs = 500) {
|
|
4062
|
-
const [errors, setErrors] =
|
|
4063
|
-
const timerRef =
|
|
4064
|
-
const validate =
|
|
4284
|
+
const [errors, setErrors] = React.useState([]);
|
|
4285
|
+
const timerRef = React.useRef(null);
|
|
4286
|
+
const validate = React.useCallback(
|
|
4065
4287
|
(text) => {
|
|
4066
4288
|
if (timerRef.current) {
|
|
4067
4289
|
clearTimeout(timerRef.current);
|
|
@@ -4110,9 +4332,9 @@ function useDebouncedValidation(delayMs = 500) {
|
|
|
4110
4332
|
);
|
|
4111
4333
|
return { errors, validate };
|
|
4112
4334
|
}
|
|
4113
|
-
var ThemeCtx =
|
|
4335
|
+
var ThemeCtx = React.createContext({});
|
|
4114
4336
|
function useBuilderTheme() {
|
|
4115
|
-
return
|
|
4337
|
+
return React.useContext(ThemeCtx);
|
|
4116
4338
|
}
|
|
4117
4339
|
function themeToCssVars(theme) {
|
|
4118
4340
|
const vars = {};
|
|
@@ -4148,10 +4370,10 @@ function themeToCssVars(theme) {
|
|
|
4148
4370
|
}
|
|
4149
4371
|
function FormBuilderThemeProvider({ theme, children }) {
|
|
4150
4372
|
const resolved = theme ?? {};
|
|
4151
|
-
const cssVars =
|
|
4373
|
+
const cssVars = React.useMemo(() => themeToCssVars(resolved), [resolved]);
|
|
4152
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 }) });
|
|
4153
4375
|
}
|
|
4154
|
-
var FormBuilderErrorBoundary = class extends
|
|
4376
|
+
var FormBuilderErrorBoundary = class extends React.Component {
|
|
4155
4377
|
constructor(props) {
|
|
4156
4378
|
super(props);
|
|
4157
4379
|
this.state = { hasError: false, error: null };
|
|
@@ -4183,31 +4405,30 @@ var FormBuilderErrorBoundary = class extends react.Component {
|
|
|
4183
4405
|
};
|
|
4184
4406
|
function FormBuilderCore(props) {
|
|
4185
4407
|
const { initialSchema = DEFAULT_SCHEMA, onChange, onSave, height = "100vh", theme, className, toolbarExtra, questionTypes, palette, preview, templates, schemaUrl } = props;
|
|
4186
|
-
const [viewMode, setViewMode] =
|
|
4187
|
-
const [jsonText, setJsonText] =
|
|
4188
|
-
const [jsonSwitchError, setJsonSwitchError] =
|
|
4189
|
-
const [
|
|
4190
|
-
const [
|
|
4191
|
-
const [
|
|
4192
|
-
const [
|
|
4193
|
-
const [schemaUrlError, setSchemaUrlError] = react.useState(null);
|
|
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);
|
|
4194
4415
|
const { errors: jsonErrors, validate: validateJson } = useDebouncedValidation(400);
|
|
4195
4416
|
const mergedQuestionTypes = questionTypes ? { ...QUESTION_TYPE_INFO, ...questionTypes } : QUESTION_TYPE_INFO;
|
|
4196
4417
|
const builderState = useBuilderState(initialSchema);
|
|
4197
4418
|
const dragDrop = useDragDrop(builderState);
|
|
4198
|
-
const fileInputRef =
|
|
4199
|
-
const [mobilePanel, setMobilePanel] =
|
|
4200
|
-
|
|
4419
|
+
const fileInputRef = React.useRef(null);
|
|
4420
|
+
const [mobilePanel, setMobilePanel] = React.useState("none");
|
|
4421
|
+
React.useEffect(() => {
|
|
4201
4422
|
if (builderState.selectedItem && window.innerWidth < 768) {
|
|
4202
4423
|
setMobilePanel("properties");
|
|
4203
4424
|
}
|
|
4204
4425
|
}, [builderState.selectedItem]);
|
|
4205
|
-
|
|
4426
|
+
React.useEffect(() => {
|
|
4206
4427
|
if (!dragDrop.activeDragItem && mobilePanel === "palette") {
|
|
4207
4428
|
setMobilePanel("none");
|
|
4208
4429
|
}
|
|
4209
4430
|
}, [dragDrop.activeDragItem]);
|
|
4210
|
-
|
|
4431
|
+
React.useEffect(() => {
|
|
4211
4432
|
if (!schemaUrl) return;
|
|
4212
4433
|
let cancelled = false;
|
|
4213
4434
|
setSchemaUrlLoading(true);
|
|
@@ -4237,12 +4458,12 @@ function FormBuilderCore(props) {
|
|
|
4237
4458
|
cancelled = true;
|
|
4238
4459
|
};
|
|
4239
4460
|
}, [schemaUrl]);
|
|
4240
|
-
|
|
4461
|
+
React.useEffect(() => {
|
|
4241
4462
|
if (onChange && builderState.isDirty) {
|
|
4242
4463
|
onChange(builderState.schema);
|
|
4243
4464
|
}
|
|
4244
4465
|
}, [builderState.schema, builderState.isDirty, onChange]);
|
|
4245
|
-
const handleSave =
|
|
4466
|
+
const handleSave = React.useCallback(() => {
|
|
4246
4467
|
if (!onSave) return;
|
|
4247
4468
|
try {
|
|
4248
4469
|
fieldcraftCore.validateSchema(builderState.schema);
|
|
@@ -4257,7 +4478,7 @@ function FormBuilderCore(props) {
|
|
|
4257
4478
|
}
|
|
4258
4479
|
}
|
|
4259
4480
|
}, [onSave, builderState]);
|
|
4260
|
-
const handleExport =
|
|
4481
|
+
const handleExport = React.useCallback(() => {
|
|
4261
4482
|
const json = JSON.stringify(builderState.schema, null, 2);
|
|
4262
4483
|
const blob = new Blob([json], { type: "application/json" });
|
|
4263
4484
|
const url = URL.createObjectURL(blob);
|
|
@@ -4267,10 +4488,10 @@ function FormBuilderCore(props) {
|
|
|
4267
4488
|
a.click();
|
|
4268
4489
|
URL.revokeObjectURL(url);
|
|
4269
4490
|
}, [builderState.schema]);
|
|
4270
|
-
const handleImport =
|
|
4491
|
+
const handleImport = React.useCallback(() => {
|
|
4271
4492
|
fileInputRef.current?.click();
|
|
4272
4493
|
}, []);
|
|
4273
|
-
const handleFileChange =
|
|
4494
|
+
const handleFileChange = React.useCallback(
|
|
4274
4495
|
(e) => {
|
|
4275
4496
|
const file = e.target.files?.[0];
|
|
4276
4497
|
if (!file) return;
|
|
@@ -4297,7 +4518,7 @@ ${details}`);
|
|
|
4297
4518
|
},
|
|
4298
4519
|
[builderState]
|
|
4299
4520
|
);
|
|
4300
|
-
const handleViewModeChange =
|
|
4521
|
+
const handleViewModeChange = React.useCallback(
|
|
4301
4522
|
(newMode) => {
|
|
4302
4523
|
setJsonSwitchError(null);
|
|
4303
4524
|
if (viewMode === "json" && newMode !== "json") {
|
|
@@ -4323,7 +4544,7 @@ ${details}`);
|
|
|
4323
4544
|
},
|
|
4324
4545
|
[viewMode, jsonText, builderState]
|
|
4325
4546
|
);
|
|
4326
|
-
const handleKeyDown =
|
|
4547
|
+
const handleKeyDown = React.useCallback(
|
|
4327
4548
|
(e) => {
|
|
4328
4549
|
const mod = e.metaKey || e.ctrlKey;
|
|
4329
4550
|
const tag = e.target.tagName;
|
|
@@ -4343,6 +4564,11 @@ ${details}`);
|
|
|
4343
4564
|
handleSave();
|
|
4344
4565
|
return;
|
|
4345
4566
|
}
|
|
4567
|
+
if (mod && e.key === "l") {
|
|
4568
|
+
e.preventDefault();
|
|
4569
|
+
handleViewModeChange(viewMode === "logic" ? "design" : "logic");
|
|
4570
|
+
return;
|
|
4571
|
+
}
|
|
4346
4572
|
if (isEditing) return;
|
|
4347
4573
|
if (e.key === "Delete" || e.key === "Backspace") {
|
|
4348
4574
|
const sel = builderState.selectedItem;
|
|
@@ -4373,7 +4599,7 @@ ${details}`);
|
|
|
4373
4599
|
}
|
|
4374
4600
|
}
|
|
4375
4601
|
},
|
|
4376
|
-
[builderState, handleSave]
|
|
4602
|
+
[builderState, handleSave, handleViewModeChange, viewMode]
|
|
4377
4603
|
);
|
|
4378
4604
|
return /* @__PURE__ */ jsxRuntime.jsx(FormBuilderThemeProvider, { theme, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4379
4605
|
core.DndContext,
|
|
@@ -4464,6 +4690,19 @@ ${details}`);
|
|
|
4464
4690
|
"JSON"
|
|
4465
4691
|
]
|
|
4466
4692
|
}
|
|
4693
|
+
),
|
|
4694
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4695
|
+
fieldcraftReact.Button,
|
|
4696
|
+
{
|
|
4697
|
+
variant: viewMode === "logic" ? "secondary" : "ghost",
|
|
4698
|
+
size: "sm",
|
|
4699
|
+
onClick: () => handleViewModeChange("logic"),
|
|
4700
|
+
className: "gap-1.5 h-7 px-2.5 text-xs",
|
|
4701
|
+
children: [
|
|
4702
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 13, strokeWidth: 1.75 }),
|
|
4703
|
+
"Logic"
|
|
4704
|
+
]
|
|
4705
|
+
}
|
|
4467
4706
|
)
|
|
4468
4707
|
] }),
|
|
4469
4708
|
toolbarExtra
|
|
@@ -4480,17 +4719,6 @@ ${details}`);
|
|
|
4480
4719
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutTemplate, { size: 15, strokeWidth: 1.75 })
|
|
4481
4720
|
}
|
|
4482
4721
|
),
|
|
4483
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4484
|
-
fieldcraftReact.Button,
|
|
4485
|
-
{
|
|
4486
|
-
variant: "ghost",
|
|
4487
|
-
size: "icon-sm",
|
|
4488
|
-
onClick: () => setShowLogicMap(true),
|
|
4489
|
-
title: "View branching logic map",
|
|
4490
|
-
"aria-label": "Logic map",
|
|
4491
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 15, strokeWidth: 1.75 })
|
|
4492
|
-
}
|
|
4493
|
-
),
|
|
4494
4722
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "mx-1 h-5" }),
|
|
4495
4723
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4496
4724
|
fieldcraftReact.Button,
|
|
@@ -4574,6 +4802,19 @@ ${details}`);
|
|
|
4574
4802
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "JSON" })
|
|
4575
4803
|
]
|
|
4576
4804
|
}
|
|
4805
|
+
),
|
|
4806
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4807
|
+
fieldcraftReact.Button,
|
|
4808
|
+
{
|
|
4809
|
+
variant: viewMode === "logic" ? "secondary" : "ghost",
|
|
4810
|
+
size: "sm",
|
|
4811
|
+
onClick: () => handleViewModeChange("logic"),
|
|
4812
|
+
className: "gap-1 h-7 px-2 text-xs",
|
|
4813
|
+
children: [
|
|
4814
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 12, strokeWidth: 1.75 }),
|
|
4815
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Logic" })
|
|
4816
|
+
]
|
|
4817
|
+
}
|
|
4577
4818
|
)
|
|
4578
4819
|
] }),
|
|
4579
4820
|
toolbarExtra,
|
|
@@ -4707,7 +4948,13 @@ ${details}`);
|
|
|
4707
4948
|
errors: jsonErrors,
|
|
4708
4949
|
onValidate: validateJson
|
|
4709
4950
|
}
|
|
4710
|
-
) : viewMode === "preview" ? /* @__PURE__ */ jsxRuntime.jsx(FormPreviewPanel, { schema: builderState.schema, preview }) : /* @__PURE__ */ jsxRuntime.
|
|
4951
|
+
) : viewMode === "preview" ? /* @__PURE__ */ jsxRuntime.jsx(FormPreviewPanel, { schema: builderState.schema, preview }) : viewMode === "logic" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4952
|
+
LogicFlowEditor,
|
|
4953
|
+
{
|
|
4954
|
+
schema: builderState.schema,
|
|
4955
|
+
onChange: (updated) => builderState.resetSchema(updated)
|
|
4956
|
+
}
|
|
4957
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4711
4958
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(QuestionPalette, { questionTypes: mergedQuestionTypes, palette }) }),
|
|
4712
4959
|
/* @__PURE__ */ jsxRuntime.jsx(FormCanvas, { builderState }),
|
|
4713
4960
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(PropertiesPanel, { builderState }) }),
|
|
@@ -4726,14 +4973,6 @@ ${details}`);
|
|
|
4726
4973
|
}
|
|
4727
4974
|
),
|
|
4728
4975
|
/* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: null, children: dragDrop.activeDragItem && /* @__PURE__ */ jsxRuntime.jsx(DragOverlayContent, { item: dragDrop.activeDragItem, schema: builderState.schema, questionTypes: mergedQuestionTypes }) }),
|
|
4729
|
-
showLogicMap && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4730
|
-
LogicFlowEditor,
|
|
4731
|
-
{
|
|
4732
|
-
schema: builderState.schema,
|
|
4733
|
-
onChange: (updated) => builderState.resetSchema(updated),
|
|
4734
|
-
onClose: () => setShowLogicMap(false)
|
|
4735
|
-
}
|
|
4736
|
-
),
|
|
4737
4976
|
showTemplateGallery && templates && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4738
4977
|
TemplateGallery,
|
|
4739
4978
|
{
|