@squaredr/fieldcraft-pro 0.0.5 → 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/dist/index.js CHANGED
@@ -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
- "button",
1018
+ fieldcraftReact.Button,
979
1019
  {
980
1020
  type: "button",
1021
+ variant: "ghost",
1022
+ size: "xs",
981
1023
  onClick: () => toggleCategory(category.category),
982
- className: "flex items-center gap-1.5 w-full px-1 py-1 text-left text-[11px] font-semibold uppercase tracking-widest text-muted-foreground bg-transparent border-0 cursor-pointer",
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
- "button",
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 rounded-lg border border-dashed border-fcb-border-strong text-muted-foreground bg-transparent flex items-center justify-center gap-2 cursor-pointer transition-colors hover:border-primary hover:text-primary hover:bg-primary/5",
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.jsxs("div", { className: "relative", children: [
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
- "button",
1851
+ fieldcraftReact.Button,
1808
1852
  {
1809
1853
  type: "button",
1854
+ variant: "ghost",
1855
+ size: "icon-xs",
1810
1856
  onClick: () => handleRemove(index),
1811
- className: "text-xs text-destructive opacity-0 group-hover:opacity-100 transition-opacity px-1",
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
- "button",
1898
+ fieldcraftReact.Button,
1861
1899
  {
1862
1900
  type: "button",
1901
+ variant: "ghost",
1902
+ size: "icon-xs",
1863
1903
  onClick: () => handleRemove(index),
1864
- className: "text-xs text-destructive opacity-0 group-hover:opacity-100 transition-opacity px-1",
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("button", { type: "button", onClick: handleAdd, className: "text-xs text-primary hover:underline", children: "+ Add" })
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("button", { type: "button", onClick: () => handleRemove(index), className: "text-xs text-destructive opacity-0 group-hover:opacity-100 transition-opacity px-1", children: "x" })
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("button", { type: "button", onClick: handleAdd, className: "text-xs text-primary hover:underline", children: "+ Add" })
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("button", { type: "button", onClick: () => handleRemove(index), className: "text-xs text-destructive opacity-0 group-hover:opacity-100 transition-opacity px-1", children: "x" })
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("div", { className: "relative", children: [
2000
- /* @__PURE__ */ jsxRuntime.jsxs(
2001
- "select",
2002
- {
2003
- value: "",
2004
- onChange: (e) => {
2005
- if (e.target.value) addRule(e.target.value);
2006
- },
2007
- className: "flex h-8 w-full appearance-none rounded-md border border-input bg-card px-3 py-1 pr-8 text-xs shadow-xs transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring text-muted-foreground cursor-pointer",
2008
- children: [
2009
- /* @__PURE__ */ jsxRuntime.jsxs("option", { value: "", children: [
2010
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { size: 12 }),
2011
- " Add validation rule..."
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
- "button",
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, className: "text-destructive", strokeWidth: 1.75 })
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
- "button",
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 text-primary mb-1.5 block cursor-pointer hover:underline",
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
- "button",
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, className: "text-destructive", strokeWidth: 1.75 })
2331
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { size: 12, strokeWidth: 1.75 })
2292
2332
  }
2293
2333
  )
2294
2334
  ] }),
2295
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2296
- /* @__PURE__ */ jsxRuntime.jsxs(
2297
- "select",
2298
- {
2299
- value: cond.field ?? "",
2300
- onChange: (e) => updateCondition(index, { field: e.target.value }),
2301
- 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",
2302
- children: [
2303
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select field..." }),
2304
- fieldOptions.map((f) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: f.id, children: f.label }, f.id))
2305
- ]
2306
- }
2307
- ),
2308
- /* @__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" }) })
2309
- ] }),
2310
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
2311
- /* @__PURE__ */ jsxRuntime.jsx(
2312
- "select",
2313
- {
2314
- value: cond.operator ?? "eq",
2315
- onChange: (e) => updateCondition(index, { operator: e.target.value }),
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
- "button",
2368
+ fieldcraftReact.Button,
2335
2369
  {
2336
2370
  type: "button",
2371
+ variant: "link",
2372
+ size: "xs",
2337
2373
  onClick: addCondition,
2338
- className: "flex items-center gap-1.5 text-xs text-primary hover:underline",
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.jsxs("div", { className: "relative", children: [
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
- "button",
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
- "px-3 py-1.5 text-xs font-medium rounded-md border-0 cursor-pointer transition-colors",
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
- if (parsed && parsed.sections && Array.isArray(parsed.sections)) {
2879
- builderState.resetSchema(parsed);
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: must contain a 'sections' array.");
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);
@@ -3166,74 +3197,190 @@ var cleanPreset = {
3166
3197
  borderStrong: "#d1d5db",
3167
3198
  textDim: "#9ca3af"
3168
3199
  };
3200
+
3201
+ // src/response-viewer/clinical-display-data.ts
3202
+ var BODY_REGION_LABELS = {
3203
+ head: "Head",
3204
+ neck: "Neck",
3205
+ "left-shoulder": "Left Shoulder",
3206
+ "right-shoulder": "Right Shoulder",
3207
+ chest: "Chest",
3208
+ abdomen: "Abdomen",
3209
+ "left-upper-arm": "Left Upper Arm",
3210
+ "right-upper-arm": "Right Upper Arm",
3211
+ "left-forearm": "Left Forearm",
3212
+ "right-forearm": "Right Forearm",
3213
+ "left-hand": "Left Hand",
3214
+ "right-hand": "Right Hand",
3215
+ pelvis: "Pelvis",
3216
+ "left-thigh": "Left Thigh",
3217
+ "right-thigh": "Right Thigh",
3218
+ "left-knee": "Left Knee",
3219
+ "right-knee": "Right Knee",
3220
+ "left-shin": "Left Shin",
3221
+ "right-shin": "Right Shin",
3222
+ "left-foot": "Left Foot",
3223
+ "right-foot": "Right Foot"
3224
+ };
3225
+ var PAIN_FACE_LABELS = [
3226
+ { score: 0, label: "No Hurt", color: "#22c55e" },
3227
+ { score: 2, label: "Hurts Little Bit", color: "#84cc16" },
3228
+ { score: 4, label: "Hurts Little More", color: "#eab308" },
3229
+ { score: 6, label: "Hurts Even More", color: "#f97316" },
3230
+ { score: 8, label: "Hurts Whole Lot", color: "#ef4444" },
3231
+ { score: 10, label: "Hurts Worst", color: "#dc2626" }
3232
+ ];
3233
+ function getPainLabel(score) {
3234
+ const face = PAIN_FACE_LABELS.reduce(
3235
+ (closest, f) => closest == null || Math.abs(f.score - score) < Math.abs(closest.score - score) ? f : closest,
3236
+ void 0
3237
+ );
3238
+ return face;
3239
+ }
3240
+ var SEVERITY_COLORS = {
3241
+ mild: "#eab308",
3242
+ moderate: "#f97316",
3243
+ severe: "#ef4444",
3244
+ "life-threatening": "#991b1b"
3245
+ };
3246
+ var BMI_CATEGORIES = [
3247
+ { label: "Underweight", max: 18.5, color: "#3b82f6" },
3248
+ { label: "Normal", max: 25, color: "#22c55e" },
3249
+ { label: "Overweight", max: 30, color: "#eab308" },
3250
+ { label: "Obese", max: Infinity, color: "#ef4444" }
3251
+ ];
3252
+ function getBmiCategory(bmi) {
3253
+ return BMI_CATEGORIES.find((c) => bmi < c.max) ?? BMI_CATEGORIES[BMI_CATEGORIES.length - 1];
3254
+ }
3255
+ var INSTRUMENT_DISPLAY_NAMES = {
3256
+ phq9: "PHQ-9",
3257
+ phq2: "PHQ-2",
3258
+ gad7: "GAD-7",
3259
+ gad2: "GAD-2",
3260
+ "audit-c": "AUDIT-C",
3261
+ dast10: "DAST-10",
3262
+ cssrs: "C-SSRS",
3263
+ epds: "EPDS",
3264
+ isi: "ISI",
3265
+ pcl5: "PCL-5",
3266
+ psc17: "PSC-17"
3267
+ };
3268
+ var SCORE_THRESHOLDS = {
3269
+ phq9: [
3270
+ { min: 0, max: 4, label: "Minimal", color: "#22c55e" },
3271
+ { min: 5, max: 9, label: "Mild", color: "#eab308" },
3272
+ { min: 10, max: 14, label: "Moderate", color: "#f97316" },
3273
+ { min: 15, max: 19, label: "Moderately Severe", color: "#ef4444" },
3274
+ { min: 20, max: 27, label: "Severe", color: "#dc2626" }
3275
+ ],
3276
+ phq2: [
3277
+ { min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
3278
+ { min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
3279
+ ],
3280
+ gad7: [
3281
+ { min: 0, max: 4, label: "Minimal", color: "#22c55e" },
3282
+ { min: 5, max: 9, label: "Mild", color: "#eab308" },
3283
+ { min: 10, max: 14, label: "Moderate", color: "#f97316" },
3284
+ { min: 15, max: 21, label: "Severe", color: "#ef4444" }
3285
+ ],
3286
+ gad2: [
3287
+ { min: 0, max: 2, label: "Negative Screen", color: "#22c55e" },
3288
+ { min: 3, max: 6, label: "Positive Screen", color: "#ef4444" }
3289
+ ],
3290
+ "audit-c": [
3291
+ { min: 0, max: 3, label: "Low Risk", color: "#22c55e" },
3292
+ { min: 4, max: 7, label: "At Risk", color: "#eab308" },
3293
+ { min: 8, max: 12, label: "High Risk", color: "#ef4444" }
3294
+ ],
3295
+ dast10: [
3296
+ { min: 0, max: 0, label: "No Problems", color: "#22c55e" },
3297
+ { min: 1, max: 2, label: "Low Level", color: "#eab308" },
3298
+ { min: 3, max: 5, label: "Moderate Level", color: "#f97316" },
3299
+ { min: 6, max: 8, label: "Substantial Level", color: "#ef4444" },
3300
+ { min: 9, max: 10, label: "Severe Level", color: "#dc2626" }
3301
+ ],
3302
+ cssrs: [
3303
+ { min: 0, max: 0, label: "No Risk Identified", color: "#22c55e" },
3304
+ { min: 1, max: 1, label: "Wish to be Dead", color: "#eab308" },
3305
+ { min: 2, max: 2, label: "Non-specific Active Suicidal Thoughts", color: "#f97316" },
3306
+ { min: 3, max: 3, label: "Active Suicidal Ideation", color: "#ef4444" },
3307
+ { min: 4, max: 4, label: "Active Ideation with Intent", color: "#dc2626" },
3308
+ { min: 5, max: 5, label: "Active Ideation with Plan", color: "#991b1b" },
3309
+ { min: 6, max: 6, label: "Imminent Risk", color: "#7f1d1d" }
3310
+ ],
3311
+ epds: [
3312
+ { min: 0, max: 8, label: "Low Likelihood", color: "#22c55e" },
3313
+ { min: 9, max: 11, label: "Possible Depression", color: "#eab308" },
3314
+ { min: 12, max: 13, label: "Fairly High Possibility", color: "#f97316" },
3315
+ { min: 14, max: 30, label: "Probable Depression", color: "#ef4444" }
3316
+ ],
3317
+ isi: [
3318
+ { min: 0, max: 7, label: "No Clinically Significant Insomnia", color: "#22c55e" },
3319
+ { min: 8, max: 14, label: "Subthreshold Insomnia", color: "#eab308" },
3320
+ { min: 15, max: 21, label: "Clinical Insomnia (Moderate)", color: "#f97316" },
3321
+ { min: 22, max: 28, label: "Clinical Insomnia (Severe)", color: "#ef4444" }
3322
+ ],
3323
+ pcl5: [
3324
+ { min: 0, max: 30, label: "Below Threshold", color: "#22c55e" },
3325
+ { min: 31, max: 80, label: "Probable PTSD", color: "#ef4444" }
3326
+ ],
3327
+ psc17: [
3328
+ { min: 0, max: 14, label: "No Significant Concerns", color: "#22c55e" },
3329
+ { min: 15, max: 34, label: "Significant Concerns", color: "#ef4444" }
3330
+ ]
3331
+ };
3332
+ function getScoreSeverity(instrumentKey, score) {
3333
+ const thresholds = SCORE_THRESHOLDS[instrumentKey];
3334
+ if (!thresholds) return void 0;
3335
+ return thresholds.find((t) => score >= t.min && score <= t.max);
3336
+ }
3169
3337
  function ResponseTable({ schema, responses, onRowClick }) {
3170
3338
  const questions = getAllQuestions(schema);
3171
- return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflow: "auto", fontFamily: "inherit" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
3172
- "table",
3173
- {
3174
- style: {
3175
- width: "100%",
3176
- borderCollapse: "collapse",
3177
- fontSize: "13px"
3178
- },
3179
- children: [
3180
- /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { backgroundColor: "var(--muted, #111113)" }, children: [
3181
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Submitted" }),
3182
- questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: q.label }, q.id)),
3183
- /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Score" })
3184
- ] }) }),
3185
- /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
3186
- responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
3187
- "tr",
3188
- {
3189
- onClick: () => onRowClick?.(response),
3190
- style: {
3191
- cursor: onRowClick ? "pointer" : "default",
3192
- borderBottom: "1px solid var(--border, #1c1c20)"
3193
- },
3194
- onMouseEnter: (e) => {
3195
- if (onRowClick) e.currentTarget.style.backgroundColor = "var(--accent, #17171a)";
3196
- },
3197
- onMouseLeave: (e) => {
3198
- e.currentTarget.style.backgroundColor = "transparent";
3339
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
3340
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { className: "bg-muted", children: [
3341
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
3342
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
3343
+ "th",
3344
+ {
3345
+ className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap",
3346
+ children: q.label
3347
+ },
3348
+ q.id
3349
+ )),
3350
+ /* @__PURE__ */ jsxRuntime.jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
3351
+ ] }) }),
3352
+ /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
3353
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
3354
+ "tr",
3355
+ {
3356
+ onClick: () => onRowClick?.(response),
3357
+ className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
3358
+ children: [
3359
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: new Date(response.submittedAt).toLocaleString() }),
3360
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx(
3361
+ "td",
3362
+ {
3363
+ className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap",
3364
+ children: formatCellValue(response.values[q.id], q.type)
3199
3365
  },
3200
- children: [
3201
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: new Date(response.submittedAt).toLocaleString() }),
3202
- questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: formatCellValue(response.values[q.id]) }, q.id)),
3203
- /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: response.totalScore ?? "\u2014" })
3204
- ]
3205
- },
3206
- response.sessionToken || idx
3207
- )),
3208
- responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
3209
- "td",
3210
- {
3211
- colSpan: questions.length + 2,
3212
- style: { ...tdStyle, textAlign: "center", color: "var(--muted-foreground, #8a8a95)", padding: "32px" },
3213
- children: "No responses yet"
3214
- }
3215
- ) })
3216
- ] })
3217
- ]
3218
- }
3219
- ) });
3366
+ q.id
3367
+ )),
3368
+ /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: response.totalScore ?? "\u2014" })
3369
+ ]
3370
+ },
3371
+ response.sessionToken || idx
3372
+ )),
3373
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
3374
+ "td",
3375
+ {
3376
+ colSpan: questions.length + 2,
3377
+ className: "px-3 py-8 text-center text-muted-foreground",
3378
+ children: "No responses yet"
3379
+ }
3380
+ ) })
3381
+ ] })
3382
+ ] }) });
3220
3383
  }
