@squaredr/fieldcraft-pro 1.8.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-IW654Z3M.mjs → chunk-5QXKDYWY.mjs} +92 -5
- package/dist/{chunk-MLP5EDWP.mjs → chunk-7GPX3YIB.mjs} +35 -61
- package/dist/{chunk-GXKQCXIB.mjs → chunk-DWRLPGX5.mjs} +395 -86
- package/dist/{chunk-CYXJGOQH.mjs → chunk-KTIU7VCP.mjs} +68 -9
- package/dist/default-schema-BGxf9Jrg.d.ts +174 -0
- package/dist/default-schema-Bwq8FATF.d.mts +174 -0
- package/dist/form-builder/index.d.mts +14 -170
- package/dist/form-builder/index.d.ts +14 -170
- package/dist/form-builder/index.js +396 -85
- package/dist/form-builder/index.mjs +1 -1
- package/dist/index.d.mts +109 -8
- package/dist/index.d.ts +109 -8
- package/dist/index.js +1697 -217
- package/dist/index.mjs +1106 -11
- package/dist/response-viewer/index.js +36 -61
- package/dist/response-viewer/index.mjs +1 -1
- package/dist/styles.css +2 -2
- package/dist/templates/index.d.mts +1 -1
- package/dist/templates/index.d.ts +1 -1
- package/dist/templates/index.js +92 -5
- package/dist/templates/index.mjs +1 -1
- package/dist/theme-editor/index.d.mts +1 -2
- package/dist/theme-editor/index.d.ts +1 -2
- package/dist/theme-editor/index.js +68 -9
- package/dist/theme-editor/index.mjs +1 -1
- package/dist/{types-bFHsZT1n.d.mts → types-BQOeI3LX.d.mts} +1 -1
- package/dist/{types-bFHsZT1n.d.ts → types-BQOeI3LX.d.ts} +1 -1
- package/package.json +21 -21
- package/theme-editor/styles.css +29 -0
|
@@ -336,21 +336,20 @@ var MAX_HISTORY = 50;
|
|
|
336
336
|
function useUndoRedo(currentSchema, setSchema) {
|
|
337
337
|
const historyRef = React.useRef([currentSchema]);
|
|
338
338
|
const [currentIndex, setCurrentIndex] = React.useState(0);
|
|
339
|
-
const currentIndexRef = React.useRef(currentIndex);
|
|
340
|
-
currentIndexRef.current = currentIndex;
|
|
341
339
|
const canUndo = currentIndex > 0;
|
|
342
340
|
const canRedo = currentIndex < historyRef.current.length - 1;
|
|
343
341
|
const push = React.useCallback(
|
|
344
342
|
(schema) => {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
historyRef.current.
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
343
|
+
setCurrentIndex((prevIndex) => {
|
|
344
|
+
historyRef.current = historyRef.current.slice(0, prevIndex + 1);
|
|
345
|
+
historyRef.current.push(schema);
|
|
346
|
+
let newIndex = prevIndex + 1;
|
|
347
|
+
if (historyRef.current.length > MAX_HISTORY) {
|
|
348
|
+
historyRef.current.shift();
|
|
349
|
+
newIndex = Math.max(0, newIndex - 1);
|
|
350
|
+
}
|
|
351
|
+
return newIndex;
|
|
352
|
+
});
|
|
354
353
|
},
|
|
355
354
|
[]
|
|
356
355
|
);
|
|
@@ -383,13 +382,9 @@ function useUndoRedo(currentSchema, setSchema) {
|
|
|
383
382
|
}
|
|
384
383
|
|
|
385
384
|
// src/form-builder/utils/id-generator.ts
|
|
386
|
-
var counter = 0;
|
|
387
385
|
function generateId(prefix) {
|
|
388
|
-
const
|
|
389
|
-
|
|
390
|
-
counter = (counter + 1) % 1e4;
|
|
391
|
-
const count = counter.toString(36);
|
|
392
|
-
return `${prefix}_${timestamp}${count}${random}`;
|
|
386
|
+
const uuid = crypto.randomUUID().replace(/-/g, "").substring(0, 12);
|
|
387
|
+
return `${prefix}_${uuid}`;
|
|
393
388
|
}
|
|
394
389
|
function generateSectionId() {
|
|
395
390
|
return generateId("section");
|
|
@@ -476,18 +471,39 @@ function duplicateSection(schema, sectionId) {
|
|
|
476
471
|
const sectionIndex = newSchema.sections.findIndex((s) => s.id === sectionId);
|
|
477
472
|
if (sectionIndex === -1) return schema;
|
|
478
473
|
const original = newSchema.sections[sectionIndex];
|
|
474
|
+
const idMap = /* @__PURE__ */ new Map();
|
|
475
|
+
for (const q of original.questions) {
|
|
476
|
+
idMap.set(q.id, generateQuestionId());
|
|
477
|
+
}
|
|
479
478
|
const duplicate = {
|
|
480
479
|
...original,
|
|
481
480
|
id: generateSectionId(),
|
|
482
481
|
title: `${original.title} (Copy)`,
|
|
482
|
+
showIf: original.showIf ? remapConditionFieldIds(original.showIf, idMap) : void 0,
|
|
483
483
|
questions: original.questions.map((q) => ({
|
|
484
484
|
...q,
|
|
485
|
-
id:
|
|
485
|
+
id: idMap.get(q.id),
|
|
486
|
+
showIf: q.showIf ? remapConditionFieldIds(q.showIf, idMap) : void 0
|
|
486
487
|
}))
|
|
487
488
|
};
|
|
488
489
|
newSchema.sections.splice(sectionIndex + 1, 0, duplicate);
|
|
489
490
|
return newSchema;
|
|
490
491
|
}
|
|
492
|
+
function remapConditionFieldIds(expr, idMap) {
|
|
493
|
+
if (expr.field) {
|
|
494
|
+
return {
|
|
495
|
+
...expr,
|
|
496
|
+
field: idMap.get(expr.field) ?? expr.field
|
|
497
|
+
};
|
|
498
|
+
}
|
|
499
|
+
if (expr.conditions) {
|
|
500
|
+
return {
|
|
501
|
+
...expr,
|
|
502
|
+
conditions: expr.conditions.map((c) => remapConditionFieldIds(c, idMap))
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
return expr;
|
|
506
|
+
}
|
|
491
507
|
function addQuestion(schema, sectionId, question, index) {
|
|
492
508
|
const newSchema = deepClone(schema);
|
|
493
509
|
const section = newSchema.sections.find((s) => s.id === sectionId);
|
|
@@ -631,7 +647,7 @@ function useBuilderState(initialSchema) {
|
|
|
631
647
|
(sectionId) => {
|
|
632
648
|
applyMutation((s) => removeSection(s, sectionId));
|
|
633
649
|
setSelectedItem((prev) => {
|
|
634
|
-
if (prev?.
|
|
650
|
+
if (prev?.sectionId === sectionId) return null;
|
|
635
651
|
return prev;
|
|
636
652
|
});
|
|
637
653
|
},
|
|
@@ -1764,6 +1780,14 @@ function SectionBlock({ section, builderState }) {
|
|
|
1764
1780
|
}
|
|
1765
1781
|
function FormCanvas({ builderState }) {
|
|
1766
1782
|
const { schema } = builderState;
|
|
1783
|
+
const [localTitle, setLocalTitle] = React.useState(schema.title);
|
|
1784
|
+
const [localDesc, setLocalDesc] = React.useState(schema.description ?? "");
|
|
1785
|
+
React.useEffect(() => {
|
|
1786
|
+
setLocalTitle(schema.title);
|
|
1787
|
+
}, [schema.title]);
|
|
1788
|
+
React.useEffect(() => {
|
|
1789
|
+
setLocalDesc(schema.description ?? "");
|
|
1790
|
+
}, [schema.description]);
|
|
1767
1791
|
const handleAddSection = () => {
|
|
1768
1792
|
const newSection = {
|
|
1769
1793
|
id: generateSectionId(),
|
|
@@ -1780,9 +1804,12 @@ function FormCanvas({ builderState }) {
|
|
|
1780
1804
|
"input",
|
|
1781
1805
|
{
|
|
1782
1806
|
type: "text",
|
|
1783
|
-
value:
|
|
1784
|
-
onChange: (e) =>
|
|
1785
|
-
|
|
1807
|
+
value: localTitle,
|
|
1808
|
+
onChange: (e) => setLocalTitle(e.target.value),
|
|
1809
|
+
onBlur: () => {
|
|
1810
|
+
if (localTitle !== schema.title) {
|
|
1811
|
+
builderState.updateSchema({ ...schema, title: localTitle });
|
|
1812
|
+
}
|
|
1786
1813
|
},
|
|
1787
1814
|
className: "w-full text-xl font-bold bg-transparent text-foreground border-0 outline-none p-1.5 rounded-md focus:bg-card transition-colors",
|
|
1788
1815
|
placeholder: "Form Title"
|
|
@@ -1791,9 +1818,12 @@ function FormCanvas({ builderState }) {
|
|
|
1791
1818
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1792
1819
|
"textarea",
|
|
1793
1820
|
{
|
|
1794
|
-
value:
|
|
1795
|
-
onChange: (e) =>
|
|
1796
|
-
|
|
1821
|
+
value: localDesc,
|
|
1822
|
+
onChange: (e) => setLocalDesc(e.target.value),
|
|
1823
|
+
onBlur: () => {
|
|
1824
|
+
if (localDesc !== (schema.description ?? "")) {
|
|
1825
|
+
builderState.updateSchema({ ...schema, description: localDesc || void 0 });
|
|
1826
|
+
}
|
|
1797
1827
|
},
|
|
1798
1828
|
className: "w-full text-sm text-muted-foreground bg-transparent border-0 outline-none p-1.5 resize-y min-h-12 rounded-md leading-relaxed focus:bg-card transition-colors",
|
|
1799
1829
|
placeholder: "Form description (optional)"
|
|
@@ -1896,12 +1926,26 @@ SelectItem.displayName = "SelectItem";
|
|
|
1896
1926
|
function useConfigUpdater(question, onUpdate) {
|
|
1897
1927
|
return (updates) => {
|
|
1898
1928
|
const current = question.config ?? {};
|
|
1899
|
-
|
|
1929
|
+
const merged = { ...current, type: question.type, ...updates };
|
|
1930
|
+
for (const key of Object.keys(merged)) {
|
|
1931
|
+
if (merged[key] === void 0) delete merged[key];
|
|
1932
|
+
}
|
|
1933
|
+
onUpdate({ config: merged });
|
|
1900
1934
|
};
|
|
1901
1935
|
}
|
|
1902
|
-
function QuestionConfigEditor({ question, onUpdate }) {
|
|
1936
|
+
function QuestionConfigEditor({ question, schema, onUpdate }) {
|
|
1903
1937
|
const updateConfig = useConfigUpdater(question, onUpdate);
|
|
1904
1938
|
const config = question.config ?? {};
|
|
1939
|
+
const allQuestions = React.useMemo(() => {
|
|
1940
|
+
if (!schema?.sections) return [];
|
|
1941
|
+
return schema.sections.flatMap((s) => s.questions || []);
|
|
1942
|
+
}, [schema]);
|
|
1943
|
+
const candidateAmountFields = React.useMemo(() => {
|
|
1944
|
+
return allQuestions.filter((q) => q.id !== question.id && ["calculated", "number", "slider", "rating", "single_select"].includes(q.type)).map((q) => ({ label: `${q.label || q.id} (${q.id})`, value: q.id }));
|
|
1945
|
+
}, [allQuestions, question.id]);
|
|
1946
|
+
const candidateTimezoneFields = React.useMemo(() => {
|
|
1947
|
+
return allQuestions.filter((q) => q.id !== question.id && ["dropdown", "single_select", "short_text"].includes(q.type)).map((q) => ({ label: `${q.label || q.id} (${q.id})`, value: q.id }));
|
|
1948
|
+
}, [allQuestions, question.id]);
|
|
1905
1949
|
switch (question.type) {
|
|
1906
1950
|
// ── Text ──
|
|
1907
1951
|
case "short_text":
|
|
@@ -1925,32 +1969,32 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
1925
1969
|
// ── Numeric ──
|
|
1926
1970
|
case "number":
|
|
1927
1971
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Number Settings", children: [
|
|
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 }) }),
|
|
1972
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Value", value: config.min, onChange: (v) => updateConfig({ min: v }) }),
|
|
1973
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Value", value: config.max, onChange: (v) => updateConfig({ max: v }) }),
|
|
1930
1974
|
/* @__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
1975
|
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Prefix", value: config.prefix, placeholder: "e.g. $", onChange: (v) => updateConfig({ prefix: v }) }),
|
|
1933
1976
|
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Suffix", value: config.suffix, placeholder: "e.g. kg", onChange: (v) => updateConfig({ suffix: v }) })
|
|
1934
1977
|
] });
|
|
1935
1978
|
case "slider":
|
|
1936
1979
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Slider Settings", children: [
|
|
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(
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1942
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1980
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Min Value", value: config.min, placeholder: "0", onChange: (v) => updateConfig({ min: v ?? 0 }) }),
|
|
1981
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Value", value: config.max, placeholder: "100", onChange: (v) => updateConfig({ max: v ?? 100 }) }),
|
|
1982
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Step", value: config.step, placeholder: "1", onChange: (v) => updateConfig({ step: v ?? 1 }) }),
|
|
1983
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Min Label", value: config.minLabel, placeholder: "Low", onChange: (v) => updateConfig({ minLabel: v }) }),
|
|
1984
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Max Label", value: config.maxLabel, placeholder: "High", onChange: (v) => updateConfig({ maxLabel: v }) }),
|
|
1985
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Show Value", checked: config.showValue !== false, onChange: (v) => updateConfig({ showValue: v }) }),
|
|
1986
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Unit", value: config.unit, placeholder: "e.g. %", onChange: (v) => updateConfig({ unit: v }) })
|
|
1943
1987
|
] });
|
|
1944
1988
|
case "rating":
|
|
1945
1989
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Rating Settings", children: [
|
|
1946
|
-
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max
|
|
1947
|
-
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "
|
|
1948
|
-
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "
|
|
1990
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Rating", value: config.maxRating, placeholder: "5", onChange: (v) => updateConfig({ maxRating: v ?? 5 }) }),
|
|
1991
|
+
/* @__PURE__ */ jsxRuntime.jsx(SelectField, { label: "Icon", value: config.icon ?? "star", options: [{ label: "Star", value: "star" }, { label: "Heart", value: "heart" }, { label: "Thumb", value: "thumb" }], onChange: (v) => updateConfig({ icon: v }) }),
|
|
1992
|
+
/* @__PURE__ */ jsxRuntime.jsx(ToggleField, { label: "Allow Half Ratings", checked: !!config.allowHalf, onChange: (v) => updateConfig({ allowHalf: v }) })
|
|
1949
1993
|
] });
|
|
1950
1994
|
case "nps":
|
|
1951
1995
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "NPS Settings", children: [
|
|
1952
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1953
|
-
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "
|
|
1996
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Left Label", value: config.leftLabel ?? "Not likely", onChange: (v) => updateConfig({ leftLabel: v }) }),
|
|
1997
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Right Label", value: config.rightLabel ?? "Extremely likely", onChange: (v) => updateConfig({ rightLabel: v }) })
|
|
1954
1998
|
] });
|
|
1955
1999
|
case "opinion_scale":
|
|
1956
2000
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Scale Settings", children: [
|
|
@@ -2016,50 +2060,126 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2016
2060
|
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Range (days)", value: config.maxRangeDays, onChange: (v) => updateConfig({ maxRangeDays: v }) })
|
|
2017
2061
|
] });
|
|
2018
2062
|
case "appointment": {
|
|
2019
|
-
const appointmentMode = typeof config.
|
|
2063
|
+
const appointmentMode = typeof config.slotsUrl === "string" ? "url" : typeof config.embedUrl === "string" ? "embed" : "static";
|
|
2064
|
+
const timezoneFieldOptions = [
|
|
2065
|
+
{ label: "None (Static Timezone)", value: "" },
|
|
2066
|
+
...candidateTimezoneFields,
|
|
2067
|
+
{ label: "Custom Field ID...", value: "__custom__" }
|
|
2068
|
+
];
|
|
2069
|
+
const isCustomTzField = Boolean(config.timezoneField) && !candidateTimezoneFields.some((opt) => opt.value === config.timezoneField);
|
|
2020
2070
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Appointment Settings", children: [
|
|
2021
2071
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2022
2072
|
SelectField,
|
|
2023
2073
|
{
|
|
2024
|
-
label: "Mode",
|
|
2074
|
+
label: "Scheduling Mode",
|
|
2025
2075
|
value: appointmentMode,
|
|
2026
2076
|
options: [
|
|
2027
|
-
{ label: "Static Slots", value: "static" },
|
|
2028
|
-
{ label: "
|
|
2029
|
-
{ label: "Embed (Calendly / Cal.com)", value: "embed" }
|
|
2077
|
+
{ label: "Manual Static Slots", value: "static" },
|
|
2078
|
+
{ label: "Fetch from URL", value: "url" },
|
|
2079
|
+
{ label: "Third-Party Embed (Calendly / Cal.com)", value: "embed" }
|
|
2030
2080
|
],
|
|
2031
2081
|
onChange: (v) => {
|
|
2032
|
-
if (v === "
|
|
2033
|
-
updateConfig({
|
|
2034
|
-
|
|
2035
|
-
|
|
2082
|
+
if (v === "url") {
|
|
2083
|
+
updateConfig({
|
|
2084
|
+
slotsUrl: "",
|
|
2085
|
+
embedUrl: void 0,
|
|
2086
|
+
embedProvider: void 0,
|
|
2087
|
+
slots: void 0
|
|
2088
|
+
});
|
|
2036
2089
|
} else if (v === "embed") {
|
|
2037
|
-
updateConfig({
|
|
2090
|
+
updateConfig({
|
|
2091
|
+
embedUrl: "",
|
|
2092
|
+
embedProvider: config.embedProvider || "cal_com",
|
|
2093
|
+
slotsUrl: void 0,
|
|
2094
|
+
slots: void 0
|
|
2095
|
+
});
|
|
2096
|
+
} else {
|
|
2097
|
+
updateConfig({
|
|
2098
|
+
slots: config.slots ?? [],
|
|
2099
|
+
slotsUrl: void 0,
|
|
2100
|
+
embedUrl: void 0,
|
|
2101
|
+
embedProvider: void 0
|
|
2102
|
+
});
|
|
2038
2103
|
}
|
|
2039
2104
|
}
|
|
2040
2105
|
}
|
|
2041
2106
|
),
|
|
2042
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2107
|
+
appointmentMode === "url" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2108
|
+
TextField,
|
|
2109
|
+
{
|
|
2110
|
+
label: "Slots URL",
|
|
2111
|
+
value: config.slotsUrl,
|
|
2112
|
+
placeholder: "https://example.com/slots",
|
|
2113
|
+
onChange: (v) => updateConfig({ slotsUrl: v ?? "" })
|
|
2114
|
+
}
|
|
2115
|
+
),
|
|
2047
2116
|
appointmentMode === "embed" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2048
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2118
|
+
TextField,
|
|
2119
|
+
{
|
|
2120
|
+
label: "Embed URL",
|
|
2121
|
+
value: config.embedUrl,
|
|
2122
|
+
placeholder: "https://calendly.com/... or https://cal.com/...",
|
|
2123
|
+
onChange: (v) => updateConfig({ embedUrl: v ?? "" })
|
|
2124
|
+
}
|
|
2125
|
+
),
|
|
2049
2126
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2050
2127
|
SelectField,
|
|
2051
2128
|
{
|
|
2052
2129
|
label: "Embed Provider",
|
|
2053
|
-
value: config.embedProvider ?? "
|
|
2130
|
+
value: config.embedProvider ?? "cal_com",
|
|
2054
2131
|
options: [
|
|
2055
|
-
{ label: "Calendly", value: "calendly" },
|
|
2056
2132
|
{ label: "Cal.com", value: "cal_com" },
|
|
2133
|
+
{ label: "Calendly", value: "calendly" },
|
|
2057
2134
|
{ label: "Custom", value: "custom" }
|
|
2058
2135
|
],
|
|
2059
2136
|
onChange: (v) => updateConfig({ embedProvider: v })
|
|
2060
2137
|
}
|
|
2061
2138
|
)
|
|
2062
2139
|
] }),
|
|
2140
|
+
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Duration (min)", value: config.duration ?? 30, onChange: (v) => updateConfig({ duration: v }) }),
|
|
2141
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Timezone", value: config.timezone, placeholder: "e.g. America/New_York", onChange: (v) => updateConfig({ timezone: v }) }),
|
|
2142
|
+
candidateTimezoneFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2143
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2144
|
+
SelectField,
|
|
2145
|
+
{
|
|
2146
|
+
label: "Dynamic Timezone Field",
|
|
2147
|
+
value: isCustomTzField ? "__custom__" : config.timezoneField ?? "",
|
|
2148
|
+
options: timezoneFieldOptions,
|
|
2149
|
+
onChange: (v) => {
|
|
2150
|
+
if (v !== "__custom__") {
|
|
2151
|
+
updateConfig({ timezoneField: v || void 0 });
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
),
|
|
2156
|
+
isCustomTzField && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2157
|
+
TextField,
|
|
2158
|
+
{
|
|
2159
|
+
label: "Custom Timezone Field ID",
|
|
2160
|
+
value: config.timezoneField,
|
|
2161
|
+
placeholder: "e.g. timezone",
|
|
2162
|
+
onChange: (v) => updateConfig({ timezoneField: v || void 0 })
|
|
2163
|
+
}
|
|
2164
|
+
) })
|
|
2165
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2166
|
+
TextField,
|
|
2167
|
+
{
|
|
2168
|
+
label: "Timezone Field",
|
|
2169
|
+
value: config.timezoneField,
|
|
2170
|
+
placeholder: "Field ID for dynamic timezone",
|
|
2171
|
+
onChange: (v) => updateConfig({ timezoneField: v || void 0 })
|
|
2172
|
+
}
|
|
2173
|
+
),
|
|
2174
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Date Format", value: config.dateFormat, placeholder: "Locale-aware (default)", onChange: (v) => updateConfig({ dateFormat: v }) }),
|
|
2175
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2176
|
+
ToggleField,
|
|
2177
|
+
{
|
|
2178
|
+
label: "Auto-Advance on Booking Complete",
|
|
2179
|
+
checked: config.autoAdvance !== false,
|
|
2180
|
+
onChange: (v) => updateConfig({ autoAdvance: v })
|
|
2181
|
+
}
|
|
2182
|
+
),
|
|
2063
2183
|
appointmentMode === "static" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2064
2184
|
AppointmentSlotsEditor,
|
|
2065
2185
|
{
|
|
@@ -2072,10 +2192,41 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2072
2192
|
// ── Media ──
|
|
2073
2193
|
case "file_upload":
|
|
2074
2194
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Upload Settings", children: [
|
|
2195
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2.5 bg-muted/40 border border-border rounded-md text-xs text-muted-foreground flex items-center gap-1.5", children: [
|
|
2196
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "\u{1F4E6}" }),
|
|
2197
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Uploads stream to your cloud bucket using Form / Account Storage settings." })
|
|
2198
|
+
] }),
|
|
2075
2199
|
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Files", value: config.maxFiles ?? 1, onChange: (v) => updateConfig({ maxFiles: v }) }),
|
|
2076
2200
|
/* @__PURE__ */ jsxRuntime.jsx(NumberField, { label: "Max Size (MB)", value: config.maxSizeMb ?? 10, onChange: (v) => updateConfig({ maxSizeMb: v }) }),
|
|
2077
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2078
|
-
|
|
2201
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2202
|
+
TextField,
|
|
2203
|
+
{
|
|
2204
|
+
label: "Accepted Types (comma-separated)",
|
|
2205
|
+
value: config.accept?.join(", "),
|
|
2206
|
+
placeholder: "e.g. image/*, .pdf, .docx, .zip",
|
|
2207
|
+
onChange: (v) => updateConfig({
|
|
2208
|
+
accept: v ? v.split(",").map((s) => s.trim()).filter(Boolean) : void 0
|
|
2209
|
+
})
|
|
2210
|
+
}
|
|
2211
|
+
),
|
|
2212
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2213
|
+
TextField,
|
|
2214
|
+
{
|
|
2215
|
+
label: "Upload URL",
|
|
2216
|
+
value: config.uploadUrl,
|
|
2217
|
+
placeholder: "https://api.example.com/s3/presign",
|
|
2218
|
+
onChange: (v) => updateConfig({ uploadUrl: v || void 0 })
|
|
2219
|
+
}
|
|
2220
|
+
),
|
|
2221
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2222
|
+
TextField,
|
|
2223
|
+
{
|
|
2224
|
+
label: "Public Key",
|
|
2225
|
+
value: config.publicKey,
|
|
2226
|
+
placeholder: "pk_test_...",
|
|
2227
|
+
onChange: (v) => updateConfig({ publicKey: v || void 0 })
|
|
2228
|
+
}
|
|
2229
|
+
)
|
|
2079
2230
|
] });
|
|
2080
2231
|
case "signature":
|
|
2081
2232
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Signature Settings", children: [
|
|
@@ -2192,32 +2343,120 @@ function QuestionConfigEditor({ question, onUpdate }) {
|
|
|
2192
2343
|
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Default Country", value: config.defaultCountry, placeholder: "e.g. US", onChange: (v) => updateConfig({ defaultCountry: v }) }),
|
|
2193
2344
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2194
2345
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-2 block", children: "Fields" }),
|
|
2195
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) =>
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2346
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: ADDRESS_FIELDS.map((f) => {
|
|
2347
|
+
const isChecked = activeFields.includes(f.value);
|
|
2348
|
+
const isLastChecked = isChecked && activeFields.length === 1;
|
|
2349
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2350
|
+
ToggleField,
|
|
2351
|
+
{
|
|
2352
|
+
label: f.label,
|
|
2353
|
+
checked: isChecked,
|
|
2354
|
+
disabled: isLastChecked,
|
|
2355
|
+
onChange: (checked) => {
|
|
2356
|
+
const next = checked ? [...activeFields, f.value] : activeFields.filter((v) => v !== f.value);
|
|
2357
|
+
updateConfig({ fields: next });
|
|
2358
|
+
}
|
|
2359
|
+
},
|
|
2360
|
+
f.value
|
|
2361
|
+
);
|
|
2362
|
+
}) })
|
|
2207
2363
|
] })
|
|
2208
2364
|
] });
|
|
2209
2365
|
}
|
|
2210
|
-
case "payment":
|
|
2366
|
+
case "payment": {
|
|
2367
|
+
const amountFieldOptions = [
|
|
2368
|
+
{ label: "None (Fixed Amount)", value: "" },
|
|
2369
|
+
...candidateAmountFields,
|
|
2370
|
+
{ label: "Custom Field ID...", value: "__custom__" }
|
|
2371
|
+
];
|
|
2372
|
+
const isCustomAmountField = Boolean(config.amountField) && !candidateAmountFields.some((opt) => opt.value === config.amountField);
|
|
2211
2373
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Payment Settings", children: [
|
|
2212
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2374
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2375
|
+
SelectField,
|
|
2376
|
+
{
|
|
2377
|
+
label: "Provider",
|
|
2378
|
+
value: config.provider ?? "stripe",
|
|
2379
|
+
options: [
|
|
2380
|
+
{ label: "Stripe", value: "stripe" },
|
|
2381
|
+
{ label: "PayPal", value: "paypal" },
|
|
2382
|
+
{ label: "Razorpay", value: "razorpay" }
|
|
2383
|
+
],
|
|
2384
|
+
onChange: (v) => updateConfig({ provider: v })
|
|
2385
|
+
}
|
|
2386
|
+
),
|
|
2387
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2388
|
+
TextField,
|
|
2389
|
+
{
|
|
2390
|
+
label: "Public Key",
|
|
2391
|
+
value: config.publicKey,
|
|
2392
|
+
placeholder: "pk_test_...",
|
|
2393
|
+
onChange: (v) => updateConfig({ publicKey: v || void 0 })
|
|
2394
|
+
}
|
|
2395
|
+
),
|
|
2396
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2397
|
+
TextField,
|
|
2398
|
+
{
|
|
2399
|
+
label: "Server URL",
|
|
2400
|
+
value: config.serverUrl,
|
|
2401
|
+
placeholder: "https://api.example.com/create-intent",
|
|
2402
|
+
onChange: (v) => updateConfig({ serverUrl: v || void 0 })
|
|
2403
|
+
}
|
|
2404
|
+
),
|
|
2405
|
+
candidateAmountFields.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2406
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2407
|
+
SelectField,
|
|
2408
|
+
{
|
|
2409
|
+
label: "Dynamic Amount Field",
|
|
2410
|
+
value: isCustomAmountField ? "__custom__" : config.amountField ?? "",
|
|
2411
|
+
options: amountFieldOptions,
|
|
2412
|
+
onChange: (v) => {
|
|
2413
|
+
if (v !== "__custom__") {
|
|
2414
|
+
updateConfig({ amountField: v || void 0 });
|
|
2415
|
+
}
|
|
2416
|
+
}
|
|
2417
|
+
}
|
|
2418
|
+
),
|
|
2419
|
+
isCustomAmountField && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2420
|
+
TextField,
|
|
2421
|
+
{
|
|
2422
|
+
label: "Custom Field ID",
|
|
2423
|
+
value: config.amountField,
|
|
2424
|
+
placeholder: "Field ID for dynamic amount",
|
|
2425
|
+
onChange: (v) => updateConfig({ amountField: v || void 0 })
|
|
2426
|
+
}
|
|
2427
|
+
) })
|
|
2428
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2429
|
+
TextField,
|
|
2430
|
+
{
|
|
2431
|
+
label: "Amount Field",
|
|
2432
|
+
value: config.amountField,
|
|
2433
|
+
placeholder: "Field ID for dynamic amount (e.g. total_cost)",
|
|
2434
|
+
onChange: (v) => updateConfig({ amountField: v || void 0 })
|
|
2435
|
+
}
|
|
2436
|
+
),
|
|
2437
|
+
!config.amountField && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2438
|
+
NumberField,
|
|
2439
|
+
{
|
|
2440
|
+
label: "Fixed Amount",
|
|
2441
|
+
value: config.amount,
|
|
2442
|
+
onChange: (v) => updateConfig({ amount: v })
|
|
2443
|
+
}
|
|
2444
|
+
),
|
|
2445
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Currency", value: config.currency ?? "USD", placeholder: "USD", onChange: (v) => updateConfig({ currency: v || "USD" }) }),
|
|
2446
|
+
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Description", value: config.description, onChange: (v) => updateConfig({ description: v }) }),
|
|
2447
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2448
|
+
TextField,
|
|
2449
|
+
{
|
|
2450
|
+
label: "Client Secret Response Path",
|
|
2451
|
+
value: typeof config.responseMapping?.clientSecretPath === "string" ? config.responseMapping.clientSecretPath : config.responseMapping ?? "",
|
|
2452
|
+
placeholder: "clientSecret",
|
|
2453
|
+
onChange: (v) => updateConfig({
|
|
2454
|
+
responseMapping: v ? { clientSecretPath: v } : void 0
|
|
2455
|
+
})
|
|
2456
|
+
}
|
|
2457
|
+
)
|
|
2220
2458
|
] });
|
|
2459
|
+
}
|
|
2221
2460
|
case "calculated":
|
|
2222
2461
|
return /* @__PURE__ */ jsxRuntime.jsxs(ConfigSection, { title: "Calculated Field", children: [
|
|
2223
2462
|
/* @__PURE__ */ jsxRuntime.jsx(TextField, { label: "Expression", value: config.expression ?? "", placeholder: "e.g. {q1} + {q2}", onChange: (v) => updateConfig({ expression: v }) }),
|
|
@@ -2326,11 +2565,12 @@ function NumberField({
|
|
|
2326
2565
|
function ToggleField({
|
|
2327
2566
|
label,
|
|
2328
2567
|
checked,
|
|
2329
|
-
onChange
|
|
2568
|
+
onChange,
|
|
2569
|
+
disabled
|
|
2330
2570
|
}) {
|
|
2331
2571
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2332
2572
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: label }),
|
|
2333
|
-
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Switch, { checked, onCheckedChange: onChange })
|
|
2573
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Switch, { checked, onCheckedChange: onChange, disabled })
|
|
2334
2574
|
] });
|
|
2335
2575
|
}
|
|
2336
2576
|
function SelectField({
|
|
@@ -3302,7 +3542,14 @@ function QuestionProperties({ question, sectionId, builderState, onClose, onOpen
|
|
|
3302
3542
|
}
|
|
3303
3543
|
)
|
|
3304
3544
|
] }),
|
|
3305
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3546
|
+
QuestionConfigEditor,
|
|
3547
|
+
{
|
|
3548
|
+
question,
|
|
3549
|
+
schema: builderState.schema,
|
|
3550
|
+
onUpdate: updateQuestion2
|
|
3551
|
+
}
|
|
3552
|
+
),
|
|
3306
3553
|
hasOptions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3307
3554
|
OptionsEditor,
|
|
3308
3555
|
{
|
|
@@ -3479,6 +3726,11 @@ function MonacoWrapper({ value, onChange, errors }) {
|
|
|
3479
3726
|
editorRef.current = editor;
|
|
3480
3727
|
monacoRef.current = monaco;
|
|
3481
3728
|
};
|
|
3729
|
+
React.useEffect(() => {
|
|
3730
|
+
return () => {
|
|
3731
|
+
editorRef.current?.dispose();
|
|
3732
|
+
};
|
|
3733
|
+
}, []);
|
|
3482
3734
|
React.useEffect(() => {
|
|
3483
3735
|
const editor = editorRef.current;
|
|
3484
3736
|
const monaco = monacoRef.current;
|
|
@@ -4283,6 +4535,11 @@ function TemplateGallery({ templates, onSelect, onClose }) {
|
|
|
4283
4535
|
function useDebouncedValidation(delayMs = 500) {
|
|
4284
4536
|
const [errors, setErrors] = React.useState([]);
|
|
4285
4537
|
const timerRef = React.useRef(null);
|
|
4538
|
+
React.useEffect(() => {
|
|
4539
|
+
return () => {
|
|
4540
|
+
if (timerRef.current) clearTimeout(timerRef.current);
|
|
4541
|
+
};
|
|
4542
|
+
}, []);
|
|
4286
4543
|
const validate = React.useCallback(
|
|
4287
4544
|
(text) => {
|
|
4288
4545
|
if (timerRef.current) {
|
|
@@ -5033,6 +5290,58 @@ function FormBuilderInner(props) {
|
|
|
5033
5290
|
// src/form-builder/components/FormBuilderGated.tsx
|
|
5034
5291
|
var FormBuilder = requireLicense(FormBuilderInner, "FormBuilder");
|
|
5035
5292
|
|
|
5293
|
+
// src/form-builder/theme/presets.ts
|
|
5294
|
+
var squaredrDarkPreset = {
|
|
5295
|
+
background: "#0F1A1F",
|
|
5296
|
+
foreground: "#E8EFF1",
|
|
5297
|
+
card: "#16242A",
|
|
5298
|
+
primary: "#63BDB4",
|
|
5299
|
+
primaryForeground: "#0F1A1F",
|
|
5300
|
+
secondary: "#182F31",
|
|
5301
|
+
secondaryForeground: "#E8EFF1",
|
|
5302
|
+
muted: "#182F31",
|
|
5303
|
+
mutedForeground: "#8CA1A9",
|
|
5304
|
+
accent: "#182F31",
|
|
5305
|
+
accentForeground: "#E8EFF1",
|
|
5306
|
+
destructive: "#E08072",
|
|
5307
|
+
destructiveForeground: "#0F1A1F",
|
|
5308
|
+
border: "#2A3B42",
|
|
5309
|
+
input: "#2A3B42",
|
|
5310
|
+
ring: "#63BDB4",
|
|
5311
|
+
radius: "0px",
|
|
5312
|
+
surface: "#16242A",
|
|
5313
|
+
surfaceHover: "#182F31",
|
|
5314
|
+
canvas: "#0F1A1F",
|
|
5315
|
+
panel: "#16242A",
|
|
5316
|
+
borderStrong: "#2F4F4C",
|
|
5317
|
+
textDim: "#5E7680"
|
|
5318
|
+
};
|
|
5319
|
+
var cleanPreset = {
|
|
5320
|
+
background: "#F4F7F8",
|
|
5321
|
+
foreground: "#12222A",
|
|
5322
|
+
card: "#FFFFFF",
|
|
5323
|
+
primary: "#1F6B6E",
|
|
5324
|
+
primaryForeground: "#FFFFFF",
|
|
5325
|
+
secondary: "#EDF3F2",
|
|
5326
|
+
secondaryForeground: "#12222A",
|
|
5327
|
+
muted: "#EDF3F2",
|
|
5328
|
+
mutedForeground: "#6A7B85",
|
|
5329
|
+
accent: "#EDF3F2",
|
|
5330
|
+
accentForeground: "#12222A",
|
|
5331
|
+
destructive: "#B04A3C",
|
|
5332
|
+
destructiveForeground: "#FFFFFF",
|
|
5333
|
+
border: "#DCE4E8",
|
|
5334
|
+
input: "#DCE4E8",
|
|
5335
|
+
ring: "#1F6B6E",
|
|
5336
|
+
radius: "0px",
|
|
5337
|
+
surface: "#FAFCFC",
|
|
5338
|
+
surfaceHover: "#EDF3F2",
|
|
5339
|
+
canvas: "#F4F7F8",
|
|
5340
|
+
panel: "#FFFFFF",
|
|
5341
|
+
borderStrong: "#B9D1CF",
|
|
5342
|
+
textDim: "#6A7B85"
|
|
5343
|
+
};
|
|
5344
|
+
|
|
5036
5345
|
exports.DEFAULT_PALETTE = DEFAULT_PALETTE;
|
|
5037
5346
|
exports.DEFAULT_SCHEMA = DEFAULT_SCHEMA;
|
|
5038
5347
|
exports.FormBuilder = FormBuilder;
|
|
@@ -5041,6 +5350,7 @@ exports.QUESTION_TYPE_INFO = QUESTION_TYPE_INFO;
|
|
|
5041
5350
|
exports.addOption = addOption;
|
|
5042
5351
|
exports.addQuestion = addQuestion;
|
|
5043
5352
|
exports.addSection = addSection;
|
|
5353
|
+
exports.cleanPreset = cleanPreset;
|
|
5044
5354
|
exports.cn = cn;
|
|
5045
5355
|
exports.duplicateQuestion = duplicateQuestion;
|
|
5046
5356
|
exports.duplicateSection = duplicateSection;
|
|
@@ -5056,6 +5366,7 @@ exports.moveSection = moveSection;
|
|
|
5056
5366
|
exports.removeOption = removeOption;
|
|
5057
5367
|
exports.removeQuestion = removeQuestion;
|
|
5058
5368
|
exports.removeSection = removeSection;
|
|
5369
|
+
exports.squaredrDarkPreset = squaredrDarkPreset;
|
|
5059
5370
|
exports.updateOption = updateOption;
|
|
5060
5371
|
exports.updateQuestion = updateQuestion;
|
|
5061
5372
|
exports.updateSection = updateSection;
|