@squaredr/fieldcraft-pro 0.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.mjs ADDED
@@ -0,0 +1,24 @@
1
+ export { DEFAULT_PALETTE, DEFAULT_SCHEMA, FormBuilder, FormBuilderThemeProvider, QUESTION_TYPE_INFO, addOption, addQuestion, addSection, cleanPreset, cn, duplicateQuestion, duplicateSection, findQuestion, findSection, generateId, generateOptionId, generateQuestionId, generateSectionId, moveOption, moveQuestion, moveSection, removeOption, removeQuestion, removeSection, squaredrDarkPreset, updateOption, updateQuestion, updateSection, useBuilderState, useBuilderTheme, useDragDrop, useUndoRedo } from './chunk-APHGEYG4.mjs';
2
+ export { ResponseViewer } from './chunk-NIKQEWPG.mjs';
3
+ export { PREVIEW_SCHEMA, ThemeEditor, ThemeEditorInner } from './chunk-MQGR25NG.mjs';
4
+ export { FieldCraftProProvider, UnlicensedOverlay, isProductionEnvironment, requireLicense, useLicense, validateLicense } from '@squaredr/fieldcraft-pro-license';
5
+
6
+ if (typeof globalThis !== "undefined" && typeof globalThis.process !== "undefined" && globalThis.process.env?.NODE_ENV !== "production") {
7
+ const _fc_banner = `
8
+ %c FieldCraft Pro %c v0.0.0
9
+
10
+ %cForm Builder \xB7 Response Viewer \xB7 Theme Editor
11
+
12
+ Docs \u2192 https://squaredr.tech/products/fieldcraft/docs/pro
13
+ Pro Tools \u2192 https://squaredr.tech/products/fieldcraft/admin-pro
14
+ Discord \u2192 https://discord.gg/zMxdu5UVW
15
+
16
+ Need a license? \u2192 https://squaredr.tech/products/fieldcraft/admin-pro#pricing
17
+ `;
18
+ console.log(
19
+ _fc_banner,
20
+ "background:#f59e0b;color:#000;font-weight:bold;padding:2px 6px;border-radius:3px 0 0 3px",
21
+ "background:#d97706;color:#000;padding:2px 6px;border-radius:0 3px 3px 0",
22
+ "color:#6b7280"
23
+ );
24
+ }
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+ import { FormEngineSchema, FormResponse } from '@squaredr/fieldcraft-core';
3
+
4
+ type ResponseViewerProps = {
5
+ schema: FormEngineSchema;
6
+ responses: FormResponse[];
7
+ onResponseSelect?: (response: FormResponse) => void;
8
+ height?: string | number;
9
+ width?: string | number;
10
+ };
11
+ type ViewMode = "table" | "card" | "detail";
12
+ type ResponseField = {
13
+ questionId: string;
14
+ label: string;
15
+ type: string;
16
+ value: unknown;
17
+ };
18
+
19
+ declare const ResponseViewer: react.ComponentType<ResponseViewerProps>;
20
+
21
+ export { type ResponseField, ResponseViewer, type ResponseViewerProps, type ViewMode };
@@ -0,0 +1,21 @@
1
+ import * as react from 'react';
2
+ import { FormEngineSchema, FormResponse } from '@squaredr/fieldcraft-core';
3
+
4
+ type ResponseViewerProps = {
5
+ schema: FormEngineSchema;
6
+ responses: FormResponse[];
7
+ onResponseSelect?: (response: FormResponse) => void;
8
+ height?: string | number;
9
+ width?: string | number;
10
+ };
11
+ type ViewMode = "table" | "card" | "detail";
12
+ type ResponseField = {
13
+ questionId: string;
14
+ label: string;
15
+ type: string;
16
+ value: unknown;
17
+ };
18
+
19
+ declare const ResponseViewer: react.ComponentType<ResponseViewerProps>;
20
+
21
+ export { type ResponseField, ResponseViewer, type ResponseViewerProps, type ViewMode };
@@ -0,0 +1,469 @@
1
+ 'use strict';
2
+
3
+ var fieldcraftProLicense = require('@squaredr/fieldcraft-pro-license');
4
+ var react = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ // src/response-viewer/ResponseViewer.tsx
8
+ function ResponseTable({ schema, responses, onRowClick }) {
9
+ const questions = getAllQuestions(schema);
10
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { overflow: "auto", fontFamily: "inherit" }, children: /* @__PURE__ */ jsxRuntime.jsxs(
11
+ "table",
12
+ {
13
+ style: {
14
+ width: "100%",
15
+ borderCollapse: "collapse",
16
+ fontSize: "13px"
17
+ },
18
+ children: [
19
+ /* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { style: { backgroundColor: "var(--muted, #111113)" }, children: [
20
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Submitted" }),
21
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: q.label }, q.id)),
22
+ /* @__PURE__ */ jsxRuntime.jsx("th", { style: thStyle, children: "Score" })
23
+ ] }) }),
24
+ /* @__PURE__ */ jsxRuntime.jsxs("tbody", { children: [
25
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsxs(
26
+ "tr",
27
+ {
28
+ onClick: () => onRowClick?.(response),
29
+ style: {
30
+ cursor: onRowClick ? "pointer" : "default",
31
+ borderBottom: "1px solid var(--border, #1c1c20)"
32
+ },
33
+ onMouseEnter: (e) => {
34
+ if (onRowClick) e.currentTarget.style.backgroundColor = "var(--accent, #17171a)";
35
+ },
36
+ onMouseLeave: (e) => {
37
+ e.currentTarget.style.backgroundColor = "transparent";
38
+ },
39
+ children: [
40
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: new Date(response.submittedAt).toLocaleString() }),
41
+ questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: formatCellValue(response.values[q.id]) }, q.id)),
42
+ /* @__PURE__ */ jsxRuntime.jsx("td", { style: tdStyle, children: response.totalScore ?? "\u2014" })
43
+ ]
44
+ },
45
+ response.sessionToken || idx
46
+ )),
47
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx(
48
+ "td",
49
+ {
50
+ colSpan: questions.length + 2,
51
+ style: { ...tdStyle, textAlign: "center", color: "var(--muted-foreground, #8a8a95)", padding: "32px" },
52
+ children: "No responses yet"
53
+ }
54
+ ) })
55
+ ] })
56
+ ]
57
+ }
58
+ ) });
59
+ }
60
+ var thStyle = {
61
+ padding: "8px 12px",
62
+ textAlign: "left",
63
+ fontWeight: 600,
64
+ color: "var(--foreground, #e8e8ea)",
65
+ borderBottom: "2px solid var(--border, #1c1c20)",
66
+ whiteSpace: "nowrap"
67
+ };
68
+ var tdStyle = {
69
+ padding: "8px 12px",
70
+ color: "var(--foreground, #e8e8ea)",
71
+ maxWidth: "200px",
72
+ overflow: "hidden",
73
+ textOverflow: "ellipsis",
74
+ whiteSpace: "nowrap"
75
+ };
76
+ function getAllQuestions(schema) {
77
+ const questions = [];
78
+ for (const section of schema.sections) {
79
+ for (const q of section.questions) {
80
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
81
+ continue;
82
+ }
83
+ questions.push(q);
84
+ }
85
+ }
86
+ return questions;
87
+ }
88
+ function formatCellValue(value) {
89
+ if (value == null) return "\u2014";
90
+ if (typeof value === "boolean") return value ? "Yes" : "No";
91
+ if (Array.isArray(value)) return value.join(", ");
92
+ if (typeof value === "object") return JSON.stringify(value);
93
+ return String(value);
94
+ }
95
+ function ResponseCard({ response, fields, onClick }) {
96
+ return /* @__PURE__ */ jsxRuntime.jsxs(
97
+ "div",
98
+ {
99
+ onClick,
100
+ style: {
101
+ border: "1px solid var(--border, #1c1c20)",
102
+ borderRadius: "8px",
103
+ padding: "16px",
104
+ backgroundColor: "var(--card, #111113)",
105
+ cursor: onClick ? "pointer" : "default",
106
+ fontFamily: "inherit",
107
+ transition: "box-shadow 0.15s"
108
+ },
109
+ onMouseEnter: (e) => {
110
+ if (onClick) e.currentTarget.style.boxShadow = "0 2px 8px rgba(0,0,0,0.3)";
111
+ },
112
+ onMouseLeave: (e) => {
113
+ e.currentTarget.style.boxShadow = "none";
114
+ },
115
+ children: [
116
+ /* @__PURE__ */ jsxRuntime.jsxs(
117
+ "div",
118
+ {
119
+ style: {
120
+ display: "flex",
121
+ justifyContent: "space-between",
122
+ marginBottom: "12px",
123
+ fontSize: "12px",
124
+ color: "var(--muted-foreground, #8a8a95)"
125
+ },
126
+ children: [
127
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(response.submittedAt).toLocaleString() }),
128
+ response.completionTimeMs != null && /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
129
+ Math.round(response.completionTimeMs / 1e3),
130
+ "s"
131
+ ] })
132
+ ]
133
+ }
134
+ ),
135
+ fields.slice(0, 4).map((field) => /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginBottom: "8px" }, children: [
136
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "11px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "2px" }, children: field.label }),
137
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "13px", color: "var(--foreground, #e8e8ea)" }, children: formatValue(field.value) })
138
+ ] }, field.questionId)),
139
+ fields.length > 4 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginTop: "8px" }, children: [
140
+ "+",
141
+ fields.length - 4,
142
+ " more fields"
143
+ ] }),
144
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
145
+ "div",
146
+ {
147
+ style: {
148
+ marginTop: "12px",
149
+ paddingTop: "8px",
150
+ borderTop: "1px solid var(--border, #1c1c20)",
151
+ fontSize: "13px",
152
+ fontWeight: 600,
153
+ color: "var(--foreground, #e8e8ea)"
154
+ },
155
+ children: [
156
+ "Score: ",
157
+ response.totalScore
158
+ ]
159
+ }
160
+ )
161
+ ]
162
+ }
163
+ );
164
+ }
165
+ function formatValue(value) {
166
+ if (value == null) return "\u2014";
167
+ if (typeof value === "boolean") return value ? "Yes" : "No";
168
+ if (Array.isArray(value)) return value.map(formatValue).join(", ");
169
+ if (typeof value === "object") return JSON.stringify(value);
170
+ return String(value);
171
+ }
172
+ function ResponseDetail({ response, fields, onBack }) {
173
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontFamily: "inherit" }, children: [
174
+ /* @__PURE__ */ jsxRuntime.jsxs(
175
+ "div",
176
+ {
177
+ style: {
178
+ display: "flex",
179
+ alignItems: "center",
180
+ gap: "12px",
181
+ marginBottom: "20px",
182
+ paddingBottom: "12px",
183
+ borderBottom: "1px solid var(--border, #1c1c20)"
184
+ },
185
+ children: [
186
+ onBack && /* @__PURE__ */ jsxRuntime.jsx(
187
+ "button",
188
+ {
189
+ type: "button",
190
+ onClick: onBack,
191
+ style: {
192
+ padding: "4px 10px",
193
+ fontSize: "13px",
194
+ color: "var(--secondary-foreground, #e8e8ea)",
195
+ backgroundColor: "var(--secondary, #17171a)",
196
+ border: "1px solid var(--border, #1c1c20)",
197
+ borderRadius: "6px",
198
+ cursor: "pointer"
199
+ },
200
+ children: "Back"
201
+ }
202
+ ),
203
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
204
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", fontWeight: 600, color: "var(--foreground, #e8e8ea)" }, children: "Response Detail" }),
205
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)" }, children: [
206
+ "Submitted ",
207
+ new Date(response.submittedAt).toLocaleString(),
208
+ response.completionTimeMs != null && ` \u2014 ${Math.round(response.completionTimeMs / 1e3)}s`
209
+ ] })
210
+ ] })
211
+ ]
212
+ }
213
+ ),
214
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: "16px" }, children: fields.map((field) => /* @__PURE__ */ jsxRuntime.jsxs(
215
+ "div",
216
+ {
217
+ style: {
218
+ padding: "12px",
219
+ backgroundColor: "var(--muted, #111113)",
220
+ borderRadius: "6px"
221
+ },
222
+ children: [
223
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "12px", color: "var(--muted-foreground, #8a8a95)", marginBottom: "4px" }, children: [
224
+ field.label,
225
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { marginLeft: "8px", fontSize: "11px", color: "var(--muted-foreground, #8a8a95)" }, children: [
226
+ "(",
227
+ field.type,
228
+ ")"
229
+ ] })
230
+ ] }),
231
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: "14px", color: "var(--foreground, #e8e8ea)", whiteSpace: "pre-wrap" }, children: formatDetailValue(field.value) })
232
+ ]
233
+ },
234
+ field.questionId
235
+ )) }),
236
+ response.scores && Object.keys(response.scores).length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: "20px" }, children: [
237
+ /* @__PURE__ */ jsxRuntime.jsx(
238
+ "div",
239
+ {
240
+ style: {
241
+ fontSize: "14px",
242
+ fontWeight: 600,
243
+ color: "var(--foreground, #e8e8ea)",
244
+ marginBottom: "12px"
245
+ },
246
+ children: "Scores"
247
+ }
248
+ ),
249
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "12px", flexWrap: "wrap" }, children: [
250
+ Object.entries(response.scores).map(([key, value]) => /* @__PURE__ */ jsxRuntime.jsxs(
251
+ "div",
252
+ {
253
+ style: {
254
+ padding: "8px 16px",
255
+ backgroundColor: "var(--accent, #17171a)",
256
+ borderRadius: "6px",
257
+ fontSize: "13px"
258
+ },
259
+ children: [
260
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: [
261
+ key,
262
+ ": "
263
+ ] }),
264
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: value })
265
+ ]
266
+ },
267
+ key
268
+ )),
269
+ response.totalScore != null && /* @__PURE__ */ jsxRuntime.jsxs(
270
+ "div",
271
+ {
272
+ style: {
273
+ padding: "8px 16px",
274
+ backgroundColor: "var(--accent, #17171a)",
275
+ borderRadius: "6px",
276
+ fontSize: "13px"
277
+ },
278
+ children: [
279
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "var(--muted-foreground, #8a8a95)" }, children: "Total: " }),
280
+ /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600, color: "var(--primary, oklch(0.82 0.14 210))" }, children: response.totalScore })
281
+ ]
282
+ }
283
+ )
284
+ ] })
285
+ ] }),
286
+ /* @__PURE__ */ jsxRuntime.jsxs(
287
+ "div",
288
+ {
289
+ style: {
290
+ marginTop: "20px",
291
+ paddingTop: "12px",
292
+ borderTop: "1px solid var(--border, #1c1c20)",
293
+ fontSize: "12px",
294
+ color: "var(--muted-foreground, #8a8a95)"
295
+ },
296
+ children: [
297
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
298
+ "Schema: ",
299
+ response.schemaId,
300
+ " (v",
301
+ response.schemaVersion,
302
+ ")"
303
+ ] }),
304
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
305
+ "Session: ",
306
+ response.sessionToken
307
+ ] })
308
+ ]
309
+ }
310
+ )
311
+ ] });
312
+ }
313
+ function formatDetailValue(value) {
314
+ if (value == null) return "\u2014";
315
+ if (typeof value === "boolean") return value ? "Yes" : "No";
316
+ if (Array.isArray(value)) return value.map(formatDetailValue).join("\n");
317
+ if (typeof value === "object") return JSON.stringify(value, null, 2);
318
+ return String(value);
319
+ }
320
+ var viewButtonStyle = (active) => ({
321
+ padding: "4px 10px",
322
+ fontSize: "12px",
323
+ fontWeight: active ? 600 : 400,
324
+ color: active ? "var(--primary, oklch(0.82 0.14 210))" : "var(--muted-foreground, #8a8a95)",
325
+ backgroundColor: active ? "var(--accent, #17171a)" : "transparent",
326
+ border: "1px solid",
327
+ borderColor: active ? "var(--ring, oklch(0.82 0.14 210))" : "var(--border, #1c1c20)",
328
+ borderRadius: "6px",
329
+ cursor: "pointer",
330
+ fontFamily: "inherit"
331
+ });
332
+ function ResponseViewerInner({
333
+ schema,
334
+ responses,
335
+ onResponseSelect,
336
+ height = "500px",
337
+ width = "100%"
338
+ }) {
339
+ const [viewMode, setViewMode] = react.useState("table");
340
+ const [selectedResponse, setSelectedResponse] = react.useState(null);
341
+ function handleSelect(response) {
342
+ setSelectedResponse(response);
343
+ onResponseSelect?.(response);
344
+ }
345
+ function handleBack() {
346
+ setSelectedResponse(null);
347
+ }
348
+ const questions = getAllQuestions2(schema);
349
+ function getFields(response) {
350
+ return questions.map((q) => ({
351
+ questionId: q.id,
352
+ label: q.label,
353
+ type: q.type,
354
+ value: response.values[q.id]
355
+ }));
356
+ }
357
+ return /* @__PURE__ */ jsxRuntime.jsxs(
358
+ "div",
359
+ {
360
+ style: {
361
+ display: "flex",
362
+ flexDirection: "column",
363
+ height: typeof height === "number" ? `${height}px` : height,
364
+ width: typeof width === "number" ? `${width}px` : width,
365
+ border: "1px solid var(--border, #1c1c20)",
366
+ borderRadius: "8px",
367
+ overflow: "hidden",
368
+ fontFamily: "inherit",
369
+ backgroundColor: "var(--background, #0a0a0b)",
370
+ color: "var(--foreground, #e8e8ea)"
371
+ },
372
+ children: [
373
+ !selectedResponse && /* @__PURE__ */ jsxRuntime.jsxs(
374
+ "div",
375
+ {
376
+ style: {
377
+ display: "flex",
378
+ justifyContent: "space-between",
379
+ alignItems: "center",
380
+ padding: "8px 12px",
381
+ borderBottom: "1px solid var(--border, #1c1c20)"
382
+ },
383
+ children: [
384
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { fontSize: "13px", color: "var(--muted-foreground, #8a8a95)" }, children: [
385
+ responses.length,
386
+ " response",
387
+ responses.length !== 1 ? "s" : ""
388
+ ] }),
389
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: "4px" }, children: [
390
+ /* @__PURE__ */ jsxRuntime.jsx(
391
+ "button",
392
+ {
393
+ type: "button",
394
+ style: viewButtonStyle(viewMode === "table"),
395
+ onClick: () => setViewMode("table"),
396
+ children: "Table"
397
+ }
398
+ ),
399
+ /* @__PURE__ */ jsxRuntime.jsx(
400
+ "button",
401
+ {
402
+ type: "button",
403
+ style: viewButtonStyle(viewMode === "card"),
404
+ onClick: () => setViewMode("card"),
405
+ children: "Cards"
406
+ }
407
+ )
408
+ ] })
409
+ ]
410
+ }
411
+ ),
412
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "auto", padding: selectedResponse ? "16px" : void 0 }, children: selectedResponse ? /* @__PURE__ */ jsxRuntime.jsx(
413
+ ResponseDetail,
414
+ {
415
+ response: selectedResponse,
416
+ fields: getFields(selectedResponse),
417
+ onBack: handleBack
418
+ }
419
+ ) : viewMode === "table" ? /* @__PURE__ */ jsxRuntime.jsx(
420
+ ResponseTable,
421
+ {
422
+ schema,
423
+ responses,
424
+ onRowClick: handleSelect
425
+ }
426
+ ) : /* @__PURE__ */ jsxRuntime.jsxs(
427
+ "div",
428
+ {
429
+ style: {
430
+ display: "grid",
431
+ gridTemplateColumns: "repeat(auto-fill, minmax(280px, 1fr))",
432
+ gap: "12px",
433
+ padding: "12px"
434
+ },
435
+ children: [
436
+ responses.map((response, idx) => /* @__PURE__ */ jsxRuntime.jsx(
437
+ ResponseCard,
438
+ {
439
+ response,
440
+ fields: getFields(response),
441
+ onClick: () => handleSelect(response)
442
+ },
443
+ response.sessionToken || idx
444
+ )),
445
+ responses.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "32px", textAlign: "center", color: "var(--muted-foreground, #8a8a95)" }, children: "No responses yet" })
446
+ ]
447
+ }
448
+ ) })
449
+ ]
450
+ }
451
+ );
452
+ }
453
+ function getAllQuestions2(schema) {
454
+ const questions = [];
455
+ for (const section of schema.sections) {
456
+ for (const q of section.questions) {
457
+ if (q.type === "info-block" || q.type === "section-header" || q.type === "page-break") {
458
+ continue;
459
+ }
460
+ questions.push(q);
461
+ }
462
+ }
463
+ return questions;
464
+ }
465
+
466
+ // src/response-viewer/ResponseViewer.tsx
467
+ var ResponseViewer = fieldcraftProLicense.requireLicense(ResponseViewerInner, "ResponseViewer");
468
+
469
+ exports.ResponseViewer = ResponseViewer;
@@ -0,0 +1 @@
1
+ export { ResponseViewer } from '../chunk-NIKQEWPG.mjs';