3221
- var thStyle = {
3222
- padding: "8px 12px",
3223
- textAlign: "left",
3224
- fontWeight: 600,
3225
- color: "var(--foreground, #e8e8ea)",
3226
- borderBottom: "2px solid var(--border, #1c1c20)",
3227
- whiteSpace: "nowrap"
3228
- };
3229
- var tdStyle = {
3230
- padding: "8px 12px",
3231
- color: "var(--foreground, #e8e8ea)",
3232
- maxWidth: "200px",
3233
- overflow: "hidden",
3234
- textOverflow: "ellipsis",
3235
- whiteSpace: "nowrap"
3236
- };
3237
3384
  function getAllQuestions(schema) {
3238
3385
  const questions = [];
3239
3386
  for (const section of schema.sections) {
@@ -3246,8 +3393,69 @@ function getAllQuestions(schema) {
3246
3393
  }
3247
3394
  return questions;
3248
3395
  }
3249
- function formatCellValue(value) {
3396
+ function formatCellValue(value, type) {
3250
3397
  if (value == null) return "\u2014";
3398
+ if (type) {
3399
+ switch (type) {
3400
+ case "vitals_entry": {
3401
+ if (typeof value !== "object" || value === null) break;
3402
+ const v = value;
3403
+ const parts = [];
3404
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
3405
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
3406
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
3407
+ if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
3408
+ return parts.length > 0 ? parts.join(", ") : "\u2014";
3409
+ }
3410
+ case "medication_list":
3411
+ if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
3412
+ break;
3413
+ case "allergy_list":
3414
+ if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
3415
+ break;
3416
+ case "body_diagram":
3417
+ if (Array.isArray(value)) {
3418
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
3419
+ return labels.join(", ");
3420
+ }
3421
+ break;
3422
+ case "pain_scale":
3423
+ if (typeof value === "number") return `${value}/10`;
3424
+ break;
3425
+ case "bmi_calculator": {
3426
+ if (typeof value !== "object" || value === null) break;
3427
+ const d = value;
3428
+ if (d.bmi != null) return `BMI ${d.bmi}`;
3429
+ break;
3430
+ }
3431
+ case "payment": {
3432
+ if (typeof value !== "object" || value === null) break;
3433
+ const p = value;
3434
+ const status = p.status;
3435
+ return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
3436
+ }
3437
+ case "insurance_card": {
3438
+ if (typeof value !== "object" || value === null) break;
3439
+ const ins = value;
3440
+ const parts = [ins.carrierId, ins.planName].filter(Boolean);
3441
+ return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
3442
+ }
3443
+ case "legal_name": {
3444
+ if (typeof value !== "object" || value === null) break;
3445
+ const n = value;
3446
+ return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
3447
+ }
3448
+ case "address": {
3449
+ if (typeof value !== "object" || value === null) break;
3450
+ const a = value;
3451
+ return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
3452
+ }
3453
+ case "consent":
3454
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
3455
+ case "signature":
3456
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
3457
+ }
3458
+ }
3251
3459
  if (typeof value === "boolean") return value ? "Yes" : "No";
3252
3460
  if (Array.isArray(value)) return value.join(", ");
3253
3461
  if (typeof value === "object") return JSON.stringify(value);
@@ -3258,238 +3466,570 @@ function ResponseCard({ response, fields, onClick }) {
3258
3466
  "div",
3259
3467
  {
3260
3468
  onClick,
3261
- style: {
3262
- border: "1px solid var(--border, #1c1c20)",
3263
- borderRadius: "8px",
3264
- padding: "16px",
3265
- backgroundColor: "var(--card, #111113)",
3266
- cursor: onClick ? "pointer" : "default",
3267
- fontFamily: "inherit",
3268
- transition: "box-shadow 0.15s"
3269
- },
3270
- onMouseEnter: (e) => {
3271
- if (onClick) e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
3272
- },
3273
- onMouseLeave: (e) => {
3274
- e.currentTarget.style.boxShadow = "none";
3275
- },
3469
+ className: onClick ? "border border-border rounded-lg p-4 bg-card cursor-pointer transition-shadow hover:shadow-md" : "border border-border rounded-lg p-4 bg-card",
3276
3470
  children: [
3277
- /* @__PURE__ */ jsxRuntime.jsxs(
3278
- "div",
3279
- {
3280
- style: {
3281
- display: "flex",
3282
- justifyContent: "space-between",
3283
- marginBottom: "12px",
3284
- fontSize: "12px",
3285
- color: "var(--muted-foreground, #8a8a95)"
3286
- },
3287
- children: [
3288
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
3289
- response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3290
- Math.round(response.completionTimeMs / 1e3),
3291
- "s"
3292
- ] })
3293
- ]
3294
- }
3295
- ),
3296
- fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "8px" }, children: [
3297
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "11px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "2px" }, children: field.label }),
3298
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "13px", color: "var(--foreground, #e8e8ea)" }, children: formatValue(field.value) })
3471
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between mb-3 text-xs text-muted-foreground", children: [
3472
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
3473
+ response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3474
+ Math.round(response.completionTimeMs / 1e3),
3475
+ "s"
3476
+ ] })
3477
+ ] }),
3478
+ fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2", children: [
3479
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-muted-foreground mb-0.5", children: field.label }),
3480
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[13px] text-foreground", children: formatCardValue(field.value, field.type) })
3299
3481
  ] }, field.questionId)),
