@squaredr/fieldcraft-pro 1.6.4 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +51 -51
- package/README.md +139 -139
- package/dist/{chunk-VECQKSWS.mjs → chunk-4MMKB2EW.mjs} +60 -86
- package/dist/{chunk-CFVT2R42.mjs → chunk-CYXJGOQH.mjs} +904 -206
- package/dist/{chunk-ANBMT5AW.mjs → chunk-GXKQCXIB.mjs} +470 -228
- package/dist/chunk-IW654Z3M.mjs +1108 -0
- package/dist/{chunk-5LKGCZAW.mjs → chunk-MLP5EDWP.mjs} +167 -178
- package/dist/form-builder/index.d.mts +176 -6
- package/dist/form-builder/index.d.ts +176 -6
- package/dist/form-builder/index.js +604 -365
- package/dist/form-builder/index.mjs +2 -2
- package/dist/index.d.mts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +3221 -984
- package/dist/index.mjs +332 -125
- package/dist/response-viewer/index.d.mts +1 -1
- package/dist/response-viewer/index.d.ts +1 -1
- package/dist/response-viewer/index.js +169 -204
- package/dist/response-viewer/index.mjs +2 -2
- package/dist/styles.css +1 -1
- package/dist/templates/index.d.mts +43 -0
- package/dist/templates/index.d.ts +43 -0
- package/dist/templates/index.js +1116 -0
- package/dist/templates/index.mjs +1 -0
- package/dist/theme-editor/index.d.mts +11 -5
- package/dist/theme-editor/index.d.ts +11 -5
- package/dist/theme-editor/index.js +907 -232
- package/dist/theme-editor/index.mjs +2 -2
- package/dist/types-bFHsZT1n.d.mts +217 -0
- package/dist/types-bFHsZT1n.d.ts +217 -0
- package/package.json +23 -11
- package/theme-editor/styles.css +468 -466
- package/dist/index-D19524df.d.mts +0 -387
- package/dist/index-D19524df.d.ts +0 -387
|
@@ -1,9 +1,125 @@
|
|
|
1
1
|
import { cn } from './chunk-QQ4JZGTD.mjs';
|
|
2
|
-
import { requireLicense } from './chunk-
|
|
2
|
+
import { requireLicense } from './chunk-4MMKB2EW.mjs';
|
|
3
3
|
import { useState, useEffect, useMemo } from 'react';
|
|
4
4
|
import { Input, Button, Separator, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@squaredr/fieldcraft-react';
|
|
5
5
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
|
+
function formatDuration(ms) {
|
|
8
|
+
if (ms == null) return "\u2014";
|
|
9
|
+
const totalSeconds = Math.round(ms / 1e3);
|
|
10
|
+
if (totalSeconds < 60) return `${totalSeconds}s`;
|
|
11
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
12
|
+
const seconds = totalSeconds % 60;
|
|
13
|
+
return `${minutes}m ${seconds}s`;
|
|
14
|
+
}
|
|
15
|
+
function countAnswered(values) {
|
|
16
|
+
let count = 0;
|
|
17
|
+
for (const v of Object.values(values)) {
|
|
18
|
+
if (v !== void 0 && v !== null && v !== "") count++;
|
|
19
|
+
}
|
|
20
|
+
return count;
|
|
21
|
+
}
|
|
22
|
+
function getTotalFieldCount(schema) {
|
|
23
|
+
let count = 0;
|
|
24
|
+
for (const section of schema.sections) {
|
|
25
|
+
for (const q of section.questions) {
|
|
26
|
+
if (!DISPLAY_ONLY_TYPES.has(q.type)) count++;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return count;
|
|
30
|
+
}
|
|
31
|
+
function ResponseTable({
|
|
32
|
+
schema,
|
|
33
|
+
responses,
|
|
34
|
+
onRowClick,
|
|
35
|
+
selectable,
|
|
36
|
+
selectedIds,
|
|
37
|
+
onToggleSelect,
|
|
38
|
+
onSelectAll
|
|
39
|
+
}) {
|
|
40
|
+
const totalFields = getTotalFieldCount(schema);
|
|
41
|
+
const allPageSelected = selectable && responses.length > 0 && responses.every(
|
|
42
|
+
(r) => r.sessionToken && selectedIds?.has(r.sessionToken)
|
|
43
|
+
);
|
|
44
|
+
const colCount = 4 + (selectable ? 1 : 0);
|
|
45
|
+
return /* @__PURE__ */ jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
|
|
46
|
+
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted", children: [
|
|
47
|
+
selectable && /* @__PURE__ */ jsx("th", { className: "px-3 py-2 w-8 border-b-2 border-border", children: /* @__PURE__ */ jsx(
|
|
48
|
+
"input",
|
|
49
|
+
{
|
|
50
|
+
type: "checkbox",
|
|
51
|
+
checked: allPageSelected,
|
|
52
|
+
onChange: () => onSelectAll?.(),
|
|
53
|
+
className: "accent-primary"
|
|
54
|
+
}
|
|
55
|
+
) }),
|
|
56
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
|
|
57
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Completion Time" }),
|
|
58
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Fields Answered" }),
|
|
59
|
+
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
|
|
60
|
+
] }) }),
|
|
61
|
+
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
62
|
+
responses.map((response, idx) => {
|
|
63
|
+
const answered = countAnswered(response.values);
|
|
64
|
+
return /* @__PURE__ */ jsxs(
|
|
65
|
+
"tr",
|
|
66
|
+
{
|
|
67
|
+
onClick: () => onRowClick?.(response),
|
|
68
|
+
className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
|
|
69
|
+
children: [
|
|
70
|
+
selectable && /* @__PURE__ */ jsx("td", { className: "px-3 py-2 w-8", children: /* @__PURE__ */ jsx(
|
|
71
|
+
"input",
|
|
72
|
+
{
|
|
73
|
+
type: "checkbox",
|
|
74
|
+
checked: !!(response.sessionToken && selectedIds?.has(response.sessionToken)),
|
|
75
|
+
onChange: (e) => {
|
|
76
|
+
e.stopPropagation();
|
|
77
|
+
if (response.sessionToken) onToggleSelect?.(response.sessionToken);
|
|
78
|
+
},
|
|
79
|
+
onClick: (e) => e.stopPropagation(),
|
|
80
|
+
className: "accent-primary"
|
|
81
|
+
}
|
|
82
|
+
) }),
|
|
83
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: new Date(response.submittedAt).toLocaleString() }),
|
|
84
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: formatDuration(response.completionTimeMs) }),
|
|
85
|
+
/* @__PURE__ */ jsxs("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: [
|
|
86
|
+
answered,
|
|
87
|
+
"/",
|
|
88
|
+
totalFields
|
|
89
|
+
] }),
|
|
90
|
+
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-foreground whitespace-nowrap", children: response.totalScore ?? "\u2014" })
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
response.sessionToken || idx
|
|
94
|
+
);
|
|
95
|
+
}),
|
|
96
|
+
responses.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
97
|
+
"td",
|
|
98
|
+
{
|
|
99
|
+
colSpan: colCount,
|
|
100
|
+
className: "px-3 py-8 text-center text-muted-foreground",
|
|
101
|
+
children: "No responses yet"
|
|
102
|
+
}
|
|
103
|
+
) })
|
|
104
|
+
] })
|
|
105
|
+
] }) });
|
|
106
|
+
}
|
|
107
|
+
var DISPLAY_ONLY_TYPES = /* @__PURE__ */ new Set([
|
|
108
|
+
"info-block",
|
|
109
|
+
"info_block",
|
|
110
|
+
"section-header",
|
|
111
|
+
"page-break",
|
|
112
|
+
"image",
|
|
113
|
+
"divider",
|
|
114
|
+
"spacer",
|
|
115
|
+
"video",
|
|
116
|
+
"rich-text",
|
|
117
|
+
"welcome-screen",
|
|
118
|
+
"thank-you-screen",
|
|
119
|
+
"hidden",
|
|
120
|
+
"calculated"
|
|
121
|
+
]);
|
|
122
|
+
|
|
7
123
|
// src/response-viewer/clinical-display-data.ts
|
|
8
124
|
var BODY_REGION_LABELS = {
|
|
9
125
|
head: "Head",
|
|
@@ -140,166 +256,6 @@ function getScoreSeverity(instrumentKey, score) {
|
|
|
140
256
|
if (!thresholds) return void 0;
|
|
141
257
|
return thresholds.find((t) => score >= t.min && score <= t.max);
|
|
142
258
|
}
|
|
143
|
-
function ResponseTable({
|
|
144
|
-
schema,
|
|
145
|
-
responses,
|
|
146
|
-
onRowClick,
|
|
147
|
-
selectable,
|
|
148
|
-
selectedIds,
|
|
149
|
-
onToggleSelect,
|
|
150
|
-
onSelectAll
|
|
151
|
-
}) {
|
|
152
|
-
const questions = getAllQuestions(schema);
|
|
153
|
-
const allPageSelected = selectable && responses.length > 0 && responses.every(
|
|
154
|
-
(r) => r.sessionToken && selectedIds?.has(r.sessionToken)
|
|
155
|
-
);
|
|
156
|
-
return /* @__PURE__ */ jsx("div", { className: "overflow-auto", children: /* @__PURE__ */ jsxs("table", { className: "w-full border-collapse text-[13px]", children: [
|
|
157
|
-
/* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { className: "bg-muted", children: [
|
|
158
|
-
selectable && /* @__PURE__ */ jsx("th", { className: "px-3 py-2 w-8 border-b-2 border-border", children: /* @__PURE__ */ jsx(
|
|
159
|
-
"input",
|
|
160
|
-
{
|
|
161
|
-
type: "checkbox",
|
|
162
|
-
checked: allPageSelected,
|
|
163
|
-
onChange: () => onSelectAll?.(),
|
|
164
|
-
className: "accent-primary"
|
|
165
|
-
}
|
|
166
|
-
) }),
|
|
167
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Submitted" }),
|
|
168
|
-
questions.map((q) => /* @__PURE__ */ jsx(
|
|
169
|
-
"th",
|
|
170
|
-
{
|
|
171
|
-
className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap",
|
|
172
|
-
children: q.label
|
|
173
|
-
},
|
|
174
|
-
q.id
|
|
175
|
-
)),
|
|
176
|
-
/* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-left font-semibold text-foreground border-b-2 border-border whitespace-nowrap", children: "Score" })
|
|
177
|
-
] }) }),
|
|
178
|
-
/* @__PURE__ */ jsxs("tbody", { children: [
|
|
179
|
-
responses.map((response, idx) => /* @__PURE__ */ jsxs(
|
|
180
|
-
"tr",
|
|
181
|
-
{
|
|
182
|
-
onClick: () => onRowClick?.(response),
|
|
183
|
-
className: onRowClick ? "cursor-pointer border-b border-border hover:bg-accent transition-colors" : "border-b border-border",
|
|
184
|
-
children: [
|
|
185
|
-
selectable && /* @__PURE__ */ jsx("td", { className: "px-3 py-2 w-8", children: /* @__PURE__ */ jsx(
|
|
186
|
-
"input",
|
|
187
|
-
{
|
|
188
|
-
type: "checkbox",
|
|
189
|
-
checked: !!(response.sessionToken && selectedIds?.has(response.sessionToken)),
|
|
190
|
-
onChange: (e) => {
|
|
191
|
-
e.stopPropagation();
|
|
192
|
-
if (response.sessionToken) onToggleSelect?.(response.sessionToken);
|
|
193
|
-
},
|
|
194
|
-
onClick: (e) => e.stopPropagation(),
|
|
195
|
-
className: "accent-primary"
|
|
196
|
-
}
|
|
197
|
-
) }),
|
|
198
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: new Date(response.submittedAt).toLocaleString() }),
|
|
199
|
-
questions.map((q) => /* @__PURE__ */ jsx(
|
|
200
|
-
"td",
|
|
201
|
-
{
|
|
202
|
-
className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap",
|
|
203
|
-
children: formatCellValue(response.values[q.id], q.type)
|
|
204
|
-
},
|
|
205
|
-
q.id
|
|
206
|
-
)),
|
|
207
|
-
/* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-foreground max-w-50 overflow-hidden text-ellipsis whitespace-nowrap", children: response.totalScore ?? "\u2014" })
|
|
208
|
-
]
|
|
209
|
-
},
|
|
210
|
-
response.sessionToken || idx
|
|
211
|
-
)),
|
|
212
|
-
responses.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
|
|
213
|
-
"td",
|
|
214
|
-
{
|
|
215
|
-
colSpan: questions.length + 2 + (selectable ? 1 : 0),
|
|
216
|
-
className: "px-3 py-8 text-center text-muted-foreground",
|
|
217
|
-
children: "No responses yet"
|
|
218
|
-
}
|
|
219
|
-
) })
|
|
220
|
-
] })
|
|
221
|
-
] }) });
|
|
222
|
-
}
|
|
223
|
-
function getAllQuestions(schema) {
|
|
224
|
-
const questions = [];
|
|
225
|
-
for (const section of schema.sections) {
|
|
226
|
-
for (const q of section.questions) {
|
|
227
|
-
if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
|
|
228
|
-
continue;
|
|
229
|
-
}
|
|
230
|
-
questions.push(q);
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return questions;
|
|
234
|
-
}
|
|
235
|
-
function formatCellValue(value, type) {
|
|
236
|
-
if (value == null) return "\u2014";
|
|
237
|
-
if (type) {
|
|
238
|
-
switch (type) {
|
|
239
|
-
case "vitals_entry": {
|
|
240
|
-
if (typeof value !== "object" || value === null) break;
|
|
241
|
-
const v = value;
|
|
242
|
-
const parts = [];
|
|
243
|
-
if (v.systolicBp && v.diastolicBp) parts.push(`BP ${v.systolicBp}/${v.diastolicBp}`);
|
|
244
|
-
if (v.heartRate) parts.push(`HR ${v.heartRate}`);
|
|
245
|
-
if (v.temperature) parts.push(`${v.temperature}\xB0F`);
|
|
246
|
-
if (v.oxygenSaturation) parts.push(`SpO\u2082 ${v.oxygenSaturation}%`);
|
|
247
|
-
return parts.length > 0 ? parts.join(", ") : "\u2014";
|
|
248
|
-
}
|
|
249
|
-
case "medication_list":
|
|
250
|
-
if (Array.isArray(value)) return `${value.length} medication${value.length !== 1 ? "s" : ""}`;
|
|
251
|
-
break;
|
|
252
|
-
case "allergy_list":
|
|
253
|
-
if (Array.isArray(value)) return `${value.length} allerg${value.length !== 1 ? "ies" : "y"}`;
|
|
254
|
-
break;
|
|
255
|
-
case "body_diagram":
|
|
256
|
-
if (Array.isArray(value)) {
|
|
257
|
-
const labels = value.map((id) => BODY_REGION_LABELS[id] ?? id);
|
|
258
|
-
return labels.join(", ");
|
|
259
|
-
}
|
|
260
|
-
break;
|
|
261
|
-
case "pain_scale":
|
|
262
|
-
if (typeof value === "number") return `${value}/10`;
|
|
263
|
-
break;
|
|
264
|
-
case "bmi_calculator": {
|
|
265
|
-
if (typeof value !== "object" || value === null) break;
|
|
266
|
-
const d = value;
|
|
267
|
-
if (d.bmi != null) return `BMI ${d.bmi}`;
|
|
268
|
-
break;
|
|
269
|
-
}
|
|
270
|
-
case "payment": {
|
|
271
|
-
if (typeof value !== "object" || value === null) break;
|
|
272
|
-
const p = value;
|
|
273
|
-
const status = p.status;
|
|
274
|
-
return status ? status.charAt(0).toUpperCase() + status.slice(1) : "\u2014";
|
|
275
|
-
}
|
|
276
|
-
case "insurance_card": {
|
|
277
|
-
if (typeof value !== "object" || value === null) break;
|
|
278
|
-
const ins = value;
|
|
279
|
-
const parts = [ins.carrierId, ins.planName].filter(Boolean);
|
|
280
|
-
return parts.length > 0 ? parts.join(" \u2014 ") : "Card uploaded";
|
|
281
|
-
}
|
|
282
|
-
case "legal_name": {
|
|
283
|
-
if (typeof value !== "object" || value === null) break;
|
|
284
|
-
const n = value;
|
|
285
|
-
return [n.first, n.last].filter(Boolean).join(" ") || "\u2014";
|
|
286
|
-
}
|
|
287
|
-
case "address": {
|
|
288
|
-
if (typeof value !== "object" || value === null) break;
|
|
289
|
-
const a = value;
|
|
290
|
-
return [a.city, a.state].filter(Boolean).join(", ") || "\u2014";
|
|
291
|
-
}
|
|
292
|
-
case "consent":
|
|
293
|
-
return value === true || value === "true" || value === "agreed" ? "Agreed" : "Not agreed";
|
|
294
|
-
case "signature":
|
|
295
|
-
return typeof value === "string" && value.startsWith("data:image") ? "Signed" : "\u2014";
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
if (typeof value === "boolean") return value ? "Yes" : "No";
|
|
299
|
-
if (Array.isArray(value)) return value.join(", ");
|
|
300
|
-
if (typeof value === "object") return JSON.stringify(value);
|
|
301
|
-
return String(value);
|
|
302
|
-
}
|
|
303
259
|
function ResponseCard({
|
|
304
260
|
response,
|
|
305
261
|
fields,
|
|
@@ -1297,13 +1253,26 @@ function exportToJson(responses, filename = "responses.json") {
|
|
|
1297
1253
|
const content = JSON.stringify(responses, null, 2);
|
|
1298
1254
|
downloadBlob(content, filename, "application/json;charset=utf-8;");
|
|
1299
1255
|
}
|
|
1256
|
+
var DISPLAY_ONLY_TYPES2 = /* @__PURE__ */ new Set([
|
|
1257
|
+
"info-block",
|
|
1258
|
+
"info_block",
|
|
1259
|
+
"section-header",
|
|
1260
|
+
"page-break",
|
|
1261
|
+
"image",
|
|
1262
|
+
"divider",
|
|
1263
|
+
"spacer",
|
|
1264
|
+
"video",
|
|
1265
|
+
"rich-text",
|
|
1266
|
+
"welcome-screen",
|
|
1267
|
+
"thank-you-screen",
|
|
1268
|
+
"hidden",
|
|
1269
|
+
"calculated"
|
|
1270
|
+
]);
|
|
1300
1271
|
function getExportableQuestions(schema) {
|
|
1301
1272
|
const questions = [];
|
|
1302
1273
|
for (const section of schema.sections) {
|
|
1303
1274
|
for (const q of section.questions) {
|
|
1304
|
-
if (
|
|
1305
|
-
continue;
|
|
1306
|
-
}
|
|
1275
|
+
if (DISPLAY_ONLY_TYPES2.has(q.type)) continue;
|
|
1307
1276
|
questions.push(q);
|
|
1308
1277
|
}
|
|
1309
1278
|
}
|
|
@@ -1369,6 +1338,10 @@ function formatExportValue(value, type) {
|
|
|
1369
1338
|
return String(value);
|
|
1370
1339
|
}
|
|
1371
1340
|
function escapeCsvField(field) {
|
|
1341
|
+
const first = field.charAt(0);
|
|
1342
|
+
if (first === "=" || first === "+" || first === "-" || first === "@" || first === " " || first === "\r") {
|
|
1343
|
+
field = `'${field}`;
|
|
1344
|
+
}
|
|
1372
1345
|
if (field.includes(",") || field.includes('"') || field.includes("\n")) {
|
|
1373
1346
|
return `"${field.replace(/"/g, '""')}"`;
|
|
1374
1347
|
}
|
|
@@ -1383,7 +1356,7 @@ function downloadBlob(content, filename, mimeType) {
|
|
|
1383
1356
|
document.body.appendChild(link);
|
|
1384
1357
|
link.click();
|
|
1385
1358
|
document.body.removeChild(link);
|
|
1386
|
-
URL.revokeObjectURL(url);
|
|
1359
|
+
setTimeout(() => URL.revokeObjectURL(url), 1e4);
|
|
1387
1360
|
}
|
|
1388
1361
|
|
|
1389
1362
|
// src/response-viewer/pagination-utils.ts
|
|
@@ -1616,9 +1589,12 @@ function ResponseViewerInner({
|
|
|
1616
1589
|
[responses, searchQuery, schema]
|
|
1617
1590
|
);
|
|
1618
1591
|
const isFiltered = hasActiveFilters(filterState);
|
|
1619
|
-
const filteredResponses =
|
|
1592
|
+
const filteredResponses = useMemo(
|
|
1593
|
+
() => applyFilters(searchedResponses, filterState),
|
|
1594
|
+
[searchedResponses, filterState]
|
|
1595
|
+
);
|
|
1620
1596
|
const pag = paginate(filteredResponses, currentPage, effectivePageSize);
|
|
1621
|
-
const questions =
|
|
1597
|
+
const questions = getAllQuestions(schema);
|
|
1622
1598
|
const isSelectable = selectable && (!!onBulkDelete || !!onBulkExport);
|
|
1623
1599
|
function handleSelect(response) {
|
|
1624
1600
|
setSelectedResponse(response);
|
|
@@ -1720,7 +1696,7 @@ function ResponseViewerInner({
|
|
|
1720
1696
|
});
|
|
1721
1697
|
}
|
|
1722
1698
|
function getFields(response) {
|
|
1723
|
-
return questions.map((q) => ({
|
|
1699
|
+
return questions.filter((q) => response.values[q.id] !== void 0).map((q) => ({
|
|
1724
1700
|
questionId: q.id,
|
|
1725
1701
|
label: q.label,
|
|
1726
1702
|
type: q.type,
|
|
@@ -1873,10 +1849,10 @@ function ResponseViewerInner({
|
|
|
1873
1849
|
className: "h-7 text-xs",
|
|
1874
1850
|
onClick: () => {
|
|
1875
1851
|
const csvFilename = filename ? filename.replace(/\.\w+$/, ".csv") : "responses.csv";
|
|
1876
|
-
exportToCsv(schema,
|
|
1877
|
-
onExport?.("csv",
|
|
1852
|
+
exportToCsv(schema, filteredResponses, csvFilename, { dateFormat, columnLabels });
|
|
1853
|
+
onExport?.("csv", filteredResponses.length);
|
|
1878
1854
|
},
|
|
1879
|
-
disabled:
|
|
1855
|
+
disabled: filteredResponses.length === 0,
|
|
1880
1856
|
children: "Export CSV"
|
|
1881
1857
|
}
|
|
1882
1858
|
),
|
|
@@ -1888,10 +1864,10 @@ function ResponseViewerInner({
|
|
|
1888
1864
|
className: "h-7 text-xs",
|
|
1889
1865
|
onClick: () => {
|
|
1890
1866
|
const jsonFilename = filename ? filename.replace(/\.\w+$/, ".json") : "responses.json";
|
|
1891
|
-
exportToJson(
|
|
1892
|
-
onExport?.("json",
|
|
1867
|
+
exportToJson(filteredResponses, jsonFilename);
|
|
1868
|
+
onExport?.("json", filteredResponses.length);
|
|
1893
1869
|
},
|
|
1894
|
-
disabled:
|
|
1870
|
+
disabled: filteredResponses.length === 0,
|
|
1895
1871
|
children: "Export JSON"
|
|
1896
1872
|
}
|
|
1897
1873
|
)
|
|
@@ -2172,13 +2148,26 @@ function ResponseViewerInner({
|
|
|
2172
2148
|
}
|
|
2173
2149
|
);
|
|
2174
2150
|
}
|
|
2175
|
-
|
|
2151
|
+
var DISPLAY_ONLY_TYPES3 = /* @__PURE__ */ new Set([
|
|
2152
|
+
"info-block",
|
|
2153
|
+
"info_block",
|
|
2154
|
+
"section-header",
|
|
2155
|
+
"page-break",
|
|
2156
|
+
"image",
|
|
2157
|
+
"divider",
|
|
2158
|
+
"spacer",
|
|
2159
|
+
"video",
|
|
2160
|
+
"rich-text",
|
|
2161
|
+
"welcome-screen",
|
|
2162
|
+
"thank-you-screen",
|
|
2163
|
+
"hidden",
|
|
2164
|
+
"calculated"
|
|
2165
|
+
]);
|
|
2166
|
+
function getAllQuestions(schema) {
|
|
2176
2167
|
const questions = [];
|
|
2177
2168
|
for (const section of schema.sections) {
|
|
2178
2169
|
for (const q of section.questions) {
|
|
2179
|
-
if (
|
|
2180
|
-
continue;
|
|
2181
|
-
}
|
|
2170
|
+
if (DISPLAY_ONLY_TYPES3.has(q.type)) continue;
|
|
2182
2171
|
questions.push(q);
|
|
2183
2172
|
}
|
|
2184
2173
|
}
|
|
@@ -1,7 +1,177 @@
|
|
|
1
|
-
|
|
2
|
-
import 'react';
|
|
3
|
-
import '
|
|
1
|
+
import * as react from 'react';
|
|
2
|
+
import { ReactNode } from 'react';
|
|
3
|
+
import { b as FormBuilderProps, d as FormBuilderTheme, f as QuestionTypeInfo, S as SelectedItem, D as DragItem } from '../types-bFHsZT1n.mjs';
|
|
4
|
+
export { B as BuilderState, a as DropTarget, F as FormBuilderPreviewProps, M as MutationAction, P as PaletteCategory, e as PropertyPanelTab, Q as QuestionTypeCategory } from '../types-bFHsZT1n.mjs';
|
|
5
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
|
+
import { FormEngineSchema, Option, Question, Section } from '@squaredr/fieldcraft-core';
|
|
7
|
+
import { ClassValue } from 'clsx';
|
|
8
|
+
import * as _dnd_kit_core from '@dnd-kit/core';
|
|
9
|
+
import { DragStartEvent, DragEndEvent } from '@dnd-kit/core';
|
|
4
10
|
import '@squaredr/fieldcraft-react';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
11
|
+
|
|
12
|
+
declare const FormBuilder: react.ComponentType<FormBuilderProps>;
|
|
13
|
+
|
|
14
|
+
declare function useBuilderTheme(): FormBuilderTheme;
|
|
15
|
+
type FormBuilderThemeProviderProps = {
|
|
16
|
+
theme?: FormBuilderTheme;
|
|
17
|
+
children: ReactNode;
|
|
18
|
+
};
|
|
19
|
+
declare function FormBuilderThemeProvider({ theme, children }: FormBuilderThemeProviderProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Metadata for all question types available in the Pro palette.
|
|
23
|
+
* Icons are lucide-react component names (imported dynamically via ICON_MAP).
|
|
24
|
+
*
|
|
25
|
+
* 44 field types — general-purpose form building.
|
|
26
|
+
* Telehealth-specific fields (15) are in @squaredr/fieldcraft-pro-telehealth.
|
|
27
|
+
*/
|
|
28
|
+
declare const QUESTION_TYPE_INFO: Record<string, QuestionTypeInfo>;
|
|
29
|
+
/**
|
|
30
|
+
* Default palette layout with categories (44 Pro field types).
|
|
31
|
+
* Telehealth fields can be appended via FormBuilder's `palette` prop.
|
|
32
|
+
*/
|
|
33
|
+
declare const DEFAULT_PALETTE: ({
|
|
34
|
+
category: "text";
|
|
35
|
+
label: string;
|
|
36
|
+
types: string[];
|
|
37
|
+
} | {
|
|
38
|
+
category: "numeric";
|
|
39
|
+
label: string;
|
|
40
|
+
types: string[];
|
|
41
|
+
} | {
|
|
42
|
+
category: "selection";
|
|
43
|
+
label: string;
|
|
44
|
+
types: string[];
|
|
45
|
+
} | {
|
|
46
|
+
category: "datetime";
|
|
47
|
+
label: string;
|
|
48
|
+
types: string[];
|
|
49
|
+
} | {
|
|
50
|
+
category: "media";
|
|
51
|
+
label: string;
|
|
52
|
+
types: string[];
|
|
53
|
+
} | {
|
|
54
|
+
category: "content";
|
|
55
|
+
label: string;
|
|
56
|
+
types: string[];
|
|
57
|
+
} | {
|
|
58
|
+
category: "structural";
|
|
59
|
+
label: string;
|
|
60
|
+
types: string[];
|
|
61
|
+
} | {
|
|
62
|
+
category: "advanced";
|
|
63
|
+
label: string;
|
|
64
|
+
types: string[];
|
|
65
|
+
})[];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Generate unique IDs for sections, questions, and options.
|
|
69
|
+
* Format: {prefix}_{timestamp}_{random}
|
|
70
|
+
*/
|
|
71
|
+
declare function generateId(prefix: string): string;
|
|
72
|
+
declare function generateSectionId(): string;
|
|
73
|
+
declare function generateQuestionId(): string;
|
|
74
|
+
declare function generateOptionId(): string;
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Pure functions for mutating FormEngineSchema.
|
|
78
|
+
* All functions return a new schema object (immutable updates).
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
declare function addSection(schema: FormEngineSchema, section: Section, index: number): FormEngineSchema;
|
|
82
|
+
declare function removeSection(schema: FormEngineSchema, sectionId: string): FormEngineSchema;
|
|
83
|
+
declare function updateSection(schema: FormEngineSchema, sectionId: string, updates: Partial<Section>): FormEngineSchema;
|
|
84
|
+
declare function moveSection(schema: FormEngineSchema, sectionId: string, newIndex: number): FormEngineSchema;
|
|
85
|
+
declare function duplicateSection(schema: FormEngineSchema, sectionId: string): FormEngineSchema;
|
|
86
|
+
declare function addQuestion(schema: FormEngineSchema, sectionId: string, question: Question, index: number): FormEngineSchema;
|
|
87
|
+
declare function removeQuestion(schema: FormEngineSchema, sectionId: string, questionId: string): FormEngineSchema;
|
|
88
|
+
declare function updateQuestion(schema: FormEngineSchema, sectionId: string, questionId: string, updates: Partial<Question>): FormEngineSchema;
|
|
89
|
+
declare function moveQuestion(schema: FormEngineSchema, sectionId: string, questionId: string, targetSectionId: string, newIndex: number): FormEngineSchema;
|
|
90
|
+
declare function duplicateQuestion(schema: FormEngineSchema, sectionId: string, questionId: string): FormEngineSchema;
|
|
91
|
+
declare function addOption(schema: FormEngineSchema, sectionId: string, questionId: string, option: Option, index: number): FormEngineSchema;
|
|
92
|
+
declare function removeOption(schema: FormEngineSchema, sectionId: string, questionId: string, optionIndex: number): FormEngineSchema;
|
|
93
|
+
declare function updateOption(schema: FormEngineSchema, sectionId: string, questionId: string, optionIndex: number, updates: Partial<Option>): FormEngineSchema;
|
|
94
|
+
declare function moveOption(schema: FormEngineSchema, sectionId: string, questionId: string, oldIndex: number, newIndex: number): FormEngineSchema;
|
|
95
|
+
declare function findQuestion(schema: FormEngineSchema, sectionId: string, questionId: string): {
|
|
96
|
+
section: Section;
|
|
97
|
+
question: Question;
|
|
98
|
+
questionIndex: number;
|
|
99
|
+
} | null;
|
|
100
|
+
declare function findSection(schema: FormEngineSchema, sectionId: string): {
|
|
101
|
+
section: Section;
|
|
102
|
+
sectionIndex: number;
|
|
103
|
+
} | null;
|
|
104
|
+
|
|
105
|
+
declare function cn(...inputs: ClassValue[]): string;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Master state hook for the FormBuilder.
|
|
109
|
+
* Combines schema state, selection, and undo/redo.
|
|
110
|
+
*
|
|
111
|
+
* All mutation callbacks use a ref to read the latest schema,
|
|
112
|
+
* avoiding stale closures when multiple mutations fire in the
|
|
113
|
+
* same render tick.
|
|
114
|
+
*/
|
|
115
|
+
declare function useBuilderState(initialSchema: FormEngineSchema): {
|
|
116
|
+
schema: FormEngineSchema;
|
|
117
|
+
selectedItem: SelectedItem | null;
|
|
118
|
+
isDirty: boolean;
|
|
119
|
+
updateSchema: (newSchema: FormEngineSchema) => void;
|
|
120
|
+
addSection: (section: Section, index: number) => void;
|
|
121
|
+
removeSection: (sectionId: string) => void;
|
|
122
|
+
updateSection: (sectionId: string, updates: Partial<Section>) => void;
|
|
123
|
+
moveSection: (sectionId: string, newIndex: number) => void;
|
|
124
|
+
duplicateSection: (sectionId: string) => void;
|
|
125
|
+
addQuestion: (sectionId: string, question: Question, index: number) => void;
|
|
126
|
+
removeQuestion: (sectionId: string, questionId: string) => void;
|
|
127
|
+
updateQuestion: (sectionId: string, questionId: string, updates: Partial<Question>) => void;
|
|
128
|
+
moveQuestion: (sectionId: string, questionId: string, targetSectionId: string, newIndex: number) => void;
|
|
129
|
+
duplicateQuestion: (sectionId: string, questionId: string) => void;
|
|
130
|
+
selectQuestion: (sectionId: string, questionId: string) => void;
|
|
131
|
+
selectSection: (sectionId: string) => void;
|
|
132
|
+
clearSelection: () => void;
|
|
133
|
+
canUndo: boolean;
|
|
134
|
+
canRedo: boolean;
|
|
135
|
+
undo: () => void;
|
|
136
|
+
redo: () => void;
|
|
137
|
+
resetSchema: (newSchema: FormEngineSchema) => void;
|
|
138
|
+
markClean: () => void;
|
|
139
|
+
};
|
|
140
|
+
type BuilderStateHook = ReturnType<typeof useBuilderState>;
|
|
141
|
+
|
|
142
|
+
type UndoRedoState = {
|
|
143
|
+
canUndo: boolean;
|
|
144
|
+
canRedo: boolean;
|
|
145
|
+
undo: () => void;
|
|
146
|
+
redo: () => void;
|
|
147
|
+
push: (schema: FormEngineSchema) => void;
|
|
148
|
+
clear: () => void;
|
|
149
|
+
};
|
|
150
|
+
/**
|
|
151
|
+
* Hook for undo/redo functionality.
|
|
152
|
+
* Maintains a history stack of schemas with max 50 entries.
|
|
153
|
+
* Uses state for the index so canUndo/canRedo trigger re-renders.
|
|
154
|
+
* The history array is kept in a ref since its identity doesn't
|
|
155
|
+
* need to cause re-renders — only the index matters.
|
|
156
|
+
*/
|
|
157
|
+
declare function useUndoRedo(currentSchema: FormEngineSchema, setSchema: (schema: FormEngineSchema) => void): UndoRedoState;
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Hook to wire up @dnd-kit drag-and-drop.
|
|
161
|
+
* Returns DndContext props and handlers.
|
|
162
|
+
*/
|
|
163
|
+
declare function useDragDrop(builderState: BuilderStateHook): {
|
|
164
|
+
sensors: _dnd_kit_core.SensorDescriptor<_dnd_kit_core.SensorOptions>[];
|
|
165
|
+
handleDragStart: (event: DragStartEvent) => void;
|
|
166
|
+
handleDragEnd: (event: DragEndEvent) => void;
|
|
167
|
+
handleDragCancel: () => void;
|
|
168
|
+
activeDragItem: DragItem | null;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Default empty schema for new forms.
|
|
173
|
+
* Contains one section with one question to get started.
|
|
174
|
+
*/
|
|
175
|
+
declare const DEFAULT_SCHEMA: FormEngineSchema;
|
|
176
|
+
|
|
177
|
+
export { type BuilderStateHook, DEFAULT_PALETTE, DEFAULT_SCHEMA, DragItem, FormBuilder, FormBuilderProps, FormBuilderTheme, FormBuilderThemeProvider, QUESTION_TYPE_INFO, QuestionTypeInfo, SelectedItem, type UndoRedoState, addOption, addQuestion, addSection, cn, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo };
|