@squaredr/fieldcraft-pro 0.0.4 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +48 -10
- package/README.md +37 -6
- package/dist/{chunk-APHGEYG4.mjs → chunk-DDQDYTMB.mjs} +155 -129
- package/dist/chunk-LOFGBNJV.mjs +976 -0
- package/dist/chunk-QQ4JZGTD.mjs +9 -0
- package/dist/form-builder/index.d.mts +2 -2
- package/dist/form-builder/index.d.ts +2 -2
- package/dist/form-builder/index.js +150 -119
- package/dist/form-builder/index.mjs +2 -1
- package/dist/index.js +983 -443
- package/dist/index.mjs +4 -3
- package/dist/response-viewer/index.d.mts +4 -1
- package/dist/response-viewer/index.d.ts +4 -1
- package/dist/response-viewer/index.js +839 -324
- package/dist/response-viewer/index.mjs +2 -1
- package/dist/styles.css +1 -1
- package/package.json +14 -13
- package/dist/chunk-NIKQEWPG.mjs +0 -467
- /package/{dist/theme-editor-styles.css → theme-editor/styles.css} +0 -0
|
@@ -212,12 +212,12 @@ declare const cleanPreset: FormBuilderTheme;
|
|
|
212
212
|
* Metadata for all question types available in the Pro palette.
|
|
213
213
|
* Icons are lucide-react component names (imported dynamically via ICON_MAP).
|
|
214
214
|
*
|
|
215
|
-
*
|
|
215
|
+
* 32 field types — general-purpose form building.
|
|
216
216
|
* Telehealth-specific fields (15) are in @squaredr/fieldcraft-pro-telehealth.
|
|
217
217
|
*/
|
|
218
218
|
declare const QUESTION_TYPE_INFO: Record<string, QuestionTypeInfo>;
|
|
219
219
|
/**
|
|
220
|
-
* Default palette layout with categories (
|
|
220
|
+
* Default palette layout with categories (32 Pro field types).
|
|
221
221
|
* Telehealth fields can be appended via FormBuilder's `palette` prop.
|
|
222
222
|
*/
|
|
223
223
|
declare const DEFAULT_PALETTE: ({
|
|
@@ -212,12 +212,12 @@ declare const cleanPreset: FormBuilderTheme;
|
|
|
212
212
|
* Metadata for all question types available in the Pro palette.
|
|
213
213
|
* Icons are lucide-react component names (imported dynamically via ICON_MAP).
|
|
214
214
|
*
|
|
215
|
-
*
|
|
215
|
+
* 32 field types — general-purpose form building.
|
|
216
216
|
* Telehealth-specific fields (15) are in @squaredr/fieldcraft-pro-telehealth.
|
|
217
217
|
*/
|
|
218
218
|
declare const QUESTION_TYPE_INFO: Record<string, QuestionTypeInfo>;
|
|
219
219
|
/**
|
|
220
|
-
* Default palette layout with categories (
|
|
220
|
+
* Default palette layout with categories (32 Pro field types).
|
|
221
221
|
* Telehealth fields can be appended via FormBuilder's `palette` prop.
|
|
222
222
|
*/
|
|
223
223
|
declare const DEFAULT_PALETTE: ({
|
|
@@ -5,6 +5,7 @@ var react = require('react');
|
|
|
5
5
|
var core = require('@dnd-kit/core');
|
|
6
6
|
var lucideReact = require('lucide-react');
|
|
7
7
|
var fieldcraftReact = require('@squaredr/fieldcraft-react');
|
|
8
|
+
var fieldcraftCore = require('@squaredr/fieldcraft-core');
|
|
8
9
|
var clsx = require('clsx');
|
|
9
10
|
var tailwindMerge = require('tailwind-merge');
|
|
10
11
|
var jsxRuntime = require('react/jsx-runtime');
|
|
@@ -80,6 +81,39 @@ function generateOptionId() {
|
|
|
80
81
|
function deepClone(obj) {
|
|
81
82
|
return structuredClone(obj);
|
|
82
83
|
}
|
|
84
|
+
function cleanCondition(expr, deletedFieldId) {
|
|
85
|
+
if (expr.field === deletedFieldId) return void 0;
|
|
86
|
+
if (expr.field && expr.field !== deletedFieldId) return expr;
|
|
87
|
+
if (expr.conditions) {
|
|
88
|
+
const cleaned = expr.conditions.map((c) => cleanCondition(c, deletedFieldId)).filter((c) => c !== void 0);
|
|
89
|
+
if (cleaned.length === 0) return void 0;
|
|
90
|
+
if (cleaned.length === 1) return cleaned[0];
|
|
91
|
+
return { ...expr, conditions: cleaned };
|
|
92
|
+
}
|
|
93
|
+
return expr;
|
|
94
|
+
}
|
|
95
|
+
function cleanupOrphanConditions(schema, deletedFieldId) {
|
|
96
|
+
for (const section of schema.sections) {
|
|
97
|
+
if (section.showIf) {
|
|
98
|
+
const cleaned = cleanCondition(section.showIf, deletedFieldId);
|
|
99
|
+
if (cleaned) {
|
|
100
|
+
section.showIf = cleaned;
|
|
101
|
+
} else {
|
|
102
|
+
delete section.showIf;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
for (const question of section.questions) {
|
|
106
|
+
if (question.showIf) {
|
|
107
|
+
const cleaned = cleanCondition(question.showIf, deletedFieldId);
|
|
108
|
+
if (cleaned) {
|
|
109
|
+
question.showIf = cleaned;
|
|
110
|
+
} else {
|
|
111
|
+
delete question.showIf;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
83
117
|
function addSection(schema, section, index) {
|
|
84
118
|
const newSchema = deepClone(schema);
|
|
85
119
|
newSchema.sections.splice(index, 0, section);
|
|
@@ -87,7 +121,12 @@ function addSection(schema, section, index) {
|
|
|
87
121
|
}
|
|
88
122
|
function removeSection(schema, sectionId) {
|
|
89
123
|
const newSchema = deepClone(schema);
|
|
124
|
+
const removedSection = newSchema.sections.find((s) => s.id === sectionId);
|
|
125
|
+
const removedFieldIds = removedSection ? removedSection.questions.map((q) => q.id) : [];
|
|
90
126
|
newSchema.sections = newSchema.sections.filter((s) => s.id !== sectionId);
|
|
127
|
+
for (const fieldId of removedFieldIds) {
|
|
128
|
+
cleanupOrphanConditions(newSchema, fieldId);
|
|
129
|
+
}
|
|
91
130
|
return newSchema;
|
|
92
131
|
}
|
|
93
132
|
function updateSection(schema, sectionId, updates) {
|
|
@@ -137,6 +176,7 @@ function removeQuestion(schema, sectionId, questionId) {
|
|
|
137
176
|
const section = newSchema.sections.find((s) => s.id === sectionId);
|
|
138
177
|
if (!section) return schema;
|
|
139
178
|
section.questions = section.questions.filter((q) => q.id !== questionId);
|
|
179
|
+
cleanupOrphanConditions(newSchema, questionId);
|
|
140
180
|
return newSchema;
|
|
141
181
|
}
|
|
142
182
|
function updateQuestion(schema, sectionId, questionId, updates) {
|
|
@@ -975,11 +1015,13 @@ function QuestionPalette({ questionTypes, palette }) {
|
|
|
975
1015
|
const isCollapsed = collapsed[category.category] && !search;
|
|
976
1016
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
|
|
977
1017
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
978
|
-
|
|
1018
|
+
fieldcraftReact.Button,
|
|
979
1019
|
{
|
|
980
1020
|
type: "button",
|
|
1021
|
+
variant: "ghost",
|
|
1022
|
+
size: "xs",
|
|
981
1023
|
onClick: () => toggleCategory(category.category),
|
|
982
|
-
className: "
|
|
1024
|
+
className: "w-full justify-start px-1 text-[11px] font-semibold uppercase tracking-widest text-muted-foreground",
|
|
983
1025
|
"aria-expanded": !isCollapsed,
|
|
984
1026
|
children: [
|
|
985
1027
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1343,11 +1385,12 @@ function FormCanvas({ builderState }) {
|
|
|
1343
1385
|
section.id
|
|
1344
1386
|
)),
|
|
1345
1387
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1346
|
-
|
|
1388
|
+
fieldcraftReact.Button,
|
|
1347
1389
|
{
|
|
1348
1390
|
type: "button",
|
|
1391
|
+
variant: "outline",
|
|
1349
1392
|
onClick: handleAddSection,
|
|
1350
|
-
className: "w-full py-4 text-sm font-medium
|
|
1393
|
+
className: "w-full py-4 h-auto text-sm font-medium border-dashed border-fcb-border-strong text-muted-foreground hover:border-primary hover:text-primary hover:bg-primary/5",
|
|
1351
1394
|
children: [
|
|
1352
1395
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 14, strokeWidth: 2 }),
|
|
1353
1396
|
"Add Section"
|
|
@@ -1357,6 +1400,26 @@ function FormCanvas({ builderState }) {
|
|
|
1357
1400
|
] })
|
|
1358
1401
|
] }) });
|
|
1359
1402
|
}
|
|
1403
|
+
var NativeSelect = react.forwardRef(
|
|
1404
|
+
({ className, wrapperClassName, children, ...props }, ref) => {
|
|
1405
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("relative", wrapperClassName), children: [
|
|
1406
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1407
|
+
"select",
|
|
1408
|
+
{
|
|
1409
|
+
ref,
|
|
1410
|
+
className: cn(
|
|
1411
|
+
"flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
1412
|
+
className
|
|
1413
|
+
),
|
|
1414
|
+
...props,
|
|
1415
|
+
children
|
|
1416
|
+
}
|
|
1417
|
+
),
|
|
1418
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground" })
|
|
1419
|
+
] });
|
|
1420
|
+
}
|
|
1421
|
+
);
|
|
1422
|
+
NativeSelect.displayName = "NativeSelect";
|
|
1360
1423
|
function useConfigUpdater(question, onUpdate) {
|
|
1361
1424
|
return (field, value) => {
|
|
1362
1425
|
const current = question.config ?? {};
|
|
@@ -1751,18 +1814,7 @@ function SelectField({
|
|
|
1751
1814
|
}) {
|
|
1752
1815
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1753
1816
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
1754
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1755
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1756
|
-
"select",
|
|
1757
|
-
{
|
|
1758
|
-
value,
|
|
1759
|
-
onChange: (e) => onChange(e.target.value),
|
|
1760
|
-
className: "flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
1761
|
-
children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
1762
|
-
}
|
|
1763
|
-
),
|
|
1764
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
1765
|
-
] })
|
|
1817
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { value, onChange: (e) => onChange(e.target.value), children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value)) })
|
|
1766
1818
|
] });
|
|
1767
1819
|
}
|
|
1768
1820
|
function LikertLabelsEditor({
|
|
@@ -1783,15 +1835,7 @@ function LikertLabelsEditor({
|
|
|
1783
1835
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1784
1836
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1785
1837
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Scale Labels" }),
|
|
1786
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1787
|
-
"button",
|
|
1788
|
-
{
|
|
1789
|
-
type: "button",
|
|
1790
|
-
onClick: handleAdd,
|
|
1791
|
-
className: "text-xs text-primary hover:underline",
|
|
1792
|
-
children: "+ Add"
|
|
1793
|
-
}
|
|
1794
|
-
)
|
|
1838
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1795
1839
|
] }),
|
|
1796
1840
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: labels.map((label, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1797
1841
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground w-4 text-right shrink-0", children: index + 1 }),
|
|
@@ -1804,11 +1848,13 @@ function LikertLabelsEditor({
|
|
|
1804
1848
|
}
|
|
1805
1849
|
),
|
|
1806
1850
|
labels.length > 2 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1807
|
-
|
|
1851
|
+
fieldcraftReact.Button,
|
|
1808
1852
|
{
|
|
1809
1853
|
type: "button",
|
|
1854
|
+
variant: "ghost",
|
|
1855
|
+
size: "icon-xs",
|
|
1810
1856
|
onClick: () => handleRemove(index),
|
|
1811
|
-
className: "text-
|
|
1857
|
+
className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1812
1858
|
children: "x"
|
|
1813
1859
|
}
|
|
1814
1860
|
)
|
|
@@ -1837,15 +1883,7 @@ function MatrixItemsEditor({
|
|
|
1837
1883
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1838
1884
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1839
1885
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: label }),
|
|
1840
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1841
|
-
"button",
|
|
1842
|
-
{
|
|
1843
|
-
type: "button",
|
|
1844
|
-
onClick: handleAdd,
|
|
1845
|
-
className: "text-xs text-primary hover:underline",
|
|
1846
|
-
children: "+ Add"
|
|
1847
|
-
}
|
|
1848
|
-
)
|
|
1886
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1849
1887
|
] }),
|
|
1850
1888
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1851
1889
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1857,11 +1895,13 @@ function MatrixItemsEditor({
|
|
|
1857
1895
|
}
|
|
1858
1896
|
),
|
|
1859
1897
|
items.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1860
|
-
|
|
1898
|
+
fieldcraftReact.Button,
|
|
1861
1899
|
{
|
|
1862
1900
|
type: "button",
|
|
1901
|
+
variant: "ghost",
|
|
1902
|
+
size: "icon-xs",
|
|
1863
1903
|
onClick: () => handleRemove(index),
|
|
1864
|
-
className: "text-
|
|
1904
|
+
className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity",
|
|
1865
1905
|
children: "x"
|
|
1866
1906
|
}
|
|
1867
1907
|
)
|
|
@@ -1894,7 +1934,7 @@ function ScoringOptionsEditor({
|
|
|
1894
1934
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1895
1935
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1896
1936
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Score Options" }),
|
|
1897
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1937
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1898
1938
|
] }),
|
|
1899
1939
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: options.map((opt, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 group", children: [
|
|
1900
1940
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1916,7 +1956,7 @@ function ScoringOptionsEditor({
|
|
|
1916
1956
|
placeholder: "Score"
|
|
1917
1957
|
}
|
|
1918
1958
|
),
|
|
1919
|
-
options.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1959
|
+
options.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "ghost", size: "icon-xs", onClick: () => handleRemove(index), className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity", children: "x" })
|
|
1920
1960
|
] }, index)) })
|
|
1921
1961
|
] });
|
|
1922
1962
|
}
|
|
@@ -1938,7 +1978,7 @@ function ScoreRangesEditor({
|
|
|
1938
1978
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1939
1979
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-2", children: [
|
|
1940
1980
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground", children: "Score Ranges" }),
|
|
1941
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1981
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "link", size: "xs", onClick: handleAdd, className: "px-0", children: "+ Add" })
|
|
1942
1982
|
] }),
|
|
1943
1983
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2", children: ranges.map((range, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-2 rounded-md border border-border space-y-1.5 group", children: [
|
|
1944
1984
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
@@ -1946,7 +1986,7 @@ function ScoreRangesEditor({
|
|
|
1946
1986
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "to" }),
|
|
1947
1987
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { type: "number", value: range.max, onChange: (e) => handleUpdate(index, { max: Number(e.target.value) }), className: "h-7 text-xs w-16", placeholder: "Max" }),
|
|
1948
1988
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { value: range.label, onChange: (e) => handleUpdate(index, { label: e.target.value }), className: "h-7 text-xs flex-1", placeholder: "Label" }),
|
|
1949
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1989
|
+
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { type: "button", variant: "ghost", size: "icon-xs", onClick: () => handleRemove(index), className: "text-destructive opacity-0 group-hover:opacity-100 transition-opacity", children: "x" })
|
|
1950
1990
|
] }),
|
|
1951
1991
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Input, { value: range.description ?? "", onChange: (e) => handleUpdate(index, { description: e.target.value || void 0 }), className: "h-7 text-xs", placeholder: "Description (optional)" })
|
|
1952
1992
|
] }, index)) })
|
|
@@ -1996,26 +2036,20 @@ function ValidationRulesEditor({ question, onUpdate }) {
|
|
|
1996
2036
|
},
|
|
1997
2037
|
`${rule.type}-${index}`
|
|
1998
2038
|
)) }),
|
|
1999
|
-
availableTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
children:
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
availableTypes.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.value, children: t.label }, t.value))
|
|
2014
|
-
]
|
|
2015
|
-
}
|
|
2016
|
-
),
|
|
2017
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-3.5 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2018
|
-
] }) })
|
|
2039
|
+
availableTypes.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-3", children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2040
|
+
NativeSelect,
|
|
2041
|
+
{
|
|
2042
|
+
value: "",
|
|
2043
|
+
onChange: (e) => {
|
|
2044
|
+
if (e.target.value) addRule(e.target.value);
|
|
2045
|
+
},
|
|
2046
|
+
className: "h-8 text-xs text-muted-foreground",
|
|
2047
|
+
children: [
|
|
2048
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Add validation rule..." }),
|
|
2049
|
+
availableTypes.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: t.value, children: t.label }, t.value))
|
|
2050
|
+
]
|
|
2051
|
+
}
|
|
2052
|
+
) })
|
|
2019
2053
|
] });
|
|
2020
2054
|
}
|
|
2021
2055
|
function RuleRow({
|
|
@@ -2029,13 +2063,15 @@ function RuleRow({
|
|
|
2029
2063
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2030
2064
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-medium text-foreground", children: label }),
|
|
2031
2065
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2032
|
-
|
|
2066
|
+
fieldcraftReact.Button,
|
|
2033
2067
|
{
|
|
2034
2068
|
type: "button",
|
|
2069
|
+
variant: "ghost",
|
|
2070
|
+
size: "icon-xs",
|
|
2035
2071
|
onClick: onRemove,
|
|
2036
|
-
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
2072
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity hover:bg-destructive/10 hover:text-destructive",
|
|
2037
2073
|
title: "Remove rule",
|
|
2038
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12,
|
|
2074
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12, strokeWidth: 1.75 })
|
|
2039
2075
|
}
|
|
2040
2076
|
)
|
|
2041
2077
|
] }),
|
|
@@ -2270,11 +2306,13 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2270
2306
|
!hasConditions && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mb-3", children: "Always visible. Add a rule to show this field conditionally." }),
|
|
2271
2307
|
hasConditions && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-2 mb-3", children: showIf.conditions.map((cond, index) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2272
2308
|
index > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2273
|
-
|
|
2309
|
+
fieldcraftReact.Button,
|
|
2274
2310
|
{
|
|
2275
2311
|
type: "button",
|
|
2312
|
+
variant: "link",
|
|
2313
|
+
size: "xs",
|
|
2276
2314
|
onClick: toggleCombine,
|
|
2277
|
-
className: "text-[10px] font-semibold uppercase tracking-wider
|
|
2315
|
+
className: "text-[10px] font-semibold uppercase tracking-wider px-0 mb-1.5",
|
|
2278
2316
|
children: showIf.combine ?? "AND"
|
|
2279
2317
|
}
|
|
2280
2318
|
),
|
|
@@ -2282,43 +2320,39 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2282
2320
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2283
2321
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-muted-foreground uppercase tracking-wider", children: "When" }),
|
|
2284
2322
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2285
|
-
|
|
2323
|
+
fieldcraftReact.Button,
|
|
2286
2324
|
{
|
|
2287
2325
|
type: "button",
|
|
2326
|
+
variant: "ghost",
|
|
2327
|
+
size: "icon-xs",
|
|
2288
2328
|
onClick: () => removeCondition(index),
|
|
2289
|
-
className: "opacity-0 group-hover:opacity-100 transition-opacity",
|
|
2329
|
+
className: "opacity-0 group-hover:opacity-100 transition-opacity hover:bg-destructive/10 hover:text-destructive",
|
|
2290
2330
|
title: "Remove condition",
|
|
2291
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12,
|
|
2331
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12, strokeWidth: 1.75 })
|
|
2292
2332
|
}
|
|
2293
2333
|
)
|
|
2294
2334
|
] }),
|
|
2295
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
children:
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
"
|
|
2313
|
-
{
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
className: "flex h-7 w-full appearance-none rounded-md border border-input bg-card px-2 py-1 pr-7 text-xs shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
2317
|
-
children: OPERATORS.map((op) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: op.value, children: op.label }, op.value))
|
|
2318
|
-
}
|
|
2319
|
-
),
|
|
2320
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 size-3 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2321
|
-
] }),
|
|
2335
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2336
|
+
NativeSelect,
|
|
2337
|
+
{
|
|
2338
|
+
value: cond.field ?? "",
|
|
2339
|
+
onChange: (e) => updateCondition(index, { field: e.target.value }),
|
|
2340
|
+
className: "h-7 text-xs",
|
|
2341
|
+
children: [
|
|
2342
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select field..." }),
|
|
2343
|
+
fieldOptions.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.id, children: f.label }, f.id))
|
|
2344
|
+
]
|
|
2345
|
+
}
|
|
2346
|
+
),
|
|
2347
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2348
|
+
NativeSelect,
|
|
2349
|
+
{
|
|
2350
|
+
value: cond.operator ?? "eq",
|
|
2351
|
+
onChange: (e) => updateCondition(index, { operator: e.target.value }),
|
|
2352
|
+
className: "h-7 text-xs",
|
|
2353
|
+
children: OPERATORS.map((op) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: op.value, children: op.label }, op.value))
|
|
2354
|
+
}
|
|
2355
|
+
),
|
|
2322
2356
|
cond.operator !== "exists" && cond.operator !== "notExists" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2323
2357
|
fieldcraftReact.Input,
|
|
2324
2358
|
{
|
|
@@ -2331,11 +2365,13 @@ function ConditionEditor({ question, schema, onUpdate }) {
|
|
|
2331
2365
|
] })
|
|
2332
2366
|
] }, index)) }),
|
|
2333
2367
|
fieldOptions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2334
|
-
|
|
2368
|
+
fieldcraftReact.Button,
|
|
2335
2369
|
{
|
|
2336
2370
|
type: "button",
|
|
2371
|
+
variant: "link",
|
|
2372
|
+
size: "xs",
|
|
2337
2373
|
onClick: addCondition,
|
|
2338
|
-
className: "
|
|
2374
|
+
className: "px-0 gap-1.5",
|
|
2339
2375
|
children: [
|
|
2340
2376
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 12, strokeWidth: 2 }),
|
|
2341
2377
|
"Add condition"
|
|
@@ -2497,18 +2533,7 @@ function SettingsSelect({
|
|
|
2497
2533
|
}) {
|
|
2498
2534
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2499
2535
|
/* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Label, { className: "text-xs text-muted-foreground mb-1", children: label }),
|
|
2500
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2501
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2502
|
-
"select",
|
|
2503
|
-
{
|
|
2504
|
-
value,
|
|
2505
|
-
onChange: (e) => onChange(e.target.value),
|
|
2506
|
-
className: "flex h-9 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-sm shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-foreground cursor-pointer",
|
|
2507
|
-
children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
2508
|
-
}
|
|
2509
|
-
),
|
|
2510
|
-
/* @__PURE__ */ jsxRuntime.jsx("svg", { className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 size-4 text-muted-foreground", xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m6 9 6 6 6-6" }) })
|
|
2511
|
-
] })
|
|
2536
|
+
/* @__PURE__ */ jsxRuntime.jsx(NativeSelect, { value, onChange: (e) => onChange(e.target.value), children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: opt.value, children: opt.label }, opt.value)) })
|
|
2512
2537
|
] });
|
|
2513
2538
|
}
|
|
2514
2539
|
function PropertiesPanel({ builderState }) {
|
|
@@ -2610,13 +2635,14 @@ function QuestionProperties({ question, sectionId, builderState, onClose, onOpen
|
|
|
2610
2635
|
typeInfo?.label
|
|
2611
2636
|
] }) }),
|
|
2612
2637
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 px-4 pt-3 flex gap-0.5", children: tabs.map((tab) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2613
|
-
|
|
2638
|
+
fieldcraftReact.Button,
|
|
2614
2639
|
{
|
|
2615
2640
|
type: "button",
|
|
2641
|
+
variant: activeTab === tab.key ? "default" : "ghost",
|
|
2642
|
+
size: "xs",
|
|
2616
2643
|
onClick: () => setActiveTab(tab.key),
|
|
2617
2644
|
className: cn(
|
|
2618
|
-
|
|
2619
|
-
activeTab === tab.key ? "bg-primary text-primary-foreground" : "bg-transparent text-muted-foreground hover:bg-accent hover:text-foreground"
|
|
2645
|
+
activeTab !== tab.key && "text-muted-foreground"
|
|
2620
2646
|
),
|
|
2621
2647
|
children: tab.label
|
|
2622
2648
|
},
|
|
@@ -2875,13 +2901,18 @@ function FormBuilderCore(props) {
|
|
|
2875
2901
|
reader.onload = (event) => {
|
|
2876
2902
|
try {
|
|
2877
2903
|
const parsed = JSON.parse(event.target?.result);
|
|
2878
|
-
|
|
2879
|
-
|
|
2904
|
+
const validated = fieldcraftCore.validateSchema(parsed);
|
|
2905
|
+
builderState.resetSchema(validated);
|
|
2906
|
+
} catch (err) {
|
|
2907
|
+
if (err instanceof fieldcraftCore.FormEngineSchemaError) {
|
|
2908
|
+
const details = err.issues.slice(0, 3).map((i) => `\u2022 ${i.path.join(".")}: ${i.message}`).join("\n");
|
|
2909
|
+
alert(`Invalid schema:
|
|
2910
|
+
${details}`);
|
|
2911
|
+
} else if (err instanceof SyntaxError) {
|
|
2912
|
+
alert("Failed to parse JSON file.");
|
|
2880
2913
|
} else {
|
|
2881
|
-
alert("Invalid schema
|
|
2914
|
+
alert("Invalid schema file.");
|
|
2882
2915
|
}
|
|
2883
|
-
} catch {
|
|
2884
|
-
alert("Failed to parse JSON file.");
|
|
2885
2916
|
}
|
|
2886
2917
|
};
|
|
2887
2918
|
reader.readAsText(file);
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset,
|
|
1
|
+
export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from '../chunk-DDQDYTMB.mjs';
|
|
2
|
+
export { cn } from '../chunk-QQ4JZGTD.mjs';
|