3300
- fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginTop: "8px" }, children: [
3482
+ fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mt-2", children: [
3301
3483
  "+",
3302
3484
  fields.length - 4,
3303
3485
  " more fields"
3304
3486
  ] }),
3305
- response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
3306
- "div",
3307
- {
3308
- style: {
3309
- marginTop: "12px",
3310
- paddingTop: "8px",
3311
- borderTop: "1px solid var(--border, #1c1c20)",
3312
- fontSize: "13px",
3313
- fontWeight: 600,
3314
- color: "var(--foreground, #e8e8ea)"
3315
- },
3316
- children: [
3317
- "Score: ",
3318
- response.totalScore
3319
- ]
3320
- }
3321
- )
3487
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-3 pt-2 border-t border-border text-[13px] font-semibold text-foreground", children: [
3488
+ "Score: ",
3489
+ response.totalScore
3490
+ ] })
3322
3491
  ]
3323
3492
  }
3324
3493
  );
3325
3494
  }
3326
- function formatValue(value) {
3495
+ function formatCardValue(value, type) {
3327
3496
  if (value == null) return "\u2014";
3497
+ if (type) {
3498
+ switch (type) {
3499
+ case "vitals_entry": {
3500
+ if (typeof value !== "object" || value === null) break;
3501
+ const v = value;
3502
+ const parts = [];
3503
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
3504
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
3505
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
3506
+ if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
3507
+ return parts.length > 0 ? parts.join(", ") : "\u2014";
3508
+ }
3509
+ case "medication_list":
3510
+ if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
3511
+ break;
3512
+ case "allergy_list":
3513
+ if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
3514
+ break;
3515
+ case "body_diagram":
3516
+ if (Array.isArray(value)) {
3517
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
3518
+ return labels.join(", ");
3519
+ }
3520
+ break;
3521
+ case "pain_scale":
3522
+ if (typeof value === "number") return `${value}/10`;
3523
+ break;
3524
+ case "bmi_calculator": {
3525
+ if (typeof value !== "object" || value === null) break;
3526
+ const d = value;
3527
+ if (d.bmi != null) return `BMI ${d.bmi}`;
3528
+ break;
3529
+ }
3530
+ case "payment": {
3531
+ if (typeof value !== "object" || value === null) break;
3532
+ const p = value;
3533
+ const status = p.status;
3534
+ return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
3535
+ }
3536
+ case "insurance_card": {
3537
+ if (typeof value !== "object" || value === null) break;
3538
+ const ins = value;
3539
+ const parts = [ins.carrierId, ins.planName].filter(Boolean);
3540
+ return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
3541
+ }
3542
+ case "legal_name": {
3543
+ if (typeof value !== "object" || value === null) break;
3544
+ const n = value;
3545
+ return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
3546
+ }
3547
+ case "address": {
3548
+ if (typeof value !== "object" || value === null) break;
3549
+ const a = value;
3550
+ return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
3551
+ }
3552
+ case "consent":
3553
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
3554
+ case "signature":
3555
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
3556
+ }
3557
+ }
3328
3558
  if (typeof value === "boolean") return value ? "Yes" : "No";
3329
- if (Array.isArray(value)) return value.map(formatValue).join(", ");
3559
+ if (Array.isArray(value)) return value.map(String).join(", ");
3330
3560
  if (typeof value === "object") return JSON.stringify(value);
3331
3561
  return String(value);
3332
3562
  }
3333
3563
  function ResponseDetail({ response, fields, onBack }) {
3334
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontFamily: "inherit" }, children: [
3335
- /* @__PURE__ */ jsxRuntime.jsxs(
3336
- "div",
3337
- {
3338
- style: {
3339
- display: "flex",
3340
- alignItems: "center",
3341
- gap: "12px",
3342
- marginBottom: "20px",
3343
- paddingBottom: "12px",
3344
- borderBottom: "1px solid var(--border, #1c1c20)"
3345
- },
3346
- children: [
3347
- onBack && /* @__PURE__ */ jsxRuntime.jsx(
3348
- "button",
3349
- {
3350
- type: "button",
3351
- onClick: onBack,
3352
- style: {
3353
- padding: "4px 10px",
3354
- fontSize: "13px",
3355
- color: "var(--secondary-foreground, #e8e8ea)",
3356
- backgroundColor: "var(--secondary, #17171a)",
3357
- border: "1px solid var(--border, #1c1c20)",
3358
- borderRadius: "6px",
3359
- cursor: "pointer"
3360
- },
3361
- children: "Back"
3362
- }
3363
- ),
3364
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3365
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", fontWeight: 600, color: "var(--foreground, #e8e8ea)" }, children: "Response Detail" }),
3366
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)" }, children: [
3367
- "Submitted ",
3368
- new Date(response.submittedAt).toLocaleString(),
3369
- response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
3370
- ] })
3371
- ] })
3372
- ]
3373
- }
3374
- ),
3375
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
3564
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3565
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 mb-5 pb-3 border-b border-border", children: [
3566
+ onBack && /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Button, { variant: "outline", size: "sm", onClick: onBack, children: "Back" }),
3567
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3568
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground", children: "Response Detail" }),
3569
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
3570
+ "Submitted ",
3571
+ new Date(response.submittedAt).toLocaleString(),
3572
+ response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
3573
+ ] })
3574
+ ] })
3575
+ ] }),
3576
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-4", children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
3376
3577
  "div",
