@squaredr/fieldcraft-pro 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-22T5PY6L.mjs +1081 -0
- package/dist/{chunk-GNBXIG63.mjs → chunk-6LRUDBC7.mjs} +1305 -89
- package/dist/{chunk-4BX7FCXH.mjs → chunk-BK4SMEW4.mjs} +840 -21
- package/dist/form-builder/index.d.mts +7 -367
- package/dist/form-builder/index.d.ts +7 -367
- package/dist/form-builder/index.js +1307 -91
- package/dist/form-builder/index.mjs +1 -1
- package/dist/index-BHJ4mqHP.d.mts +398 -0
- package/dist/index-BHJ4mqHP.d.ts +398 -0
- package/dist/index.d.mts +30 -3
- package/dist/index.d.ts +30 -3
- package/dist/index.js +3230 -331
- package/dist/index.mjs +276 -4
- package/dist/preview-schema-DFvV4y6J.d.mts +66 -0
- package/dist/preview-schema-DFvV4y6J.d.ts +66 -0
- package/dist/response-viewer/index.d.mts +9 -1
- package/dist/response-viewer/index.d.ts +9 -1
- package/dist/response-viewer/index.js +838 -19
- package/dist/response-viewer/index.mjs +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme-editor/index.d.mts +30 -26
- package/dist/theme-editor/index.d.ts +30 -26
- package/dist/theme-editor/index.js +702 -22
- package/dist/theme-editor/index.mjs +1 -1
- package/package.json +18 -6
- package/theme-editor/styles.css +266 -62
- package/dist/chunk-7LQW5QYT.mjs +0 -407
|
@@ -8,6 +8,8 @@ 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 react$1 = require('@xyflow/react');
|
|
12
|
+
require('@xyflow/react/dist/style.css');
|
|
11
13
|
|
|
12
14
|
// ../license/dist/index.mjs
|
|
13
15
|
var PRO_FEATURES = [
|
|
@@ -300,19 +302,19 @@ function UnlicensedOverlay({ featureName, reason, children }) {
|
|
|
300
302
|
)
|
|
301
303
|
] });
|
|
302
304
|
}
|
|
303
|
-
function requireLicense(
|
|
305
|
+
function requireLicense(Component3, featureName) {
|
|
304
306
|
function LicenseGated(props) {
|
|
305
307
|
const { status, tier } = useLicense();
|
|
306
308
|
const isProduction = isProductionEnvironment();
|
|
307
309
|
if (!isProduction) {
|
|
308
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
310
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
|
|
309
311
|
}
|
|
310
312
|
if (status === "validating") {
|
|
311
313
|
return null;
|
|
312
314
|
}
|
|
313
315
|
const isLicensed = status === "valid" && tier != null && tierHasFeature(tier, featureName);
|
|
314
316
|
if (isLicensed) {
|
|
315
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
317
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props });
|
|
316
318
|
}
|
|
317
319
|
let reason = "A valid license is required for production use.";
|
|
318
320
|
if (status === "invalid") {
|
|
@@ -326,9 +328,9 @@ function requireLicense(Component2, featureName) {
|
|
|
326
328
|
} else if (!tier || !tierHasFeature(tier, featureName)) {
|
|
327
329
|
reason = "Your license does not include this feature. Please upgrade your plan.";
|
|
328
330
|
}
|
|
329
|
-
return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
331
|
+
return /* @__PURE__ */ jsxRuntime.jsx(UnlicensedOverlay, { featureName, reason, children: /* @__PURE__ */ jsxRuntime.jsx(Component3, { ...props }) });
|
|
330
332
|
}
|
|
331
|
-
LicenseGated.displayName = `requireLicense(${
|
|
333
|
+
LicenseGated.displayName = `requireLicense(${Component3.displayName || Component3.name || "Component"})`;
|
|
332
334
|
return LicenseGated;
|
|
333
335
|
}
|
|
334
336
|
var MAX_HISTORY = 50;
|
|
@@ -775,6 +777,14 @@ var QUESTION_TYPE_INFO = {
|
|
|
775
777
|
icon: "Phone",
|
|
776
778
|
description: "US phone number input"
|
|
777
779
|
},
|
|
780
|
+
phone_international: {
|
|
781
|
+
type: "phone_international",
|
|
782
|
+
label: "Intl Phone",
|
|
783
|
+
category: "text",
|
|
784
|
+
icon: "Globe2",
|
|
785
|
+
description: "Phone with country code",
|
|
786
|
+
defaultConfig: { type: "phone_international", defaultCountry: "US" }
|
|
787
|
+
},
|
|
778
788
|
url: {
|
|
779
789
|
type: "url",
|
|
780
790
|
label: "URL",
|
|
@@ -868,6 +878,14 @@ var QUESTION_TYPE_INFO = {
|
|
|
868
878
|
requiresOptions: true,
|
|
869
879
|
defaultConfig: { type: "ranking", items: [] }
|
|
870
880
|
},
|
|
881
|
+
country_select: {
|
|
882
|
+
type: "country_select",
|
|
883
|
+
label: "Country",
|
|
884
|
+
category: "selection",
|
|
885
|
+
icon: "Globe",
|
|
886
|
+
description: "Country dropdown with search",
|
|
887
|
+
defaultConfig: { type: "country_select" }
|
|
888
|
+
},
|
|
871
889
|
// ── Date/Time ──
|
|
872
890
|
date: {
|
|
873
891
|
type: "date",
|
|
@@ -894,7 +912,97 @@ var QUESTION_TYPE_INFO = {
|
|
|
894
912
|
description: "Upload files",
|
|
895
913
|
defaultConfig: { type: "file_upload", maxFiles: 1, maxSizeMb: 10 }
|
|
896
914
|
},
|
|
915
|
+
// ── Compound ──
|
|
916
|
+
legal_name: {
|
|
917
|
+
type: "legal_name",
|
|
918
|
+
label: "Legal Name",
|
|
919
|
+
category: "text",
|
|
920
|
+
icon: "UserCheck",
|
|
921
|
+
description: "First, middle, and last name",
|
|
922
|
+
defaultConfig: { type: "legal_name" }
|
|
923
|
+
},
|
|
924
|
+
address: {
|
|
925
|
+
type: "address",
|
|
926
|
+
label: "Address",
|
|
927
|
+
category: "text",
|
|
928
|
+
icon: "MapPin",
|
|
929
|
+
description: "Street, city, state, ZIP",
|
|
930
|
+
defaultConfig: { type: "address", includeCountry: false }
|
|
931
|
+
},
|
|
932
|
+
signature: {
|
|
933
|
+
type: "signature",
|
|
934
|
+
label: "Signature",
|
|
935
|
+
category: "media",
|
|
936
|
+
icon: "PenTool",
|
|
937
|
+
description: "Canvas signature pad",
|
|
938
|
+
defaultConfig: { type: "signature" }
|
|
939
|
+
},
|
|
940
|
+
image_capture: {
|
|
941
|
+
type: "image_capture",
|
|
942
|
+
label: "Camera",
|
|
943
|
+
category: "media",
|
|
944
|
+
icon: "Camera",
|
|
945
|
+
description: "Capture photo from camera",
|
|
946
|
+
defaultConfig: { type: "image_capture", allowGallery: true }
|
|
947
|
+
},
|
|
948
|
+
date_range: {
|
|
949
|
+
type: "date_range",
|
|
950
|
+
label: "Date Range",
|
|
951
|
+
category: "datetime",
|
|
952
|
+
icon: "CalendarRange",
|
|
953
|
+
description: "Start and end date picker",
|
|
954
|
+
defaultConfig: { type: "date_range" }
|
|
955
|
+
},
|
|
956
|
+
appointment: {
|
|
957
|
+
type: "appointment",
|
|
958
|
+
label: "Appointment",
|
|
959
|
+
category: "datetime",
|
|
960
|
+
icon: "CalendarCheck",
|
|
961
|
+
description: "Date & time slot booking",
|
|
962
|
+
defaultConfig: { type: "appointment", duration: 30 }
|
|
963
|
+
},
|
|
897
964
|
// ── Advanced ──
|
|
965
|
+
repeater: {
|
|
966
|
+
type: "repeater",
|
|
967
|
+
label: "Repeater",
|
|
968
|
+
category: "advanced",
|
|
969
|
+
icon: "ListPlus",
|
|
970
|
+
description: "Repeatable group of fields",
|
|
971
|
+
defaultConfig: { type: "repeater", fields: [], minItems: 1, maxItems: 10 }
|
|
972
|
+
},
|
|
973
|
+
likert: {
|
|
974
|
+
type: "likert",
|
|
975
|
+
label: "Likert Scale",
|
|
976
|
+
category: "advanced",
|
|
977
|
+
icon: "AlignHorizontalSpaceAround",
|
|
978
|
+
description: "Agreement scale (e.g. Strongly Disagree to Strongly Agree)",
|
|
979
|
+
requiresOptions: true,
|
|
980
|
+
defaultConfig: {
|
|
981
|
+
type: "likert",
|
|
982
|
+
scale: [
|
|
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
|
+
]
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
scoring: {
|
|
992
|
+
type: "scoring",
|
|
993
|
+
label: "Scoring",
|
|
994
|
+
category: "advanced",
|
|
995
|
+
icon: "Award",
|
|
996
|
+
description: "Scored question with point values per option",
|
|
997
|
+
requiresOptions: true,
|
|
998
|
+
defaultConfig: {
|
|
999
|
+
type: "scoring",
|
|
1000
|
+
options: [
|
|
1001
|
+
{ label: "Option 1", value: "1", score: 1 },
|
|
1002
|
+
{ label: "Option 2", value: "2", score: 2 }
|
|
1003
|
+
]
|
|
1004
|
+
}
|
|
1005
|
+
},
|
|
898
1006
|
matrix: {
|
|
899
1007
|
type: "matrix",
|
|
900
1008
|
label: "Matrix",
|
|
@@ -924,6 +1032,14 @@ var QUESTION_TYPE_INFO = {
|
|
|
924
1032
|
description: "Hidden value from URL or static",
|
|
925
1033
|
defaultConfig: { type: "hidden", source: "static" }
|
|
926
1034
|
},
|
|
1035
|
+
payment: {
|
|
1036
|
+
type: "payment",
|
|
1037
|
+
label: "Payment",
|
|
1038
|
+
category: "advanced",
|
|
1039
|
+
icon: "CreditCard",
|
|
1040
|
+
description: "Collect payment via Stripe",
|
|
1041
|
+
defaultConfig: { type: "payment", provider: "stripe", publicKey: "", currency: "USD" }
|
|
1042
|
+
},
|
|
927
1043
|
// ── Structural ──
|
|
928
1044
|
section_header: {
|
|
929
1045
|
type: "section_header",
|
|
@@ -1028,7 +1144,7 @@ var DEFAULT_PALETTE = [
|
|
|
1028
1144
|
{
|
|
1029
1145
|
category: "text",
|
|
1030
1146
|
label: "Text Input",
|
|
1031
|
-
types: ["short_text", "long_text", "email", "phone", "url"]
|
|
1147
|
+
types: ["short_text", "long_text", "email", "phone", "phone_international", "url", "legal_name", "address"]
|
|
1032
1148
|
},
|
|
1033
1149
|
{
|
|
1034
1150
|
category: "numeric",
|
|
@@ -1038,17 +1154,17 @@ var DEFAULT_PALETTE = [
|
|
|
1038
1154
|
{
|
|
1039
1155
|
category: "selection",
|
|
1040
1156
|
label: "Selection",
|
|
1041
|
-
types: ["single_select", "multi_select", "dropdown", "boolean", "ranking"]
|
|
1157
|
+
types: ["single_select", "multi_select", "dropdown", "boolean", "ranking", "country_select"]
|
|
1042
1158
|
},
|
|
1043
1159
|
{
|
|
1044
1160
|
category: "datetime",
|
|
1045
1161
|
label: "Date & Time",
|
|
1046
|
-
types: ["date", "time"]
|
|
1162
|
+
types: ["date", "time", "date_range", "appointment"]
|
|
1047
1163
|
},
|
|
1048
1164
|
{
|
|
1049
1165
|
category: "media",
|
|
1050
1166
|
label: "Media",
|
|
1051
|
-
types: ["file_upload"]
|
|
1167
|
+
types: ["file_upload", "signature", "image_capture"]
|
|
1052
1168
|
},
|
|
1053
1169
|
{
|
|
1054
1170
|
category: "content",
|
|
@@ -1063,7 +1179,7 @@ var DEFAULT_PALETTE = [
|
|
|
1063
1179
|
{
|
|
1064
1180
|
category: "advanced",
|
|
1065
1181
|
label: "Advanced",
|
|
1066
|
-
types: ["matrix", "calculated", "hidden"]
|
|
1182
|
+
types: ["repeater", "likert", "scoring", "matrix", "calculated", "hidden", "payment"]
|
|
1067
1183
|
}
|
|
1068
1184
|
];
|
|
1069
1185
|
|
|
@@ -2580,7 +2696,8 @@ function getFieldOptions(schema, excludeId) {
|
|
|
2580
2696
|
return fields;
|
|
2581
2697
|
}
|
|
2582
2698
|
function ConditionEditor({ question, schema, onUpdate }) {
|
|
2583
|
-
const
|
|
2699
|
+
const rawShowIf = question.showIf;
|
|
2700
|
+
const showIf = rawShowIf && rawShowIf.field && !rawShowIf.conditions ? { combine: "AND", conditions: [rawShowIf] } : rawShowIf;
|
|
2584
2701
|
const fieldOptions = getFieldOptions(schema, question.id);
|
|
2585
2702
|
const updateShowIf = (next) => {
|
|
2586
2703
|
onUpdate({ showIf: next });
|
|
@@ -2702,6 +2819,24 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2702
2819
|
}
|
|
2703
2820
|
function FormSettingsPanel({ schema, onUpdate }) {
|
|
2704
2821
|
const settings = schema.settings ?? {};
|
|
2822
|
+
const hasConditions = schema.sections.some(
|
|
2823
|
+
(s) => s.showIf || s.questions.some((q) => q.showIf)
|
|
2824
|
+
);
|
|
2825
|
+
const displayModeOptions = hasConditions ? [
|
|
2826
|
+
{ label: "Stepped", value: "stepped" },
|
|
2827
|
+
{ label: "Conversational", value: "conversational" }
|
|
2828
|
+
] : [
|
|
2829
|
+
{ label: "Stepped", value: "stepped" },
|
|
2830
|
+
{ label: "Classic", value: "classic" },
|
|
2831
|
+
{ label: "Conversational", value: "conversational" }
|
|
2832
|
+
];
|
|
2833
|
+
const displayMode = settings.displayMode ?? "stepped";
|
|
2834
|
+
const effectiveDisplayMode = hasConditions && displayMode === "classic" ? "stepped" : displayMode;
|
|
2835
|
+
react.useEffect(() => {
|
|
2836
|
+
if (effectiveDisplayMode !== displayMode) {
|
|
2837
|
+
onUpdate({ ...schema, settings: { ...settings, displayMode: effectiveDisplayMode } });
|
|
2838
|
+
}
|
|
2839
|
+
}, [effectiveDisplayMode, displayMode]);
|
|
2705
2840
|
const updateSettings = (updates) => {
|
|
2706
2841
|
onUpdate({ ...schema, settings: { ...settings, ...updates } });
|
|
2707
2842
|
};
|
|
@@ -2729,12 +2864,8 @@ function FormSettingsPanel({ schema, onUpdate }) {
|
|
|
2729
2864
|
SettingsSelect,
|
|
2730
2865
|
{
|
|
2731
2866
|
label: "Mode",
|
|
2732
|
-
value:
|
|
2733
|
-
options:
|
|
2734
|
-
{ label: "Classic", value: "classic" },
|
|
2735
|
-
{ label: "Stepped", value: "stepped" },
|
|
2736
|
-
{ label: "Conversational", value: "conversational" }
|
|
2737
|
-
],
|
|
2867
|
+
value: effectiveDisplayMode,
|
|
2868
|
+
options: displayModeOptions,
|
|
2738
2869
|
onChange: (v) => updateSettings({ displayMode: v })
|
|
2739
2870
|
}
|
|
2740
2871
|
),
|
|
@@ -3112,6 +3243,873 @@ function FieldGroup({ label, children }) {
|
|
|
3112
3243
|
children
|
|
3113
3244
|
] });
|
|
3114
3245
|
}
|
|
3246
|
+
var PreviewErrorBoundary = class extends react.Component {
|
|
3247
|
+
state = { error: null };
|
|
3248
|
+
static getDerivedStateFromError(error) {
|
|
3249
|
+
return { error };
|
|
3250
|
+
}
|
|
3251
|
+
componentDidCatch(error, info) {
|
|
3252
|
+
console.error("[FormBuilder Preview]", error, info);
|
|
3253
|
+
}
|
|
3254
|
+
componentDidUpdate(prevProps) {
|
|
3255
|
+
if (prevProps.resetKey !== this.props.resetKey && this.state.error) {
|
|
3256
|
+
this.setState({ error: null });
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
render() {
|
|
3260
|
+
if (this.state.error) {
|
|
3261
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 text-destructive text-sm font-mono", children: [
|
|
3262
|
+
/* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Render Error:" }),
|
|
3263
|
+
" ",
|
|
3264
|
+
this.state.error.message
|
|
3265
|
+
] });
|
|
3266
|
+
}
|
|
3267
|
+
return this.props.children;
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
function FormPreviewPanel({ schema, preview }) {
|
|
3271
|
+
const hasSections = schema.sections && schema.sections.length > 0;
|
|
3272
|
+
const hasFields = hasSections && schema.sections.some((s) => s.questions.length > 0);
|
|
3273
|
+
if (!hasFields) {
|
|
3274
|
+
return /* @__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-2", children: [
|
|
3275
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No fields to preview" }),
|
|
3276
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: "Add fields in the Design view to see a live preview here." })
|
|
3277
|
+
] }) });
|
|
3278
|
+
}
|
|
3279
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-2xl mx-auto py-8 px-4", children: /* @__PURE__ */ jsxRuntime.jsx(PreviewErrorBoundary, { resetKey: schema.id + (schema.version ?? ""), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3280
|
+
fieldcraftReact.FormEngineRenderer,
|
|
3281
|
+
{
|
|
3282
|
+
schema,
|
|
3283
|
+
theme: preview?.theme,
|
|
3284
|
+
components: preview?.components,
|
|
3285
|
+
onReady: preview?.onReady,
|
|
3286
|
+
onFieldChange: preview?.onFieldChange,
|
|
3287
|
+
onSubmit: preview?.onSubmit ?? (() => {
|
|
3288
|
+
})
|
|
3289
|
+
}
|
|
3290
|
+
) }) }) });
|
|
3291
|
+
}
|
|
3292
|
+
|
|
3293
|
+
// src/form-builder/utils/validation-markers.ts
|
|
3294
|
+
var MarkerSeverity = {
|
|
3295
|
+
Error: 8};
|
|
3296
|
+
function errorsToMarkers(errors) {
|
|
3297
|
+
return errors.map((error) => ({
|
|
3298
|
+
severity: MarkerSeverity.Error,
|
|
3299
|
+
message: error.message,
|
|
3300
|
+
startLineNumber: error.line ?? 1,
|
|
3301
|
+
startColumn: error.column ?? 1,
|
|
3302
|
+
endLineNumber: error.endLine ?? error.line ?? 1,
|
|
3303
|
+
endColumn: error.endColumn ?? error.column ?? 1,
|
|
3304
|
+
source: "FieldCraft Schema Validator"
|
|
3305
|
+
}));
|
|
3306
|
+
}
|
|
3307
|
+
var Editor = react.lazy(() => import('@monaco-editor/react').then((m) => ({ default: m.default })));
|
|
3308
|
+
function MonacoWrapper({ value, onChange, errors }) {
|
|
3309
|
+
const editorRef = react.useRef(null);
|
|
3310
|
+
const monacoRef = react.useRef(null);
|
|
3311
|
+
const handleMount = (editor, monaco) => {
|
|
3312
|
+
editorRef.current = editor;
|
|
3313
|
+
monacoRef.current = monaco;
|
|
3314
|
+
};
|
|
3315
|
+
react.useEffect(() => {
|
|
3316
|
+
const editor = editorRef.current;
|
|
3317
|
+
const monaco = monacoRef.current;
|
|
3318
|
+
if (!editor || !monaco) return;
|
|
3319
|
+
const model = editor.getModel();
|
|
3320
|
+
if (!model) return;
|
|
3321
|
+
const markers = errorsToMarkers(errors);
|
|
3322
|
+
monaco.editor.setModelMarkers(model, "fieldcraft-schema", markers);
|
|
3323
|
+
}, [errors]);
|
|
3324
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3325
|
+
Editor,
|
|
3326
|
+
{
|
|
3327
|
+
height: "100%",
|
|
3328
|
+
language: "json",
|
|
3329
|
+
theme: "vs-dark",
|
|
3330
|
+
value,
|
|
3331
|
+
onChange: (val) => onChange(val ?? ""),
|
|
3332
|
+
onMount: handleMount,
|
|
3333
|
+
options: {
|
|
3334
|
+
minimap: { enabled: false },
|
|
3335
|
+
fontSize: 13,
|
|
3336
|
+
wordWrap: "on",
|
|
3337
|
+
formatOnPaste: true,
|
|
3338
|
+
automaticLayout: true,
|
|
3339
|
+
tabSize: 2,
|
|
3340
|
+
scrollBeyondLastLine: false,
|
|
3341
|
+
padding: { top: 12 }
|
|
3342
|
+
}
|
|
3343
|
+
}
|
|
3344
|
+
);
|
|
3345
|
+
}
|
|
3346
|
+
function JsonEditorPanel({ value, onChange, errors, onValidate }) {
|
|
3347
|
+
const handleChange = react.useCallback(
|
|
3348
|
+
(newValue) => {
|
|
3349
|
+
onChange(newValue);
|
|
3350
|
+
onValidate(newValue);
|
|
3351
|
+
},
|
|
3352
|
+
[onChange, onValidate]
|
|
3353
|
+
);
|
|
3354
|
+
const handleFormat = react.useCallback(() => {
|
|
3355
|
+
try {
|
|
3356
|
+
const formatted = JSON.stringify(JSON.parse(value), null, 2);
|
|
3357
|
+
onChange(formatted);
|
|
3358
|
+
} catch {
|
|
3359
|
+
}
|
|
3360
|
+
}, [value, onChange]);
|
|
3361
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex flex-col overflow-hidden", children: [
|
|
3362
|
+
errors.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-3 py-1.5 bg-destructive/10 border-b border-destructive/20 text-destructive text-xs font-mono overflow-x-auto", children: [
|
|
3363
|
+
errors.slice(0, 3).map((e, i) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
3364
|
+
e.line ? `Line ${e.line}: ` : "",
|
|
3365
|
+
e.path ? `${e.path}: ` : "",
|
|
3366
|
+
e.message
|
|
3367
|
+
] }, i)),
|
|
3368
|
+
errors.length > 3 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-muted-foreground", children: [
|
|
3369
|
+
"...and ",
|
|
3370
|
+
errors.length - 3,
|
|
3371
|
+
" more"
|
|
3372
|
+
] })
|
|
3373
|
+
] }),
|
|
3374
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 flex items-center justify-between px-3 py-1.5 bg-card border-b border-border text-xs", children: [
|
|
3375
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: errors.length === 0 ? "Valid schema" : `${errors.length} error${errors.length !== 1 ? "s" : ""}` }),
|
|
3376
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3377
|
+
"button",
|
|
3378
|
+
{
|
|
3379
|
+
type: "button",
|
|
3380
|
+
onClick: handleFormat,
|
|
3381
|
+
className: "text-primary hover:underline",
|
|
3382
|
+
children: "Format JSON"
|
|
3383
|
+
}
|
|
3384
|
+
)
|
|
3385
|
+
] }),
|
|
3386
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3387
|
+
react.Suspense,
|
|
3388
|
+
{
|
|
3389
|
+
fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center h-full text-sm text-muted-foreground", children: "Loading editor..." }),
|
|
3390
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MonacoWrapper, { value, onChange: handleChange, errors })
|
|
3391
|
+
}
|
|
3392
|
+
) })
|
|
3393
|
+
] });
|
|
3394
|
+
}
|
|
3395
|
+
|
|
3396
|
+
// src/form-builder/utils/logic-graph.ts
|
|
3397
|
+
function extractFieldRefs(expr) {
|
|
3398
|
+
const refs = [];
|
|
3399
|
+
if (expr.field) {
|
|
3400
|
+
refs.push({ field: expr.field, operator: expr.operator, value: expr.value });
|
|
3401
|
+
}
|
|
3402
|
+
if (expr.conditions) {
|
|
3403
|
+
for (const child of expr.conditions) {
|
|
3404
|
+
refs.push(...extractFieldRefs(child));
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
return refs;
|
|
3408
|
+
}
|
|
3409
|
+
function buildLogicGraph(schema) {
|
|
3410
|
+
const nodes = [];
|
|
3411
|
+
const edges = [];
|
|
3412
|
+
const nodeIds = /* @__PURE__ */ new Set();
|
|
3413
|
+
for (const section of schema.sections) {
|
|
3414
|
+
nodes.push({
|
|
3415
|
+
id: section.id,
|
|
3416
|
+
label: section.title || "Untitled Section",
|
|
3417
|
+
type: "section",
|
|
3418
|
+
sectionId: section.id,
|
|
3419
|
+
sectionTitle: section.title || "Untitled Section",
|
|
3420
|
+
hasCondition: !!section.showIf
|
|
3421
|
+
});
|
|
3422
|
+
nodeIds.add(section.id);
|
|
3423
|
+
if (section.showIf) {
|
|
3424
|
+
const refs = extractFieldRefs(section.showIf);
|
|
3425
|
+
for (const ref of refs) {
|
|
3426
|
+
edges.push({ from: ref.field, to: section.id, edgeType: "showIf", operator: ref.operator, value: ref.value });
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
if (section.onExit) {
|
|
3430
|
+
for (const rule of section.onExit.rules) {
|
|
3431
|
+
if (rule.jumpTo) {
|
|
3432
|
+
edges.push({ from: section.id, to: rule.jumpTo, edgeType: "onExit", jumpTo: rule.jumpTo });
|
|
3433
|
+
}
|
|
3434
|
+
}
|
|
3435
|
+
if (section.onExit.default) {
|
|
3436
|
+
edges.push({ from: section.id, to: section.onExit.default, edgeType: "onExit", jumpTo: section.onExit.default });
|
|
3437
|
+
}
|
|
3438
|
+
}
|
|
3439
|
+
for (const question of section.questions) {
|
|
3440
|
+
nodes.push({
|
|
3441
|
+
id: question.id,
|
|
3442
|
+
label: question.label || question.id,
|
|
3443
|
+
type: "field",
|
|
3444
|
+
fieldType: question.type,
|
|
3445
|
+
sectionId: section.id,
|
|
3446
|
+
sectionTitle: section.title || "Untitled Section",
|
|
3447
|
+
hasCondition: !!question.showIf
|
|
3448
|
+
});
|
|
3449
|
+
nodeIds.add(question.id);
|
|
3450
|
+
if (question.showIf) {
|
|
3451
|
+
const refs = extractFieldRefs(question.showIf);
|
|
3452
|
+
for (const ref of refs) {
|
|
3453
|
+
edges.push({ from: ref.field, to: question.id, edgeType: "showIf", operator: ref.operator, value: ref.value });
|
|
3454
|
+
}
|
|
3455
|
+
}
|
|
3456
|
+
}
|
|
3457
|
+
}
|
|
3458
|
+
const validEdges = edges.filter((e) => nodeIds.has(e.from) && nodeIds.has(e.to));
|
|
3459
|
+
return { nodes, edges: validEdges };
|
|
3460
|
+
}
|
|
3461
|
+
var SECTION_COLORS = [
|
|
3462
|
+
"#3b82f6",
|
|
3463
|
+
// blue
|
|
3464
|
+
"#8b5cf6",
|
|
3465
|
+
// violet
|
|
3466
|
+
"#06b6d4",
|
|
3467
|
+
// cyan
|
|
3468
|
+
"#f59e0b",
|
|
3469
|
+
// amber
|
|
3470
|
+
"#10b981",
|
|
3471
|
+
// emerald
|
|
3472
|
+
"#ef4444",
|
|
3473
|
+
// red
|
|
3474
|
+
"#ec4899",
|
|
3475
|
+
// pink
|
|
3476
|
+
"#6366f1"
|
|
3477
|
+
// indigo
|
|
3478
|
+
];
|
|
3479
|
+
var FIELD_NODE_WIDTH = 220;
|
|
3480
|
+
var FIELD_NODE_HEIGHT = 52;
|
|
3481
|
+
var SECTION_HEADER_HEIGHT = 40;
|
|
3482
|
+
var SECTION_PADDING_X = 16;
|
|
3483
|
+
var SECTION_PADDING_TOP = 12;
|
|
3484
|
+
var SECTION_PADDING_BOTTOM = 16;
|
|
3485
|
+
var FIELD_GAP = 10;
|
|
3486
|
+
var SECTION_GAP = 80;
|
|
3487
|
+
function formatEdgeLabel(edge) {
|
|
3488
|
+
if (edge.edgeType === "onExit") return "jump";
|
|
3489
|
+
if (!edge.operator) return "";
|
|
3490
|
+
const op = edge.operator;
|
|
3491
|
+
const val = edge.value;
|
|
3492
|
+
if (op === "exists") return "has value";
|
|
3493
|
+
if (op === "notExists") return "is empty";
|
|
3494
|
+
if (val === void 0 || val === null || val === "") return op;
|
|
3495
|
+
const short = String(val).length > 12 ? String(val).slice(0, 12) + "\u2026" : String(val);
|
|
3496
|
+
return `${op} ${short}`;
|
|
3497
|
+
}
|
|
3498
|
+
function buildReactFlowGraph(schema) {
|
|
3499
|
+
const graph = buildLogicGraph(schema);
|
|
3500
|
+
const nodes = [];
|
|
3501
|
+
const edges = [];
|
|
3502
|
+
let sectionX = 0;
|
|
3503
|
+
let maxSectionHeight = 0;
|
|
3504
|
+
for (const section of schema.sections) {
|
|
3505
|
+
const fieldCount = section.questions.length;
|
|
3506
|
+
const contentHeight = SECTION_HEADER_HEIGHT + SECTION_PADDING_TOP + fieldCount * FIELD_NODE_HEIGHT + Math.max(0, fieldCount - 1) * FIELD_GAP + SECTION_PADDING_BOTTOM;
|
|
3507
|
+
if (contentHeight > maxSectionHeight) maxSectionHeight = contentHeight;
|
|
3508
|
+
}
|
|
3509
|
+
if (maxSectionHeight < SECTION_HEADER_HEIGHT + SECTION_PADDING_TOP + SECTION_PADDING_BOTTOM + FIELD_NODE_HEIGHT) {
|
|
3510
|
+
maxSectionHeight = SECTION_HEADER_HEIGHT + SECTION_PADDING_TOP + SECTION_PADDING_BOTTOM + FIELD_NODE_HEIGHT;
|
|
3511
|
+
}
|
|
3512
|
+
const sectionWidth = FIELD_NODE_WIDTH + SECTION_PADDING_X * 2;
|
|
3513
|
+
for (let sIdx = 0; sIdx < schema.sections.length; sIdx++) {
|
|
3514
|
+
const section = schema.sections[sIdx];
|
|
3515
|
+
const colorIndex = sIdx;
|
|
3516
|
+
nodes.push({
|
|
3517
|
+
id: section.id,
|
|
3518
|
+
type: "sectionNode",
|
|
3519
|
+
position: { x: sectionX, y: 0 },
|
|
3520
|
+
data: {
|
|
3521
|
+
label: section.title || "Untitled Section",
|
|
3522
|
+
sectionId: section.id,
|
|
3523
|
+
fieldCount: section.questions.length,
|
|
3524
|
+
hasCondition: !!section.showIf,
|
|
3525
|
+
hasExitLogic: !!section.onExit,
|
|
3526
|
+
colorIndex
|
|
3527
|
+
},
|
|
3528
|
+
style: { width: sectionWidth, height: maxSectionHeight }
|
|
3529
|
+
});
|
|
3530
|
+
for (let fIdx = 0; fIdx < section.questions.length; fIdx++) {
|
|
3531
|
+
const question = section.questions[fIdx];
|
|
3532
|
+
const fieldY = SECTION_HEADER_HEIGHT + SECTION_PADDING_TOP + fIdx * (FIELD_NODE_HEIGHT + FIELD_GAP);
|
|
3533
|
+
nodes.push({
|
|
3534
|
+
id: question.id,
|
|
3535
|
+
type: "fieldNode",
|
|
3536
|
+
position: { x: SECTION_PADDING_X, y: fieldY },
|
|
3537
|
+
parentId: section.id,
|
|
3538
|
+
extent: "parent",
|
|
3539
|
+
data: {
|
|
3540
|
+
label: question.label || question.id,
|
|
3541
|
+
fieldType: question.type,
|
|
3542
|
+
sectionId: section.id,
|
|
3543
|
+
hasCondition: !!question.showIf,
|
|
3544
|
+
colorIndex
|
|
3545
|
+
},
|
|
3546
|
+
style: { width: FIELD_NODE_WIDTH }
|
|
3547
|
+
});
|
|
3548
|
+
}
|
|
3549
|
+
if (sIdx < schema.sections.length - 1) {
|
|
3550
|
+
const nextSection = schema.sections[sIdx + 1];
|
|
3551
|
+
edges.push({
|
|
3552
|
+
id: `pipeline-${section.id}-${nextSection.id}`,
|
|
3553
|
+
source: section.id,
|
|
3554
|
+
target: nextSection.id,
|
|
3555
|
+
type: "pipelineEdge",
|
|
3556
|
+
data: { edgeType: "pipeline" }
|
|
3557
|
+
});
|
|
3558
|
+
}
|
|
3559
|
+
sectionX += sectionWidth + SECTION_GAP;
|
|
3560
|
+
}
|
|
3561
|
+
for (let i = 0; i < graph.edges.length; i++) {
|
|
3562
|
+
const edge = graph.edges[i];
|
|
3563
|
+
edges.push({
|
|
3564
|
+
id: `e-${edge.from}-${edge.to}-${i}`,
|
|
3565
|
+
source: edge.from,
|
|
3566
|
+
target: edge.to,
|
|
3567
|
+
type: "conditionEdge",
|
|
3568
|
+
animated: edge.edgeType === "showIf",
|
|
3569
|
+
style: edge.edgeType === "onExit" ? { strokeDasharray: "6 3", stroke: "#f59e0b" } : void 0,
|
|
3570
|
+
label: formatEdgeLabel(edge),
|
|
3571
|
+
data: {
|
|
3572
|
+
edgeType: edge.edgeType,
|
|
3573
|
+
operator: edge.operator,
|
|
3574
|
+
value: edge.value,
|
|
3575
|
+
sourceId: edge.from,
|
|
3576
|
+
targetId: edge.to
|
|
3577
|
+
}
|
|
3578
|
+
});
|
|
3579
|
+
}
|
|
3580
|
+
return { nodes, edges };
|
|
3581
|
+
}
|
|
3582
|
+
function SectionNodeInner({ data }) {
|
|
3583
|
+
const d = data;
|
|
3584
|
+
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
3585
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group", style: { borderColor: color }, children: [
|
|
3586
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "target", position: react$1.Position.Left, className: "fc-flow-handle fc-flow-handle--section" }),
|
|
3587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-section-group__header", style: { background: color }, children: [
|
|
3588
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__label", children: d.label.length > 30 ? d.label.slice(0, 30) + "\u2026" : d.label }),
|
|
3589
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "fc-flow-section-group__meta", children: [
|
|
3590
|
+
d.fieldCount,
|
|
3591
|
+
" field",
|
|
3592
|
+
d.fieldCount !== 1 ? "s" : "",
|
|
3593
|
+
d.hasCondition && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-section-group__badge", title: "Has showIf condition", children: "?" }),
|
|
3594
|
+
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
|
+
] })
|
|
3596
|
+
] }),
|
|
3597
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "source", position: react$1.Position.Right, className: "fc-flow-handle fc-flow-handle--section" })
|
|
3598
|
+
] });
|
|
3599
|
+
}
|
|
3600
|
+
var SectionNode = react.memo(SectionNodeInner);
|
|
3601
|
+
function FieldNodeInner({ data }) {
|
|
3602
|
+
const d = data;
|
|
3603
|
+
const color = SECTION_COLORS[d.colorIndex % SECTION_COLORS.length];
|
|
3604
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3605
|
+
"div",
|
|
3606
|
+
{
|
|
3607
|
+
className: "fc-flow-field",
|
|
3608
|
+
style: {
|
|
3609
|
+
borderColor: d.hasCondition ? color : void 0,
|
|
3610
|
+
borderWidth: d.hasCondition ? 2 : 1
|
|
3611
|
+
},
|
|
3612
|
+
children: [
|
|
3613
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "target", position: react$1.Position.Left, className: "fc-flow-handle" }),
|
|
3614
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fc-flow-field__content", children: [
|
|
3615
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__label", children: d.label.length > 26 ? d.label.slice(0, 26) + "\u2026" : d.label }),
|
|
3616
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "fc-flow-field__type", children: d.fieldType })
|
|
3617
|
+
] }),
|
|
3618
|
+
d.hasCondition && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fc-flow-badge", style: { background: color }, title: "Has showIf condition", children: "?" }),
|
|
3619
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Handle, { type: "source", position: react$1.Position.Right, className: "fc-flow-handle" })
|
|
3620
|
+
]
|
|
3621
|
+
}
|
|
3622
|
+
);
|
|
3623
|
+
}
|
|
3624
|
+
var FieldNode = react.memo(FieldNodeInner);
|
|
3625
|
+
var logicFlowNodeTypes = {
|
|
3626
|
+
sectionNode: SectionNode,
|
|
3627
|
+
fieldNode: FieldNode
|
|
3628
|
+
};
|
|
3629
|
+
function ConditionEdgeInner({
|
|
3630
|
+
id,
|
|
3631
|
+
sourceX,
|
|
3632
|
+
sourceY,
|
|
3633
|
+
targetX,
|
|
3634
|
+
targetY,
|
|
3635
|
+
sourcePosition,
|
|
3636
|
+
targetPosition,
|
|
3637
|
+
label,
|
|
3638
|
+
style,
|
|
3639
|
+
data,
|
|
3640
|
+
markerEnd
|
|
3641
|
+
}) {
|
|
3642
|
+
const [edgePath, labelX, labelY] = react$1.getBezierPath({
|
|
3643
|
+
sourceX,
|
|
3644
|
+
sourceY,
|
|
3645
|
+
sourcePosition,
|
|
3646
|
+
targetX,
|
|
3647
|
+
targetY,
|
|
3648
|
+
targetPosition
|
|
3649
|
+
});
|
|
3650
|
+
const isJump = data?.edgeType === "onExit";
|
|
3651
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3652
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3653
|
+
react$1.BaseEdge,
|
|
3654
|
+
{
|
|
3655
|
+
id,
|
|
3656
|
+
path: edgePath,
|
|
3657
|
+
markerEnd,
|
|
3658
|
+
style: {
|
|
3659
|
+
stroke: isJump ? "#f59e0b" : "var(--primary, #3b82f6)",
|
|
3660
|
+
strokeWidth: 1.5,
|
|
3661
|
+
strokeOpacity: 0.7,
|
|
3662
|
+
...style
|
|
3663
|
+
}
|
|
3664
|
+
}
|
|
3665
|
+
),
|
|
3666
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(react$1.EdgeLabelRenderer, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3667
|
+
"div",
|
|
3668
|
+
{
|
|
3669
|
+
className: "fc-flow-edge-label",
|
|
3670
|
+
style: {
|
|
3671
|
+
transform: `translate(-50%, -50%) translate(${labelX}px, ${labelY}px)`,
|
|
3672
|
+
background: isJump ? "#f59e0b" : "var(--primary, #3b82f6)"
|
|
3673
|
+
},
|
|
3674
|
+
children: label
|
|
3675
|
+
}
|
|
3676
|
+
) })
|
|
3677
|
+
] });
|
|
3678
|
+
}
|
|
3679
|
+
var ConditionEdge = react.memo(ConditionEdgeInner);
|
|
3680
|
+
function PipelineEdgeInner({
|
|
3681
|
+
id,
|
|
3682
|
+
sourceX,
|
|
3683
|
+
sourceY,
|
|
3684
|
+
targetX,
|
|
3685
|
+
targetY,
|
|
3686
|
+
sourcePosition,
|
|
3687
|
+
targetPosition,
|
|
3688
|
+
markerEnd
|
|
3689
|
+
}) {
|
|
3690
|
+
const [edgePath] = react$1.getBezierPath({
|
|
3691
|
+
sourceX,
|
|
3692
|
+
sourceY,
|
|
3693
|
+
sourcePosition,
|
|
3694
|
+
targetX,
|
|
3695
|
+
targetY,
|
|
3696
|
+
targetPosition
|
|
3697
|
+
});
|
|
3698
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3699
|
+
react$1.BaseEdge,
|
|
3700
|
+
{
|
|
3701
|
+
id,
|
|
3702
|
+
path: edgePath,
|
|
3703
|
+
markerEnd,
|
|
3704
|
+
style: {
|
|
3705
|
+
stroke: "var(--muted-foreground, #71717a)",
|
|
3706
|
+
strokeWidth: 2,
|
|
3707
|
+
strokeOpacity: 0.4
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
);
|
|
3711
|
+
}
|
|
3712
|
+
var PipelineEdge = react.memo(PipelineEdgeInner);
|
|
3713
|
+
var logicFlowEdgeTypes = {
|
|
3714
|
+
conditionEdge: ConditionEdge,
|
|
3715
|
+
pipelineEdge: PipelineEdge
|
|
3716
|
+
};
|
|
3717
|
+
function findQuestion2(schema, fieldId) {
|
|
3718
|
+
for (const section of schema.sections) {
|
|
3719
|
+
for (const q of section.questions) {
|
|
3720
|
+
if (q.id === fieldId) return q;
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
return void 0;
|
|
3724
|
+
}
|
|
3725
|
+
function updateQuestionInSchema(schema, fieldId, updates) {
|
|
3726
|
+
return {
|
|
3727
|
+
...schema,
|
|
3728
|
+
sections: schema.sections.map((section) => ({
|
|
3729
|
+
...section,
|
|
3730
|
+
questions: section.questions.map(
|
|
3731
|
+
(q) => q.id === fieldId ? { ...q, ...updates } : q
|
|
3732
|
+
)
|
|
3733
|
+
}))
|
|
3734
|
+
};
|
|
3735
|
+
}
|
|
3736
|
+
function removeConditionForSource(showIf, sourceFieldId) {
|
|
3737
|
+
if (!showIf) return void 0;
|
|
3738
|
+
if (showIf.field === sourceFieldId) return void 0;
|
|
3739
|
+
if (showIf.field && showIf.field !== sourceFieldId) return showIf;
|
|
3740
|
+
if (showIf.conditions) {
|
|
3741
|
+
const filtered = showIf.conditions.map((c) => removeConditionForSource(c, sourceFieldId)).filter((c) => c !== void 0);
|
|
3742
|
+
if (filtered.length === 0) return void 0;
|
|
3743
|
+
if (filtered.length === 1) return filtered[0];
|
|
3744
|
+
return { ...showIf, conditions: filtered };
|
|
3745
|
+
}
|
|
3746
|
+
return showIf;
|
|
3747
|
+
}
|
|
3748
|
+
var defaultEdgeOptions = {
|
|
3749
|
+
markerEnd: {
|
|
3750
|
+
type: react$1.MarkerType.ArrowClosed,
|
|
3751
|
+
width: 16,
|
|
3752
|
+
height: 12
|
|
3753
|
+
}
|
|
3754
|
+
};
|
|
3755
|
+
function LogicFlowEditor({ schema, onChange, onClose }) {
|
|
3756
|
+
const noSections = schema.sections.length === 0;
|
|
3757
|
+
const flowGraph = react.useMemo(() => buildReactFlowGraph(schema), [schema]);
|
|
3758
|
+
const [nodes, setNodes, onNodesChange] = react$1.useNodesState(flowGraph.nodes);
|
|
3759
|
+
const [edges, setEdges, onEdgesChange] = react$1.useEdgesState(flowGraph.edges);
|
|
3760
|
+
const [selectedFieldId, setSelectedFieldId] = react.useState(null);
|
|
3761
|
+
const selectedQuestion = selectedFieldId ? findQuestion2(schema, selectedFieldId) : void 0;
|
|
3762
|
+
react.useEffect(() => {
|
|
3763
|
+
setNodes(flowGraph.nodes);
|
|
3764
|
+
setEdges(flowGraph.edges);
|
|
3765
|
+
}, [flowGraph, setNodes, setEdges]);
|
|
3766
|
+
const sectionIds = react.useMemo(() => {
|
|
3767
|
+
const ids = [];
|
|
3768
|
+
for (const section of schema.sections) {
|
|
3769
|
+
ids.push(section.id);
|
|
3770
|
+
}
|
|
3771
|
+
return ids;
|
|
3772
|
+
}, [schema]);
|
|
3773
|
+
const onNodeClick = react.useCallback(
|
|
3774
|
+
(_event, node) => {
|
|
3775
|
+
if (node.type === "fieldNode") {
|
|
3776
|
+
setSelectedFieldId(node.id);
|
|
3777
|
+
}
|
|
3778
|
+
},
|
|
3779
|
+
[]
|
|
3780
|
+
);
|
|
3781
|
+
const onConnect = react.useCallback(
|
|
3782
|
+
(connection) => {
|
|
3783
|
+
if (!connection.source || !connection.target) return;
|
|
3784
|
+
const targetQuestion = findQuestion2(schema, connection.target);
|
|
3785
|
+
if (!targetQuestion) return;
|
|
3786
|
+
const newCondition = {
|
|
3787
|
+
field: connection.source,
|
|
3788
|
+
operator: "exists"
|
|
3789
|
+
};
|
|
3790
|
+
let updatedShowIf;
|
|
3791
|
+
const existing = targetQuestion.showIf;
|
|
3792
|
+
if (!existing) {
|
|
3793
|
+
updatedShowIf = { combine: "AND", conditions: [newCondition] };
|
|
3794
|
+
} else {
|
|
3795
|
+
updatedShowIf = {
|
|
3796
|
+
...existing,
|
|
3797
|
+
conditions: [...existing.conditions ?? [], newCondition]
|
|
3798
|
+
};
|
|
3799
|
+
}
|
|
3800
|
+
const updatedSchema = updateQuestionInSchema(schema, connection.target, {
|
|
3801
|
+
showIf: updatedShowIf
|
|
3802
|
+
});
|
|
3803
|
+
onChange(updatedSchema);
|
|
3804
|
+
setSelectedFieldId(connection.target);
|
|
3805
|
+
},
|
|
3806
|
+
[schema, onChange]
|
|
3807
|
+
);
|
|
3808
|
+
const onEdgesDelete = react.useCallback(
|
|
3809
|
+
(deletedEdges) => {
|
|
3810
|
+
let updatedSchema = schema;
|
|
3811
|
+
for (const edge of deletedEdges) {
|
|
3812
|
+
const edgeData = edge.data;
|
|
3813
|
+
if (!edgeData) continue;
|
|
3814
|
+
const targetId = edge.target;
|
|
3815
|
+
const sourceId = edge.source;
|
|
3816
|
+
const edgeType = edgeData.edgeType;
|
|
3817
|
+
if (edgeType === "showIf") {
|
|
3818
|
+
const question = findQuestion2(updatedSchema, targetId);
|
|
3819
|
+
if (!question) continue;
|
|
3820
|
+
const updatedShowIf = removeConditionForSource(
|
|
3821
|
+
question.showIf,
|
|
3822
|
+
sourceId
|
|
3823
|
+
);
|
|
3824
|
+
updatedSchema = updateQuestionInSchema(updatedSchema, targetId, {
|
|
3825
|
+
showIf: updatedShowIf
|
|
3826
|
+
});
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
onChange(updatedSchema);
|
|
3830
|
+
},
|
|
3831
|
+
[schema, onChange]
|
|
3832
|
+
);
|
|
3833
|
+
const handleConditionUpdate = react.useCallback(
|
|
3834
|
+
(updates) => {
|
|
3835
|
+
if (!selectedFieldId) return;
|
|
3836
|
+
const updatedSchema = updateQuestionInSchema(schema, selectedFieldId, updates);
|
|
3837
|
+
onChange(updatedSchema);
|
|
3838
|
+
},
|
|
3839
|
+
[schema, selectedFieldId, onChange]
|
|
3840
|
+
);
|
|
3841
|
+
const showIfCount = flowGraph.edges.filter(
|
|
3842
|
+
(e) => e.data?.edgeType === "showIf"
|
|
3843
|
+
).length;
|
|
3844
|
+
const jumpCount = flowGraph.edges.filter(
|
|
3845
|
+
(e) => e.data?.edgeType === "onExit"
|
|
3846
|
+
).length;
|
|
3847
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-50 flex flex-col bg-background/95 backdrop-blur-sm", children: [
|
|
3848
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "h-12 shrink-0 flex items-center justify-between px-4 border-b border-border bg-card", children: [
|
|
3849
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
3850
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 16, className: "text-primary" }),
|
|
3851
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: "Logic Flow" }),
|
|
3852
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3853
|
+
showIfCount,
|
|
3854
|
+
" condition",
|
|
3855
|
+
showIfCount !== 1 ? "s" : "",
|
|
3856
|
+
jumpCount > 0 && ` \xB7 ${jumpCount} jump${jumpCount !== 1 ? "s" : ""}`,
|
|
3857
|
+
" \xB7 ",
|
|
3858
|
+
sectionIds.length,
|
|
3859
|
+
" section",
|
|
3860
|
+
sectionIds.length !== 1 ? "s" : ""
|
|
3861
|
+
] })
|
|
3862
|
+
] }),
|
|
3863
|
+
/* @__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 and press Delete to remove" }),
|
|
3865
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-sm", onClick: onClose, title: "Close logic flow", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, strokeWidth: 1.75 }) })
|
|
3866
|
+
] })
|
|
3867
|
+
] }),
|
|
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-2", children: [
|
|
3869
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.GitBranch, { size: 32, className: "mx-auto opacity-40" }),
|
|
3870
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium", children: "No sections found" }),
|
|
3871
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs max-w-xs", children: "Add sections and fields to your form to see the logic flow pipeline." })
|
|
3872
|
+
] }) }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 flex", children: [
|
|
3873
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3874
|
+
react$1.ReactFlow,
|
|
3875
|
+
{
|
|
3876
|
+
nodes,
|
|
3877
|
+
edges,
|
|
3878
|
+
onNodesChange,
|
|
3879
|
+
onEdgesChange,
|
|
3880
|
+
onNodeClick,
|
|
3881
|
+
onConnect,
|
|
3882
|
+
onEdgesDelete,
|
|
3883
|
+
nodeTypes: logicFlowNodeTypes,
|
|
3884
|
+
edgeTypes: logicFlowEdgeTypes,
|
|
3885
|
+
defaultEdgeOptions,
|
|
3886
|
+
fitView: true,
|
|
3887
|
+
fitViewOptions: { padding: 0.2 },
|
|
3888
|
+
deleteKeyCode: ["Backspace", "Delete"],
|
|
3889
|
+
proOptions: { hideAttribution: true },
|
|
3890
|
+
children: [
|
|
3891
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Background, { gap: 20, size: 1 }),
|
|
3892
|
+
/* @__PURE__ */ jsxRuntime.jsx(react$1.Controls, { showInteractive: false }),
|
|
3893
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3894
|
+
react$1.MiniMap,
|
|
3895
|
+
{
|
|
3896
|
+
nodeColor: (node) => {
|
|
3897
|
+
const d = node.data;
|
|
3898
|
+
const idx = d.colorIndex ?? 0;
|
|
3899
|
+
return SECTION_COLORS[idx % SECTION_COLORS.length];
|
|
3900
|
+
},
|
|
3901
|
+
maskColor: "rgba(0, 0, 0, 0.3)"
|
|
3902
|
+
}
|
|
3903
|
+
)
|
|
3904
|
+
]
|
|
3905
|
+
}
|
|
3906
|
+
) }),
|
|
3907
|
+
selectedFieldId && selectedQuestion && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-72 border-l border-border bg-card overflow-auto", children: [
|
|
3908
|
+
/* @__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: [
|
|
3910
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-semibold truncate", children: selectedQuestion.label || selectedQuestion.id }),
|
|
3911
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-muted-foreground", children: selectedQuestion.type })
|
|
3912
|
+
] }),
|
|
3913
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3914
|
+
fieldcraftReact.Button,
|
|
3915
|
+
{
|
|
3916
|
+
variant: "ghost",
|
|
3917
|
+
size: "icon-xs",
|
|
3918
|
+
onClick: () => setSelectedFieldId(null),
|
|
3919
|
+
title: "Close panel",
|
|
3920
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 14, strokeWidth: 1.75 })
|
|
3921
|
+
}
|
|
3922
|
+
)
|
|
3923
|
+
] }),
|
|
3924
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3925
|
+
ConditionEditor,
|
|
3926
|
+
{
|
|
3927
|
+
question: selectedQuestion,
|
|
3928
|
+
schema,
|
|
3929
|
+
onUpdate: handleConditionUpdate
|
|
3930
|
+
}
|
|
3931
|
+
) })
|
|
3932
|
+
] })
|
|
3933
|
+
] }),
|
|
3934
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 border-t border-border bg-card flex items-center gap-4 text-xs text-muted-foreground flex-wrap", children: [
|
|
3935
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3936
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-0.5 rounded", style: { background: "var(--muted-foreground)", opacity: 0.4 } }),
|
|
3937
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "flow" })
|
|
3938
|
+
] }),
|
|
3939
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3940
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-0.5 bg-primary rounded" }),
|
|
3941
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "showIf" })
|
|
3942
|
+
] }),
|
|
3943
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3944
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-0.5 rounded", style: { background: "#f59e0b" } }),
|
|
3945
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "jump" })
|
|
3946
|
+
] }),
|
|
3947
|
+
sectionIds.map((id, i) => {
|
|
3948
|
+
const section = schema.sections.find((s) => s.id === id);
|
|
3949
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
3950
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-3 h-3 rounded-sm", style: { background: SECTION_COLORS[i % SECTION_COLORS.length] } }),
|
|
3951
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: section?.title || id })
|
|
3952
|
+
] }, id);
|
|
3953
|
+
})
|
|
3954
|
+
] })
|
|
3955
|
+
] });
|
|
3956
|
+
}
|
|
3957
|
+
function TemplateGallery({ templates, onSelect, onClose }) {
|
|
3958
|
+
const [search, setSearch] = react.useState("");
|
|
3959
|
+
const [activeCategory, setActiveCategory] = react.useState("all");
|
|
3960
|
+
const [confirmTemplate, setConfirmTemplate] = react.useState(null);
|
|
3961
|
+
const categories = react.useMemo(() => {
|
|
3962
|
+
const cats = /* @__PURE__ */ new Set();
|
|
3963
|
+
for (const t of templates) cats.add(t.meta.category);
|
|
3964
|
+
return ["all", ...Array.from(cats)];
|
|
3965
|
+
}, [templates]);
|
|
3966
|
+
const filtered = react.useMemo(() => {
|
|
3967
|
+
return templates.filter((t) => {
|
|
3968
|
+
const matchesCategory = activeCategory === "all" || t.meta.category === activeCategory;
|
|
3969
|
+
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()));
|
|
3970
|
+
return matchesCategory && matchesSearch;
|
|
3971
|
+
});
|
|
3972
|
+
}, [templates, activeCategory, search]);
|
|
3973
|
+
const handleConfirm = () => {
|
|
3974
|
+
if (confirmTemplate) {
|
|
3975
|
+
onSelect(confirmTemplate);
|
|
3976
|
+
setConfirmTemplate(null);
|
|
3977
|
+
onClose();
|
|
3978
|
+
}
|
|
3979
|
+
};
|
|
3980
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50 backdrop-blur-sm", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-3xl max-h-[85vh] mx-4 bg-card border border-border rounded-lg shadow-xl flex flex-col overflow-hidden", children: [
|
|
3981
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 flex items-center justify-between px-4 py-3 border-b border-border", children: [
|
|
3982
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
3983
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutTemplate, { size: 18, className: "text-primary", strokeWidth: 1.75 }),
|
|
3984
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-sm font-semibold", children: "Template Gallery" }),
|
|
3985
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
|
|
3986
|
+
"(",
|
|
3987
|
+
templates.length,
|
|
3988
|
+
" templates)"
|
|
3989
|
+
] })
|
|
3990
|
+
] }),
|
|
3991
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "icon-sm", onClick: onClose, title: "Close", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { size: 16, strokeWidth: 1.75 }) })
|
|
3992
|
+
] }),
|
|
3993
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 space-y-2 border-b border-border", children: [
|
|
3994
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
|
|
3995
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Search, { size: 14, className: "absolute left-2.5 top-1/2 -translate-y-1/2 text-muted-foreground", strokeWidth: 1.75 }),
|
|
3996
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3997
|
+
"input",
|
|
3998
|
+
{
|
|
3999
|
+
type: "text",
|
|
4000
|
+
placeholder: "Search templates...",
|
|
4001
|
+
value: search,
|
|
4002
|
+
onChange: (e) => setSearch(e.target.value),
|
|
4003
|
+
className: "w-full pl-8 pr-3 py-1.5 text-sm bg-background border border-border rounded-md text-foreground placeholder:text-muted-foreground focus:outline-none focus:ring-1 focus:ring-primary"
|
|
4004
|
+
}
|
|
4005
|
+
)
|
|
4006
|
+
] }),
|
|
4007
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 overflow-x-auto pb-0.5", children: categories.map((cat) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4008
|
+
"button",
|
|
4009
|
+
{
|
|
4010
|
+
type: "button",
|
|
4011
|
+
onClick: () => setActiveCategory(cat),
|
|
4012
|
+
className: `shrink-0 px-2.5 py-1 rounded-md text-xs font-medium transition-colors ${activeCategory === cat ? "bg-primary text-primary-foreground" : "bg-muted text-muted-foreground hover:text-foreground"}`,
|
|
4013
|
+
children: cat === "all" ? "All" : cat.charAt(0).toUpperCase() + cat.slice(1)
|
|
4014
|
+
},
|
|
4015
|
+
cat
|
|
4016
|
+
)) })
|
|
4017
|
+
] }),
|
|
4018
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 overflow-y-auto p-4", children: filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center justify-center h-40 text-muted-foreground text-sm", children: /* @__PURE__ */ jsxRuntime.jsx("p", { children: "No templates match your search." }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-3", children: filtered.map((template) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4019
|
+
"button",
|
|
4020
|
+
{
|
|
4021
|
+
type: "button",
|
|
4022
|
+
onClick: () => setConfirmTemplate(template),
|
|
4023
|
+
className: "text-left p-3 rounded-lg border border-border bg-background hover:border-primary/50 hover:bg-primary/5 transition-colors group",
|
|
4024
|
+
children: [
|
|
4025
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-2 mb-1.5", children: [
|
|
4026
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-sm font-medium text-foreground group-hover:text-primary transition-colors", children: template.meta.name }),
|
|
4027
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "shrink-0 px-1.5 py-0.5 rounded text-[10px] font-medium bg-muted text-muted-foreground", children: template.meta.category })
|
|
4028
|
+
] }),
|
|
4029
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-2 line-clamp-2", children: template.meta.description }),
|
|
4030
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 text-xs text-muted-foreground", children: [
|
|
4031
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
|
|
4032
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 11, strokeWidth: 1.75 }),
|
|
4033
|
+
template.meta.fieldCount,
|
|
4034
|
+
" field",
|
|
4035
|
+
template.meta.fieldCount !== 1 ? "s" : ""
|
|
4036
|
+
] }),
|
|
4037
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-1", children: [
|
|
4038
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Layers, { size: 11, strokeWidth: 1.75 }),
|
|
4039
|
+
template.meta.sectionCount,
|
|
4040
|
+
" section",
|
|
4041
|
+
template.meta.sectionCount !== 1 ? "s" : ""
|
|
4042
|
+
] })
|
|
4043
|
+
] })
|
|
4044
|
+
]
|
|
4045
|
+
},
|
|
4046
|
+
template.meta.id
|
|
4047
|
+
)) }) }),
|
|
4048
|
+
confirmTemplate && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-3 border-t border-border bg-muted/50 flex items-center justify-between gap-3", children: [
|
|
4049
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-sm", children: [
|
|
4050
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Use " }),
|
|
4051
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-foreground", children: confirmTemplate.meta.name }),
|
|
4052
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "? This will replace the current form." })
|
|
4053
|
+
] }),
|
|
4054
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 shrink-0", children: [
|
|
4055
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "ghost", size: "sm", onClick: () => setConfirmTemplate(null), children: "Cancel" }),
|
|
4056
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { size: "sm", onClick: handleConfirm, children: "Use Template" })
|
|
4057
|
+
] })
|
|
4058
|
+
] })
|
|
4059
|
+
] }) });
|
|
4060
|
+
}
|
|
4061
|
+
function useDebouncedValidation(delayMs = 500) {
|
|
4062
|
+
const [errors, setErrors] = react.useState([]);
|
|
4063
|
+
const timerRef = react.useRef(null);
|
|
4064
|
+
const validate = react.useCallback(
|
|
4065
|
+
(text) => {
|
|
4066
|
+
if (timerRef.current) {
|
|
4067
|
+
clearTimeout(timerRef.current);
|
|
4068
|
+
}
|
|
4069
|
+
timerRef.current = setTimeout(() => {
|
|
4070
|
+
const result = [];
|
|
4071
|
+
let parsed;
|
|
4072
|
+
try {
|
|
4073
|
+
parsed = JSON.parse(text);
|
|
4074
|
+
} catch (err) {
|
|
4075
|
+
if (err instanceof SyntaxError) {
|
|
4076
|
+
const posMatch = err.message.match(/position\s+(\d+)/i);
|
|
4077
|
+
let line = 1;
|
|
4078
|
+
let column = 1;
|
|
4079
|
+
if (posMatch) {
|
|
4080
|
+
const pos = parseInt(posMatch[1], 10);
|
|
4081
|
+
const upToPos = text.slice(0, pos);
|
|
4082
|
+
line = (upToPos.match(/\n/g) || []).length + 1;
|
|
4083
|
+
column = pos - upToPos.lastIndexOf("\n");
|
|
4084
|
+
}
|
|
4085
|
+
result.push({ message: err.message, line, column, endLine: line, endColumn: column + 1 });
|
|
4086
|
+
} else {
|
|
4087
|
+
result.push({ message: "Invalid JSON" });
|
|
4088
|
+
}
|
|
4089
|
+
setErrors(result);
|
|
4090
|
+
return;
|
|
4091
|
+
}
|
|
4092
|
+
try {
|
|
4093
|
+
fieldcraftCore.validateSchema(parsed);
|
|
4094
|
+
} catch (err) {
|
|
4095
|
+
if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
4096
|
+
for (const issue of err.issues) {
|
|
4097
|
+
result.push({
|
|
4098
|
+
message: issue.message,
|
|
4099
|
+
path: issue.path?.join(".")
|
|
4100
|
+
});
|
|
4101
|
+
}
|
|
4102
|
+
} else if (err instanceof Error) {
|
|
4103
|
+
result.push({ message: err.message });
|
|
4104
|
+
}
|
|
4105
|
+
}
|
|
4106
|
+
setErrors(result);
|
|
4107
|
+
}, delayMs);
|
|
4108
|
+
},
|
|
4109
|
+
[delayMs]
|
|
4110
|
+
);
|
|
4111
|
+
return { errors, validate };
|
|
4112
|
+
}
|
|
3115
4113
|
var ThemeCtx = react.createContext({});
|
|
3116
4114
|
function useBuilderTheme() {
|
|
3117
4115
|
return react.useContext(ThemeCtx);
|
|
@@ -3184,7 +4182,16 @@ var FormBuilderErrorBoundary = class extends react.Component {
|
|
|
3184
4182
|
}
|
|
3185
4183
|
};
|
|
3186
4184
|
function FormBuilderCore(props) {
|
|
3187
|
-
const { initialSchema = DEFAULT_SCHEMA, onChange, onSave, height = "100vh", theme, className, toolbarExtra, questionTypes, palette } = props;
|
|
4185
|
+
const { initialSchema = DEFAULT_SCHEMA, onChange, onSave, height = "100vh", theme, className, toolbarExtra, questionTypes, palette, preview, templates, schemaUrl } = props;
|
|
4186
|
+
const [viewMode, setViewMode] = react.useState("design");
|
|
4187
|
+
const [jsonText, setJsonText] = react.useState("");
|
|
4188
|
+
const [jsonSwitchError, setJsonSwitchError] = react.useState(null);
|
|
4189
|
+
const [showLogicMap, setShowLogicMap] = react.useState(false);
|
|
4190
|
+
const [showTemplateGallery, setShowTemplateGallery] = react.useState(false);
|
|
4191
|
+
const [saveValidationErrors, setSaveValidationErrors] = react.useState(null);
|
|
4192
|
+
const [schemaUrlLoading, setSchemaUrlLoading] = react.useState(!!schemaUrl);
|
|
4193
|
+
const [schemaUrlError, setSchemaUrlError] = react.useState(null);
|
|
4194
|
+
const { errors: jsonErrors, validate: validateJson } = useDebouncedValidation(400);
|
|
3188
4195
|
const mergedQuestionTypes = questionTypes ? { ...QUESTION_TYPE_INFO, ...questionTypes } : QUESTION_TYPE_INFO;
|
|
3189
4196
|
const builderState = useBuilderState(initialSchema);
|
|
3190
4197
|
const dragDrop = useDragDrop(builderState);
|
|
@@ -3200,15 +4207,54 @@ function FormBuilderCore(props) {
|
|
|
3200
4207
|
setMobilePanel("none");
|
|
3201
4208
|
}
|
|
3202
4209
|
}, [dragDrop.activeDragItem]);
|
|
4210
|
+
react.useEffect(() => {
|
|
4211
|
+
if (!schemaUrl) return;
|
|
4212
|
+
let cancelled = false;
|
|
4213
|
+
setSchemaUrlLoading(true);
|
|
4214
|
+
setSchemaUrlError(null);
|
|
4215
|
+
fetch(schemaUrl).then((res) => {
|
|
4216
|
+
if (!res.ok) throw new Error(`HTTP ${res.status}: ${res.statusText}`);
|
|
4217
|
+
return res.json();
|
|
4218
|
+
}).then((json) => {
|
|
4219
|
+
if (cancelled) return;
|
|
4220
|
+
try {
|
|
4221
|
+
const validated = fieldcraftCore.validateSchema(json);
|
|
4222
|
+
builderState.resetSchema(validated);
|
|
4223
|
+
} catch (err) {
|
|
4224
|
+
if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
4225
|
+
setSchemaUrlError(`Invalid schema: ${err.issues[0]?.message ?? "validation failed"}`);
|
|
4226
|
+
} else {
|
|
4227
|
+
setSchemaUrlError(err.message);
|
|
4228
|
+
}
|
|
4229
|
+
}
|
|
4230
|
+
setSchemaUrlLoading(false);
|
|
4231
|
+
}).catch((err) => {
|
|
4232
|
+
if (cancelled) return;
|
|
4233
|
+
setSchemaUrlError(err.message ?? "Failed to fetch schema");
|
|
4234
|
+
setSchemaUrlLoading(false);
|
|
4235
|
+
});
|
|
4236
|
+
return () => {
|
|
4237
|
+
cancelled = true;
|
|
4238
|
+
};
|
|
4239
|
+
}, [schemaUrl]);
|
|
3203
4240
|
react.useEffect(() => {
|
|
3204
4241
|
if (onChange && builderState.isDirty) {
|
|
3205
4242
|
onChange(builderState.schema);
|
|
3206
4243
|
}
|
|
3207
4244
|
}, [builderState.schema, builderState.isDirty, onChange]);
|
|
3208
4245
|
const handleSave = react.useCallback(() => {
|
|
3209
|
-
if (onSave)
|
|
4246
|
+
if (!onSave) return;
|
|
4247
|
+
try {
|
|
4248
|
+
fieldcraftCore.validateSchema(builderState.schema);
|
|
4249
|
+
setSaveValidationErrors(null);
|
|
3210
4250
|
onSave(builderState.schema);
|
|
3211
4251
|
builderState.markClean();
|
|
4252
|
+
} catch (err) {
|
|
4253
|
+
if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
4254
|
+
setSaveValidationErrors(err.issues.map((issue) => issue.message));
|
|
4255
|
+
} else {
|
|
4256
|
+
setSaveValidationErrors([err.message ?? "Unknown validation error"]);
|
|
4257
|
+
}
|
|
3212
4258
|
}
|
|
3213
4259
|
}, [onSave, builderState]);
|
|
3214
4260
|
const handleExport = react.useCallback(() => {
|
|
@@ -3251,6 +4297,32 @@ ${details}`);
|
|
|
3251
4297
|
},
|
|
3252
4298
|
[builderState]
|
|
3253
4299
|
);
|
|
4300
|
+
const handleViewModeChange = react.useCallback(
|
|
4301
|
+
(newMode) => {
|
|
4302
|
+
setJsonSwitchError(null);
|
|
4303
|
+
if (viewMode === "json" && newMode !== "json") {
|
|
4304
|
+
try {
|
|
4305
|
+
const parsed = JSON.parse(jsonText);
|
|
4306
|
+
const validated = fieldcraftCore.validateSchema(parsed);
|
|
4307
|
+
builderState.resetSchema(validated);
|
|
4308
|
+
} catch (err) {
|
|
4309
|
+
if (err instanceof SyntaxError) {
|
|
4310
|
+
setJsonSwitchError("Cannot switch: JSON has syntax errors");
|
|
4311
|
+
} else if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
4312
|
+
setJsonSwitchError(`Cannot switch: ${err.issues[0]?.message ?? "Invalid schema"}`);
|
|
4313
|
+
} else {
|
|
4314
|
+
setJsonSwitchError("Cannot switch: Invalid schema");
|
|
4315
|
+
}
|
|
4316
|
+
return;
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
if (newMode === "json") {
|
|
4320
|
+
setJsonText(JSON.stringify(builderState.schema, null, 2));
|
|
4321
|
+
}
|
|
4322
|
+
setViewMode(newMode);
|
|
4323
|
+
},
|
|
4324
|
+
[viewMode, jsonText, builderState]
|
|
4325
|
+
);
|
|
3254
4326
|
const handleKeyDown = react.useCallback(
|
|
3255
4327
|
(e) => {
|
|
3256
4328
|
const mod = e.metaKey || e.ctrlKey;
|
|
@@ -3352,8 +4424,74 @@ ${details}`);
|
|
|
3352
4424
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "mx-2 h-5" }),
|
|
3353
4425
|
builderState.isDirty && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-primary", role: "status", children: "Unsaved changes" })
|
|
3354
4426
|
] }),
|
|
3355
|
-
/* @__PURE__ */ jsxRuntime.
|
|
4427
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2", children: [
|
|
4428
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5 bg-muted rounded-md p-0.5", children: [
|
|
4429
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4430
|
+
fieldcraftReact.Button,
|
|
4431
|
+
{
|
|
4432
|
+
variant: viewMode === "design" ? "secondary" : "ghost",
|
|
4433
|
+
size: "sm",
|
|
4434
|
+
onClick: () => handleViewModeChange("design"),
|
|
4435
|
+
className: "gap-1.5 h-7 px-2.5 text-xs",
|
|
4436
|
+
children: [
|
|
4437
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PencilRuler, { size: 13, strokeWidth: 1.75 }),
|
|
4438
|
+
"Design"
|
|
4439
|
+
]
|
|
4440
|
+
}
|
|
4441
|
+
),
|
|
4442
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4443
|
+
fieldcraftReact.Button,
|
|
4444
|
+
{
|
|
4445
|
+
variant: viewMode === "preview" ? "secondary" : "ghost",
|
|
4446
|
+
size: "sm",
|
|
4447
|
+
onClick: () => handleViewModeChange("preview"),
|
|
4448
|
+
className: "gap-1.5 h-7 px-2.5 text-xs",
|
|
4449
|
+
children: [
|
|
4450
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { size: 13, strokeWidth: 1.75 }),
|
|
4451
|
+
"Preview"
|
|
4452
|
+
]
|
|
4453
|
+
}
|
|
4454
|
+
),
|
|
4455
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4456
|
+
fieldcraftReact.Button,
|
|
4457
|
+
{
|
|
4458
|
+
variant: viewMode === "json" ? "secondary" : "ghost",
|
|
4459
|
+
size: "sm",
|
|
4460
|
+
onClick: () => handleViewModeChange("json"),
|
|
4461
|
+
className: "gap-1.5 h-7 px-2.5 text-xs",
|
|
4462
|
+
children: [
|
|
4463
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code, { size: 13, strokeWidth: 1.75 }),
|
|
4464
|
+
"JSON"
|
|
4465
|
+
]
|
|
4466
|
+
}
|
|
4467
|
+
)
|
|
4468
|
+
] }),
|
|
4469
|
+
toolbarExtra
|
|
4470
|
+
] }),
|
|
3356
4471
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-end gap-1.5", children: [
|
|
4472
|
+
templates && templates.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4473
|
+
fieldcraftReact.Button,
|
|
4474
|
+
{
|
|
4475
|
+
variant: "ghost",
|
|
4476
|
+
size: "icon-sm",
|
|
4477
|
+
onClick: () => setShowTemplateGallery(true),
|
|
4478
|
+
title: "Browse templates",
|
|
4479
|
+
"aria-label": "Template gallery",
|
|
4480
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.LayoutTemplate, { size: 15, strokeWidth: 1.75 })
|
|
4481
|
+
}
|
|
4482
|
+
),
|
|
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
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "mx-1 h-5" }),
|
|
3357
4495
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3358
4496
|
fieldcraftReact.Button,
|
|
3359
4497
|
{
|
|
@@ -3397,6 +4535,47 @@ ${details}`);
|
|
|
3397
4535
|
}
|
|
3398
4536
|
) }),
|
|
3399
4537
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-1", children: [
|
|
4538
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-0.5 bg-muted rounded-md p-0.5", children: [
|
|
4539
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4540
|
+
fieldcraftReact.Button,
|
|
4541
|
+
{
|
|
4542
|
+
variant: viewMode === "design" ? "secondary" : "ghost",
|
|
4543
|
+
size: "sm",
|
|
4544
|
+
onClick: () => handleViewModeChange("design"),
|
|
4545
|
+
className: "gap-1 h-7 px-2 text-xs",
|
|
4546
|
+
children: [
|
|
4547
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.PencilRuler, { size: 12, strokeWidth: 1.75 }),
|
|
4548
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Design" })
|
|
4549
|
+
]
|
|
4550
|
+
}
|
|
4551
|
+
),
|
|
4552
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4553
|
+
fieldcraftReact.Button,
|
|
4554
|
+
{
|
|
4555
|
+
variant: viewMode === "preview" ? "secondary" : "ghost",
|
|
4556
|
+
size: "sm",
|
|
4557
|
+
onClick: () => handleViewModeChange("preview"),
|
|
4558
|
+
className: "gap-1 h-7 px-2 text-xs",
|
|
4559
|
+
children: [
|
|
4560
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Eye, { size: 12, strokeWidth: 1.75 }),
|
|
4561
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "Preview" })
|
|
4562
|
+
]
|
|
4563
|
+
}
|
|
4564
|
+
),
|
|
4565
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4566
|
+
fieldcraftReact.Button,
|
|
4567
|
+
{
|
|
4568
|
+
variant: viewMode === "json" ? "secondary" : "ghost",
|
|
4569
|
+
size: "sm",
|
|
4570
|
+
onClick: () => handleViewModeChange("json"),
|
|
4571
|
+
className: "gap-1 h-7 px-2 text-xs",
|
|
4572
|
+
children: [
|
|
4573
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Code, { size: 12, strokeWidth: 1.75 }),
|
|
4574
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "hidden sm:inline", children: "JSON" })
|
|
4575
|
+
]
|
|
4576
|
+
}
|
|
4577
|
+
)
|
|
4578
|
+
] }),
|
|
3400
4579
|
toolbarExtra,
|
|
3401
4580
|
/* @__PURE__ */ jsxRuntime.jsxs(fieldcraftReact.Button, { onClick: handleSave, size: "sm", className: "border-0 shadow-sm fcb-glow ml-1", "aria-label": "Save form", children: [
|
|
3402
4581
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { size: 14, strokeWidth: 2 }),
|
|
@@ -3485,7 +4664,50 @@ ${details}`);
|
|
|
3485
4664
|
"aria-hidden": "true"
|
|
3486
4665
|
}
|
|
3487
4666
|
),
|
|
3488
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
4667
|
+
jsonSwitchError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 bg-destructive/10 border-b border-destructive/20 text-destructive text-xs flex items-center justify-between", children: [
|
|
4668
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: jsonSwitchError }),
|
|
4669
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setJsonSwitchError(null), className: "ml-2 hover:underline", children: "Dismiss" })
|
|
4670
|
+
] }),
|
|
4671
|
+
saveValidationErrors && saveValidationErrors.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 bg-destructive/10 border-b border-destructive/20 text-xs", children: [
|
|
4672
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1", children: [
|
|
4673
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold text-destructive", children: [
|
|
4674
|
+
"Schema validation failed (",
|
|
4675
|
+
saveValidationErrors.length,
|
|
4676
|
+
" issue",
|
|
4677
|
+
saveValidationErrors.length !== 1 ? "s" : "",
|
|
4678
|
+
")"
|
|
4679
|
+
] }),
|
|
4680
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setSaveValidationErrors(null), className: "text-destructive hover:underline", children: "Dismiss" })
|
|
4681
|
+
] }),
|
|
4682
|
+
/* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "list-disc pl-4 text-destructive/80 space-y-0.5", children: [
|
|
4683
|
+
saveValidationErrors.slice(0, 10).map((msg, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: msg }, i)),
|
|
4684
|
+
saveValidationErrors.length > 10 && /* @__PURE__ */ jsxRuntime.jsxs("li", { children: [
|
|
4685
|
+
"...and ",
|
|
4686
|
+
saveValidationErrors.length - 10,
|
|
4687
|
+
" more"
|
|
4688
|
+
] })
|
|
4689
|
+
] })
|
|
4690
|
+
] }),
|
|
4691
|
+
schemaUrlLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 border-b border-border bg-muted/50 text-xs text-muted-foreground flex items-center gap-2", children: [
|
|
4692
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-block w-3 h-3 border-2 border-primary border-t-transparent rounded-full animate-spin" }),
|
|
4693
|
+
"Loading schema from URL..."
|
|
4694
|
+
] }),
|
|
4695
|
+
schemaUrlError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shrink-0 px-4 py-2 bg-destructive/10 border-b border-destructive/20 text-destructive text-xs flex items-center justify-between", children: [
|
|
4696
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
4697
|
+
"Failed to load schema: ",
|
|
4698
|
+
schemaUrlError
|
|
4699
|
+
] }),
|
|
4700
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", onClick: () => setSchemaUrlError(null), className: "ml-2 hover:underline", children: "Dismiss" })
|
|
4701
|
+
] }),
|
|
4702
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex-1 flex overflow-hidden relative", children: viewMode === "json" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4703
|
+
JsonEditorPanel,
|
|
4704
|
+
{
|
|
4705
|
+
value: jsonText,
|
|
4706
|
+
onChange: setJsonText,
|
|
4707
|
+
errors: jsonErrors,
|
|
4708
|
+
onValidate: validateJson
|
|
4709
|
+
}
|
|
4710
|
+
) : viewMode === "preview" ? /* @__PURE__ */ jsxRuntime.jsx(FormPreviewPanel, { schema: builderState.schema, preview }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3489
4711
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(QuestionPalette, { questionTypes: mergedQuestionTypes, palette }) }),
|
|
3490
4712
|
/* @__PURE__ */ jsxRuntime.jsx(FormCanvas, { builderState }),
|
|
3491
4713
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "hidden md:flex", children: /* @__PURE__ */ jsxRuntime.jsx(PropertiesPanel, { builderState }) }),
|
|
@@ -3499,11 +4721,27 @@ ${details}`);
|
|
|
3499
4721
|
"aria-hidden": "true"
|
|
3500
4722
|
}
|
|
3501
4723
|
)
|
|
3502
|
-
] })
|
|
4724
|
+
] }) })
|
|
3503
4725
|
]
|
|
3504
4726
|
}
|
|
3505
4727
|
),
|
|
3506
|
-
/* @__PURE__ */ jsxRuntime.jsx(core.DragOverlay, { dropAnimation: null, children: dragDrop.activeDragItem && /* @__PURE__ */ jsxRuntime.jsx(DragOverlayContent, { item: dragDrop.activeDragItem, schema: builderState.schema, questionTypes: mergedQuestionTypes }) })
|
|
4728
|
+
/* @__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
|
+
showTemplateGallery && templates && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4738
|
+
TemplateGallery,
|
|
4739
|
+
{
|
|
4740
|
+
templates,
|
|
4741
|
+
onSelect: (template) => builderState.resetSchema(template.schema),
|
|
4742
|
+
onClose: () => setShowTemplateGallery(false)
|
|
4743
|
+
}
|
|
4744
|
+
)
|
|
3507
4745
|
]
|
|
3508
4746
|
}
|
|
3509
4747
|
) });
|
|
@@ -3558,76 +4796,54 @@ var FormBuilder = requireLicense(FormBuilderInner, "FormBuilder");
|
|
|
3558
4796
|
|
|
3559
4797
|
// src/form-builder/theme/presets.ts
|
|
3560
4798
|
var squaredrDarkPreset = {
|
|
3561
|
-
background: "#
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
|
|
3583
|
-
|
|
3584
|
-
// sr-error
|
|
3585
|
-
destructiveForeground: "#e8e8ea",
|
|
3586
|
-
// ink-100
|
|
3587
|
-
border: "#1c1c20",
|
|
3588
|
-
// ink-800
|
|
3589
|
-
input: "#1c1c20",
|
|
3590
|
-
// ink-800
|
|
3591
|
-
ring: "oklch(0.82 0.14 210)",
|
|
3592
|
-
// sr-accent-cyan
|
|
3593
|
-
radius: "6px",
|
|
3594
|
-
surface: "#111113",
|
|
3595
|
-
// ink-900
|
|
3596
|
-
surfaceHover: "#17171a",
|
|
3597
|
-
// ink-850
|
|
3598
|
-
canvas: "#0a0a0b",
|
|
3599
|
-
// ink-950
|
|
3600
|
-
panel: "#111113",
|
|
3601
|
-
// ink-900
|
|
3602
|
-
borderStrong: "#26262c",
|
|
3603
|
-
// ink-700
|
|
3604
|
-
textDim: "#5a5a66"
|
|
3605
|
-
// ink-500
|
|
4799
|
+
background: "#0F1A1F",
|
|
4800
|
+
foreground: "#E8EFF1",
|
|
4801
|
+
card: "#16242A",
|
|
4802
|
+
primary: "#63BDB4",
|
|
4803
|
+
primaryForeground: "#0F1A1F",
|
|
4804
|
+
secondary: "#182F31",
|
|
4805
|
+
secondaryForeground: "#E8EFF1",
|
|
4806
|
+
muted: "#182F31",
|
|
4807
|
+
mutedForeground: "#8CA1A9",
|
|
4808
|
+
accent: "#182F31",
|
|
4809
|
+
accentForeground: "#E8EFF1",
|
|
4810
|
+
destructive: "#E08072",
|
|
4811
|
+
destructiveForeground: "#0F1A1F",
|
|
4812
|
+
border: "#2A3B42",
|
|
4813
|
+
input: "#2A3B42",
|
|
4814
|
+
ring: "#63BDB4",
|
|
4815
|
+
radius: "0px",
|
|
4816
|
+
surface: "#16242A",
|
|
4817
|
+
surfaceHover: "#182F31",
|
|
4818
|
+
canvas: "#0F1A1F",
|
|
4819
|
+
panel: "#16242A",
|
|
4820
|
+
borderStrong: "#2F4F4C",
|
|
4821
|
+
textDim: "#5E7680"
|
|
3606
4822
|
};
|
|
3607
4823
|
var cleanPreset = {
|
|
3608
|
-
background: "#
|
|
3609
|
-
foreground: "#
|
|
3610
|
-
card: "#
|
|
3611
|
-
primary: "#
|
|
3612
|
-
primaryForeground: "#
|
|
3613
|
-
secondary: "#
|
|
3614
|
-
secondaryForeground: "#
|
|
3615
|
-
muted: "#
|
|
3616
|
-
mutedForeground: "#
|
|
3617
|
-
accent: "#
|
|
3618
|
-
accentForeground: "#
|
|
3619
|
-
destructive: "#
|
|
3620
|
-
destructiveForeground: "#
|
|
3621
|
-
border: "#
|
|
3622
|
-
input: "#
|
|
3623
|
-
ring: "#
|
|
3624
|
-
radius: "
|
|
3625
|
-
surface: "#
|
|
3626
|
-
surfaceHover: "#
|
|
3627
|
-
canvas: "#
|
|
3628
|
-
panel: "#
|
|
3629
|
-
borderStrong: "#
|
|
3630
|
-
textDim: "#
|
|
4824
|
+
background: "#F4F7F8",
|
|
4825
|
+
foreground: "#12222A",
|
|
4826
|
+
card: "#FFFFFF",
|
|
4827
|
+
primary: "#1F6B6E",
|
|
4828
|
+
primaryForeground: "#FFFFFF",
|
|
4829
|
+
secondary: "#EDF3F2",
|
|
4830
|
+
secondaryForeground: "#12222A",
|
|
4831
|
+
muted: "#EDF3F2",
|
|
4832
|
+
mutedForeground: "#6A7B85",
|
|
4833
|
+
accent: "#EDF3F2",
|
|
4834
|
+
accentForeground: "#12222A",
|
|
4835
|
+
destructive: "#B04A3C",
|
|
4836
|
+
destructiveForeground: "#FFFFFF",
|
|
4837
|
+
border: "#DCE4E8",
|
|
4838
|
+
input: "#DCE4E8",
|
|
4839
|
+
ring: "#1F6B6E",
|
|
4840
|
+
radius: "0px",
|
|
4841
|
+
surface: "#FAFCFC",
|
|
4842
|
+
surfaceHover: "#EDF3F2",
|
|
4843
|
+
canvas: "#F4F7F8",
|
|
4844
|
+
panel: "#FFFFFF",
|
|
4845
|
+
borderStrong: "#B9D1CF",
|
|
4846
|
+
textDim: "#6A7B85"
|
|
3631
4847
|
};
|
|
3632
4848
|
|
|
3633
4849
|
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|