3377
3578
  {
3378
- style: {
3379
- padding: "12px",
3380
- backgroundColor: "var(--muted, #111113)",
3381
- borderRadius: "6px"
3382
- },
3579
+ className: "p-3 bg-muted rounded-md",
3383
3580
  children: [
3384
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "4px" }, children: [
3581
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground mb-1", children: [
3385
3582
  field.label,
3386
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: "8px", fontSize: "11px", color: "var(--muted-foreground, #8a8a95)" }, children: [
3583
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "ml-2 text-[11px] text-muted-foreground", children: [
3387
3584
  "(",
3388
3585
  field.type,
3389
3586
  ")"
3390
3587
  ] })
3391
3588
  ] }),
3392
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", color: "var(--foreground, #e8e8ea)", whiteSpace: "pre-wrap" }, children: formatDetailValue(field.value) })
3589
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm text-foreground", children: renderFieldValue(field) })
3393
3590
  ]
3394
3591
  },
3395
3592
  field.questionId
3396
3593
  )) }),
3397
- response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "20px" }, children: [
3398
- /* @__PURE__ */ jsxRuntime.jsx(
3399
- "div",
3400
- {
3401
- style: {
3402
- fontSize: "14px",
3403
- fontWeight: 600,
3404
- color: "var(--foreground, #e8e8ea)",
3405
- marginBottom: "12px"
3406
- },
3407
- children: "Scores"
3408
- }
3409
- ),
3410
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "12px", flexWrap: "wrap" }, children: [
3411
- Object.entries(response.scores).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(
3412
- "div",
3413
- {
3414
- style: {
3415
- padding: "8px 16px",
3416
- backgroundColor: "var(--accent, #17171a)",
3417
- borderRadius: "6px",
3418
- fontSize: "13px"
3419
- },
3420
- children: [
3421
- /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: [
3422
- key,
3423
- ": "
3424
- ] }),
3425
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: value })
3426
- ]
3427
- },
3428
- key
3429
- )),
3430
- response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
3431
- "div",
3432
- {
3433
- style: {
3434
- padding: "8px 16px",
3435
- backgroundColor: "var(--accent, #17171a)",
3436
- borderRadius: "6px",
3437
- fontSize: "13px"
3594
+ response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5", children: [
3595
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-foreground mb-3", children: "Scores" }),
3596
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 flex-wrap", children: [
3597
+ Object.entries(response.scores).map(([key, value]) => {
3598
+ const displayName = INSTRUMENT_DISPLAY_NAMES[key] ?? key;
3599
+ const severity = typeof value === "number" ? getScoreSeverity(key, value) : void 0;
3600
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3601
+ "div",
3602
+ {
3603
+ className: "px-4 py-2 bg-accent rounded-md text-[13px] flex items-center gap-2",
3604
+ children: [
3605
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
3606
+ displayName,
3607
+ ": "
3608
+ ] }),
3609
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: value }),
3610
+ severity && /* @__PURE__ */ jsxRuntime.jsx(
3611
+ "span",
3612
+ {
3613
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
3614
+ style: { backgroundColor: severity.color },
3615
+ children: severity.label
3616
+ }
3617
+ )
3618
+ ]
3438
3619
  },
3439
- children: [
3440
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: "Total: " }),
3441
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: response.totalScore })
3442
- ]
3443
- }
3444
- )
3620
+ key
3621
+ );
3622
+ }),
3623
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-4 py-2 bg-accent rounded-md text-[13px]", children: [
3624
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "Total: " }),
3625
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold text-primary", children: response.totalScore })
3626
+ ] })
3445
3627
  ] })
3446
3628
  ] }),
3447
- /* @__PURE__ */ jsxRuntime.jsxs(
3629
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-5 pt-3 border-t border-border text-xs text-muted-foreground", children: [
3630
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3631
+ "Schema: ",
3632
+ response.schemaId,
3633
+ " (v",
3634
+ response.schemaVersion,
3635
+ ")"
3636
+ ] }),
3637
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3638
+ "Session: ",
3639
+ response.sessionToken
3640
+ ] })
3641
+ ] })
3642
+ ] });
3643
+ }
3644
+ function renderFieldValue(field) {
3645
+ const { type, value } = field;
3646
+ if (value == null) return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" });
3647
+ switch (type) {
3648
+ case "vitals_entry":
3649
+ return renderVitals(value);
3650
+ case "medication_list":
3651
+ return renderMedications(value);
3652
+ case "allergy_list":
3653
+ return renderAllergies(value);
3654
+ case "bmi_calculator":
3655
+ return renderBmi(value);
3656
+ case "body_diagram":
3657
+ return renderBodyDiagram(value);
3658
+ case "pain_scale":
3659
+ return renderPainScale(value);
3660
+ case "insurance_card":
3661
+ return renderInsurance(value);
3662
+ case "payment":
3663
+ return renderPayment(value);
3664
+ case "legal_name":
3665
+ return renderLegalName(value);
3666
+ case "address":
3667
+ return renderAddress(value);
3668
+ case "consent":
3669
+ return renderConsent(value);
3670
+ case "signature":
3671
+ return renderSignature(value);
3672
+ default:
3673
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-pre-wrap", children: formatFallbackValue(value) });
3674
+ }
3675
+ }
3676
+ var VITALS_LABELS = {
3677
+ systolicBp: { label: "Systolic BP", unit: "mmHg", normalRange: "90-140" },
3678
+ diastolicBp: { label: "Diastolic BP", unit: "mmHg", normalRange: "60-90" },
3679
+ heartRate: { label: "Heart Rate", unit: "bpm", normalRange: "60-100" },
3680
+ temperature: { label: "Temperature", unit: "\xB0F", normalRange: "97.0-99.5" },
3681
+ respiratoryRate: { label: "Respiratory Rate", unit: "/min", normalRange: "12-20" },
3682
+ oxygenSaturation: { label: "SpO\u2082", unit: "%", normalRange: "95-100" }
3683
+ };
3684
+ function renderVitals(value) {
3685
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3686
+ const vitals = value;
3687
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-2", children: Object.entries(VITALS_LABELS).map(([key, meta]) => {
3688
+ const val = vitals[key];
3689
+ if (val == null || val === 0) return null;
3690
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px]", children: [
3691
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
3692
+ meta.label,
3693
+ ": "
3694
+ ] }),
3695
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-medium", children: [
3696
+ String(val),
3697
+ " ",
3698
+ meta.unit
3699
+ ] }),
3700
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground ml-1", children: [
3701
+ "(",
3702
+ meta.normalRange,
3703
+ ")"
3704
+ ] })
3705
+ ] }, key);
3706
+ }) });
3707
+ }
3708
+ function renderMedications(value) {
3709
+ if (!Array.isArray(value) || value.length === 0) return "No medications";
3710
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((med, idx) => {
3711
+ const m = med;
3712
+ const parts = [m.dosage, m.frequency, m.route].filter(Boolean);
3713
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3448
3714
  "div",
3449
3715
  {
3450
- style: {
3451
- marginTop: "20px",
3452
- paddingTop: "12px",
3453
- borderTop: "1px solid var(--border, #1c1c20)",
3454
- fontSize: "12px",
3455
- color: "var(--muted-foreground, #8a8a95)"
3456
- },
3716
+ className: "px-3 py-2 border border-border rounded-md text-[13px]",
3717
+ children: [
3718
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: m.name || "Unnamed" }),
3719
+ parts.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
3720
+ " \u2014 ",
3721
+ parts.join(" \xB7 ")
3722
+ ] }),
3723
+ m.notes && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mt-0.5", children: m.notes })
3724
+ ]
3725
+ },
3726
+ idx
3727
+ );
3728
+ }) });
3729
+ }
3730
+ function renderAllergies(value) {
3731
+ if (!Array.isArray(value) || value.length === 0) return "No allergies";
3732
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: value.map((allergy, idx) => {
3733
+ const a = allergy;
3734
+ const sevColor = SEVERITY_COLORS[a.severity];
3735
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3736
+ "div",
3737
+ {
3738
+ className: "px-3 py-2 border border-border rounded-md text-[13px] flex items-center gap-2 flex-wrap",
3457
3739
  children: [
3458
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3459
- "Schema: ",
3460
- response.schemaId,
3461
- " (v",
3462
- response.schemaVersion,
3740
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-semibold", children: a.allergen || "Unknown" }),
3741
+ a.type && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[11px] text-muted-foreground", children: [
3742
+ "(",
3743
+ a.type,
3463
3744
  ")"
3464
3745
  ] }),
3465
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3466
- "Session: ",
3467
- response.sessionToken
3746
+ a.severity && /* @__PURE__ */ jsxRuntime.jsx(
3747
+ "span",
3748
+ {
3749
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full",
3750
+ style: {
3751
+ backgroundColor: sevColor ?? "var(--accent)",
3752
+ color: sevColor ? "#fff" : "var(--foreground)"
3753
+ },
3754
+ children: a.severity
3755
+ }
3756
+ ),
3757
+ a.reaction && /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: [
3758
+ "\u2014 ",
3759
+ a.reaction
3468
3760
  ] })
3469
3761
  ]
3762
+ },
3763
+ idx
3764
+ );
3765
+ }) });
3766
+ }
3767
+ function renderBmi(value) {
3768
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3769
+ const data = value;
3770
+ const bmi = data.bmi;
3771
+ const unit = data.unit ?? "imperial";
3772
+ const height = data.height;
3773
+ const weight = data.weight;
3774
+ const heightUnit = unit === "metric" ? "cm" : "in";
3775
+ const weightUnit = unit === "metric" ? "kg" : "lbs";
3776
+ const category = bmi != null ? getBmiCategory(bmi) : void 0;
3777
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-[13px] flex items-center gap-2 flex-wrap", children: [
3778
+ height != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3779
+ "Height: ",
3780
+ height,
3781
+ " ",
3782
+ heightUnit
3783
+ ] }),
3784
+ height != null && weight != null && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "|" }),
3785
+ weight != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
3786
+ "Weight: ",
3787
+ weight,
3788
+ " ",
3789
+ weightUnit
3790
+ ] }),
3791
+ bmi != null && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3792
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "\u2014" }),
3793
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", children: [
3794
+ "BMI: ",
3795
+ bmi
3796
+ ] }),
3797
+ category && /* @__PURE__ */ jsxRuntime.jsx(
3798
+ "span",
3799
+ {
3800
+ className: "text-[11px] font-semibold px-2 py-0.5 rounded-full text-white",
3801
+ style: { backgroundColor: category.color },
3802
+ children: category.label
3803
+ }
3804
+ )
3805
+ ] })
3806
+ ] });
3807
+ }
3808
+ function renderBodyDiagram(value) {
3809
+ if (!Array.isArray(value) || value.length === 0) return "No regions selected";
3810
+ const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
3811
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: labels.join(", ") });
3812
+ }
3813
+ function renderPainScale(value) {
3814
+ if (typeof value !== "number") return formatFallbackValue(value);
3815
+ const face = getPainLabel(value);
3816
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-semibold", style: { color: face?.color }, children: [
3817
+ value,
3818
+ "/10",
3819
+ face ? ` \u2014 ${face.label}` : ""
3820
+ ] });
3821
+ }
3822
+ function renderInsurance(value) {
3823
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3824
+ const ins = value;
3825
+ const textFields = [
3826
+ { key: "carrierId", label: "Carrier" },
3827
+ { key: "planName", label: "Plan" },
3828
+ { key: "memberId", label: "Member ID" },
3829
+ { key: "groupNumber", label: "Group #" },
3830
+ { key: "subscriberName", label: "Subscriber" },
3831
+ { key: "relationship", label: "Relationship" }
3832
+ ];
3833
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
3834
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-3 gap-y-1 text-[13px]", children: textFields.map(({ key, label }) => {
3835
+ const val = ins[key];
3836
+ if (!val) return null;
3837
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
3838
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-muted-foreground", children: [
3839
+ label,
3840
+ ": "
3841
+ ] }),
3842
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: String(val) })
3843
+ ] }, key);
3844
+ }) }),
3845
+ !!(ins.frontImage || ins.backImage) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 mt-1", children: [
3846
+ typeof ins.frontImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
3847
+ "img",
3848
+ {
3849
+ src: ins.frontImage,
3850
+ alt: "Front of card",
3851
+ className: "h-12 rounded border border-border"
3852
+ }
3853
+ ),
3854
+ typeof ins.backImage === "string" && /* @__PURE__ */ jsxRuntime.jsx(
3855
+ "img",
3856
+ {
3857
+ src: ins.backImage,
3858
+ alt: "Back of card",
3859
+ className: "h-12 rounded border border-border"
3860
+ }
3861
+ )
3862
+ ] })
3863
+ ] });
3864
+ }
3865
+ function renderPayment(value) {
3866
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3867
+ const payment = value;
3868
+ const status = payment.status;
3869
+ const statusConfig = {
3870
+ succeeded: { bg: "#22c55e", label: "Succeeded" },
3871
+ failed: { bg: "#ef4444", label: "Failed" },
3872
+ processing: { bg: "#eab308", label: "Processing" }
3873
+ };
3874
+ const cfg = statusConfig[status];
3875
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-[13px]", children: [
3876
+ /* @__PURE__ */ jsxRuntime.jsx(
3877
+ "span",
3878
+ {
3879
+ className: "text-[11px] font-semibold px-2.5 py-0.5 rounded-full text-white",
3880
+ style: { backgroundColor: cfg?.bg ?? "var(--accent)" },
3881
+ children: cfg?.label ?? status
3470
3882
  }
3471
- )
3883
+ ),
3884
+ !!payment.chargeId && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: String(payment.chargeId) }),
3885
+ !!payment.error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: String(payment.error) })
3472
3886
  ] });
3473
3887
  }
3474
- function formatDetailValue(value) {
3888
+ function renderLegalName(value) {
3889
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3890
+ const name = value;
3891
+ const parts = [name.first, name.middle, name.last].filter(Boolean);
3892
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium", children: parts.join(" ") || "\u2014" });
3893
+ }
3894
+ function renderAddress(value) {
3895
+ if (typeof value !== "object" || value === null) return formatFallbackValue(value);
3896
+ const addr = value;
3897
+ const line1 = [addr.street, addr.street2].filter(Boolean).join(", ");
3898
+ const line2 = [addr.city, addr.state, addr.zip].filter(Boolean).join(", ");
3899
+ const full = [line1, line2].filter(Boolean).join(", ");
3900
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: full || "\u2014" });
3901
+ }
3902
+ function renderConsent(value) {
3903
+ const agreed = value === true || value === "true" || value === "agreed";
3904
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: agreed ? "font-semibold text-green-500" : "font-semibold text-muted-foreground", children: agreed ? "Agreed" : "Not agreed" });
3905
+ }
3906
+ function renderSignature(value) {
3907
+ if (typeof value !== "string") return formatFallbackValue(value);
3908
+ if (value.startsWith("data:image")) {
3909
+ return /* @__PURE__ */ jsxRuntime.jsx(
3910
+ "img",
3911
+ {
3912
+ src: value,
3913
+ alt: "Signature",
3914
+ className: "h-15 border border-border rounded"
3915
+ }
3916
+ );
3917
+ }
3918
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { children: value });
3919
+ }
3920
+ function formatFallbackValue(value) {
3475
3921
  if (value == null) return "\u2014";
3476
3922
  if (typeof value === "boolean") return value ? "Yes" : "No";
3477
- if (Array.isArray(value)) return value.map(formatDetailValue).join("\n");
3923
+ if (Array.isArray(value)) return value.map(formatFallbackValue).join(", ");
3478
3924
  if (typeof value === "object") return JSON.stringify(value, null, 2);
3479
3925
  return String(value);
3480
3926
  }
3481
- var viewButtonStyle = (active) => ({
3482
- padding: "4px 10px",
3483
- fontSize: "12px",
3484
- fontWeight: active ? 600 : 400,
3485
- color: active ? "var(--primary, oklch(0.82 0.14 210))" : "var(--muted-foreground, #8a8a95)",
3486
- backgroundColor: active ? "var(--accent, #17171a)" : "transparent",
3487
- border: "1px solid",
3488
- borderColor: active ? "var(--ring, oklch(0.82 0.14 210))" : "var(--border, #1c1c20)",
3489
- borderRadius: "6px",
3490
- cursor: "pointer",
3491
- fontFamily: "inherit"
3492
- });
3927
+
3928
+ // src/response-viewer/export-utils.ts
3929
+ function exportToCsv(schema, responses, filename = "responses.csv") {
3930
+ const questions = getExportableQuestions(schema);
3931
+ const headers = ["Submitted", ...questions.map((q) => q.label), "Score"];
3932
+ const rows = responses.map((r) => {
3933
+ const submitted = new Date(r.submittedAt).toLocaleString();
3934
+ const values = questions.map((q) => formatExportValue(r.values[q.id], q.type));
3935
+ const score = r.totalScore != null ? String(r.totalScore) : "";
3936
+ return [submitted, ...values, score];
3937
+ });
3938
+ const csvContent = [headers, ...rows].map((row) => row.map(escapeCsvField).join(",")).join("\n");
3939
+ downloadBlob(csvContent, filename, "text/csv;charset=utf-8;");
3940
+ }
3941
+ function exportToJson(responses, filename = "responses.json") {
3942
+ const content = JSON.stringify(responses, null, 2);
3943
+ downloadBlob(content, filename, "application/json;charset=utf-8;");
3944
+ }
3945
+ function getExportableQuestions(schema) {
3946
+ const questions = [];
3947
+ for (const section of schema.sections) {
3948
+ for (const q of section.questions) {
3949
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
3950
+ continue;
3951
+ }
3952
+ questions.push(q);
3953
+ }
3954
+ }
3955
+ return questions;
3956
+ }
3957
+ function formatExportValue(value, type) {
3958
+ if (value == null) return "";
3959
+ switch (type) {
3960
+ case "vitals_entry": {
3961
+ if (typeof value !== "object" || value === null) break;
3962
+ const v = value;
3963
+ const parts = [];
3964
+ if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
3965
+ if (v.heartRate) parts.push(`HR ${v.heartRate}`);
3966
+ if (v.temperature) parts.push(`${v.temperature}\xB0F`);
3967
+ if (v.oxygenSaturation) parts.push(`SpO2 ${v.oxygenSaturation}%`);
3968
+ return parts.join("; ");
3969
+ }
3970
+ case "medication_list":
3971
+ if (Array.isArray(value)) {
3972
+ return value.map((m) => [m.name, m.dosage, m.frequency].filter(Boolean).join(" ")).join("; ");
3973
+ }
3974
+ break;
3975
+ case "allergy_list":
3976
+ if (Array.isArray(value)) {
3977
+ return value.map((a) => [a.allergen, a.severity].filter(Boolean).join(" - ")).join("; ");
3978
+ }
3979
+ break;
3980
+ case "body_diagram":
3981
+ if (Array.isArray(value)) {
3982
+ return value.map((id) => BODY_REGION_LABELS[id] ?? id).join("; ");
3983
+ }
3984
+ break;
3985
+ case "pain_scale":
3986
+ return typeof value === "number" ? `${value}/10` : String(value);
3987
+ case "bmi_calculator": {
3988
+ if (typeof value !== "object" || value === null) break;
3989
+ const d = value;
3990
+ return d.bmi != null ? `BMI ${d.bmi}` : "";
3991
+ }
3992
+ case "payment": {
3993
+ if (typeof value !== "object" || value === null) break;
3994
+ return value.status ?? "";
3995
+ }
3996
+ case "legal_name": {
3997
+ if (typeof value !== "object" || value === null) break;
3998
+ const n = value;
3999
+ return [n.first, n.middle, n.last].filter(Boolean).join(" ");
4000
+ }
4001
+ case "address": {
4002
+ if (typeof value !== "object" || value === null) break;
4003
+ const a = value;
4004
+ return [a.street, a.city, a.state, a.zip].filter(Boolean).join(", ");
4005
+ }
4006
+ case "consent":
4007
+ return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
4008
+ case "signature":
4009
+ return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "";
4010
+ }
4011
+ if (typeof value === "boolean") return value ? "Yes" : "No";
4012
+ if (Array.isArray(value)) return value.join("; ");
4013
+ if (typeof value === "object") return JSON.stringify(value);
4014
+ return String(value);
4015
+ }
4016
+ function escapeCsvField(field) {
4017
+ if (field.includes(",") || field.includes('"') || field.includes("\n")) {
4018
+ return `"${field.replace(/"/g, '""')}"`;
4019
+ }
4020
+ return field;
4021
+ }
4022
+ function downloadBlob(content, filename, mimeType) {
4023
+ const blob = new Blob([content], { type: mimeType });
4024
+ const url = URL.createObjectURL(blob);
4025
+ const link = document.createElement("a");
4026
+ link.href = url;
4027
+ link.download = filename;
4028
+ document.body.appendChild(link);
4029
+ link.click();
4030
+ document.body.removeChild(link);
4031
+ URL.revokeObjectURL(url);
4032
+ }
3493
4033
  function ResponseViewerInner({
3494
4034
  schema,
3495
4035
  responses,
@@ -3515,62 +4055,73 @@ function ResponseViewerInner({
3515
4055
  value: response.values[q.id]
3516
4056
  }));
3517
4057
  }
4058
+ const heightValue = typeof height === "number" ? `${height}px` : height;
4059
+ const widthValue = typeof width === "number" ? `${width}px` : width;
3518
4060
  return /* @__PURE__ */ jsxRuntime.jsxs(
3519
4061
  "div",
3520
4062
  {
3521
- style: {
3522
- display: "flex",
3523
- flexDirection: "column",
3524
- height: typeof height === "number" ? `${height}px` : height,
3525
- width: typeof width === "number" ? `${width}px` : width,
3526
- border: "1px solid var(--border, #1c1c20)",
3527
- borderRadius: "8px",
3528
- overflow: "hidden",
3529
- fontFamily: "inherit",
3530
- backgroundColor: "var(--background, #0a0a0b)",
3531
- color: "var(--foreground, #e8e8ea)"
3532
- },
4063
+ className: "flex flex-col border border-border rounded-lg overflow-hidden bg-background text-foreground",
4064
+ style: { height: heightValue, width: widthValue },
3533
4065
  children: [
3534
- !selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs(
3535
- "div",
3536
- {
3537
- style: {
3538
- display: "flex",
3539
- justifyContent: "space-between",
3540
- alignItems: "center",
3541
- padding: "8px 12px",
3542
- borderBottom: "1px solid var(--border, #1c1c20)"
3543
- },
3544
- children: [
3545
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "13px", color: "var(--muted-foreground, #8a8a95)" }, children: [
3546
- responses.length,
3547
- " response",
3548
- responses.length !== 1 ? "s" : ""
3549
- ] }),
3550
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
3551
- /* @__PURE__ */ jsxRuntime.jsx(
3552
- "button",
3553
- {
3554
- type: "button",
3555
- style: viewButtonStyle(viewMode === "table"),
3556
- onClick: () => setViewMode("table"),
3557
- children: "Table"
3558
- }
4066
+ !selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex justify-between items-center px-3 py-2 border-b border-border", children: [
4067
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground", children: [
4068
+ responses.length,
4069
+ " response",
4070
+ responses.length !== 1 ? "s" : ""
4071
+ ] }),
4072
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
4073
+ /* @__PURE__ */ jsxRuntime.jsx(
4074
+ fieldcraftReact.Button,
4075
+ {
4076
+ variant: viewMode === "table" ? "secondary" : "ghost",
4077
+ size: "sm",
4078
+ className: cn(
4079
+ "h-7 text-xs",
4080
+ viewMode === "table" && "font-semibold border border-ring"
3559
4081
  ),
3560
- /* @__PURE__ */ jsxRuntime.jsx(
3561
- "button",
3562
- {
3563
- type: "button",
3564
- style: viewButtonStyle(viewMode === "card"),
3565
- onClick: () => setViewMode("card"),
3566
- children: "Cards"
3567
- }
3568
- )
3569
- ] })
3570
- ]
3571
- }
3572
- ),
3573
- /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "auto", padding: selectedResponse ? "16px" : void 0 }, children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
4082
+ onClick: () => setViewMode("table"),
4083
+ children: "Table"
4084
+ }
4085
+ ),
4086
+ /* @__PURE__ */ jsxRuntime.jsx(
4087
+ fieldcraftReact.Button,
4088
+ {
4089
+ variant: viewMode === "card" ? "secondary" : "ghost",
4090
+ size: "sm",
4091
+ className: cn(
4092
+ "h-7 text-xs",
4093
+ viewMode === "card" && "font-semibold border border-ring"
4094
+ ),
4095
+ onClick: () => setViewMode("card"),
4096
+ children: "Cards"
4097
+ }
4098
+ ),
4099
+ /* @__PURE__ */ jsxRuntime.jsx(fieldcraftReact.Separator, { orientation: "vertical", className: "h-5 mx-1" }),
4100
+ /* @__PURE__ */ jsxRuntime.jsx(
4101
+ fieldcraftReact.Button,
4102
+ {
4103
+ variant: "outline",
4104
+ size: "sm",
4105
+ className: "h-7 text-xs",
4106
+ onClick: () => exportToCsv(schema, responses),
4107
+ disabled: responses.length === 0,
4108
+ children: "Export CSV"
4109
+ }
4110
+ ),
4111
+ /* @__PURE__ */ jsxRuntime.jsx(
4112
+ fieldcraftReact.Button,
4113
+ {
4114
+ variant: "outline",
4115
+ size: "sm",
4116
+ className: "h-7 text-xs",
4117
+ onClick: () => exportToJson(responses),
4118
+ disabled: responses.length === 0,
4119
+ children: "Export JSON"
4120
+ }
4121
+ )
4122
+ ] })
4123
+ ] }),
4124
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex-1 overflow-auto", selectedResponse && "p-4"), children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
3574
4125
  ResponseDetail,
3575
4126
  {
3576
4127
  response: selectedResponse,
@@ -3584,29 +4135,18 @@ function ResponseViewerInner({
3584
4135
  responses,
3585
4136
  onRowClick: handleSelect
3586
4137
  }
3587
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
3588
- "div",
3589
- {
3590
- style: {
3591
- display: "grid",
3592
- gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
3593
- gap: "12px",
3594
- padding: "12px"
4138
+ ) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-3 p-3 grid-cols-[repeat(auto-fill,minmax(280px,1fr))]", children: [
4139
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
4140
+ ResponseCard,
4141
+ {
4142
+ response,
4143
+ fields: getFields(response),
4144
+ onClick: () => handleSelect(response)
3595
4145
  },
3596
- children: [
3597
- responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
3598
- ResponseCard,
3599
- {
3600
- response,
3601
- fields: getFields(response),
3602
- onClick: () => handleSelect(response)
3603
- },
3604
- response.sessionToken || idx
3605
- )),
3606
- responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "32px", textAlign: "center", color: "var(--muted-foreground, #8a8a95)" }, children: "No responses yet" })
3607
- ]
3608
- }
3609
- ) })
4146
+ response.sessionToken || idx
4147
+ )),
4148
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 text-center text-muted-foreground", children: "No responses yet" })
4149
+ ] }) })
3610
4150
  ]
3611
4151
  }
3612
4152
  );
@@ -4031,7 +4571,7 @@ var ThemeEditor = fieldcraftProLicense.requireLicense(ThemeEditorInner, "ThemeEd
4031
4571
  // src/index.ts
4032
4572
  if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
4033
4573
  const _fc_banner = `
4034
- %c FieldCraft Pro %c v0.0.0
4574
+ %c FieldCraft Pro %c v1.0.1
4035
4575
 
4036
4576
  %cForm Builder \xB7 Response Viewer \xB7 Theme Editor
4037
4577