@elevasis/ui 2.34.0 → 2.35.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.
Files changed (106) hide show
  1. package/dist/api/index.js +3 -3
  2. package/dist/app/index.d.ts +12 -12
  3. package/dist/app/index.js +25 -23
  4. package/dist/charts/index.js +3 -5
  5. package/dist/chunk-26HFM4MH.js +41449 -0
  6. package/dist/{chunk-DTFKWZ7A.js → chunk-4U3XAWCN.js} +502 -484
  7. package/dist/{chunk-ND5TDV2J.js → chunk-57OZ3AEG.js} +1 -1
  8. package/dist/{chunk-E4WQGJNS.js → chunk-7FPLLSHN.js} +14 -1
  9. package/dist/{chunk-RQA2EVN3.js → chunk-AKW7KISS.js} +39 -3
  10. package/dist/chunk-AUDNF2Q7.js +2050 -0
  11. package/dist/{chunk-TYRUKGGD.js → chunk-GX6XBRRF.js} +1 -2
  12. package/dist/{chunk-V6SZ4ECN.js → chunk-LUYVRATI.js} +257 -6
  13. package/dist/{chunk-X4WBGKJQ.js → chunk-R3VCBZDC.js} +50 -3
  14. package/dist/chunk-SIQ3P4OR.js +1764 -0
  15. package/dist/{chunk-RIAXZ6AH.js → chunk-VDOOGGBA.js} +1 -1
  16. package/dist/{chunk-3FV6HBXS.js → chunk-WF7CONXF.js} +23 -23
  17. package/dist/{chunk-3QXJK5IY.js → chunk-YYX7OPZQ.js} +1 -1
  18. package/dist/components/index.d.ts +69 -69
  19. package/dist/components/index.js +20 -2795
  20. package/dist/components/navigation/index.js +25 -5
  21. package/dist/execution/index.d.ts +9 -9
  22. package/dist/execution/index.js +1 -2
  23. package/dist/features/auth/index.js +23 -2
  24. package/dist/features/clients/index.js +20 -26
  25. package/dist/features/crm/index.js +20 -30
  26. package/dist/features/dashboard/index.d.ts +68 -68
  27. package/dist/features/dashboard/index.js +20 -28
  28. package/dist/features/delivery/index.js +20 -30
  29. package/dist/features/knowledge/index.js +25 -9
  30. package/dist/features/lead-gen/index.d.ts +9 -9
  31. package/dist/features/lead-gen/index.js +20 -31
  32. package/dist/features/monitoring/index.js +20 -30
  33. package/dist/features/monitoring/requests/index.js +20 -25
  34. package/dist/features/operations/index.d.ts +153 -153
  35. package/dist/features/operations/index.js +18 -37
  36. package/dist/features/seo/index.js +3 -4
  37. package/dist/features/settings/index.js +20 -27
  38. package/dist/graph/index.js +1 -1
  39. package/dist/hooks/delivery/index.js +30 -2
  40. package/dist/hooks/index.d.ts +85 -85
  41. package/dist/hooks/index.js +20 -21
  42. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +35 -35
  43. package/dist/hooks/published.d.ts +85 -85
  44. package/dist/hooks/published.js +20 -20
  45. package/dist/index.css +532 -532
  46. package/dist/index.d.ts +9256 -5803
  47. package/dist/index.js +22 -26
  48. package/dist/knowledge/index.d.ts +21 -21
  49. package/dist/knowledge/index.js +8 -15
  50. package/dist/layout/index.js +4 -10
  51. package/dist/organization/index.js +27 -1
  52. package/dist/provider/index.d.ts +47 -21
  53. package/dist/provider/index.js +20 -15
  54. package/dist/provider/published.d.ts +15 -16
  55. package/dist/provider/published.js +20 -11
  56. package/dist/test-utils/index.js +3 -3
  57. package/dist/theme/index.js +2 -3
  58. package/dist/theme/presets/index.d.ts +28 -3
  59. package/dist/theme/presets/index.js +1 -1
  60. package/dist/typeform/index.js +1 -2049
  61. package/dist/types/index.d.ts +68 -68
  62. package/dist/utils/index.d.ts +46 -46
  63. package/dist/utils/index.js +1 -1
  64. package/dist/zustand/index.d.ts +6 -6
  65. package/dist/zustand/index.js +0 -3
  66. package/package.json +5 -5
  67. package/dist/chunk-3AJVNMY5.js +0 -4769
  68. package/dist/chunk-3MEXPLWT.js +0 -265
  69. package/dist/chunk-3ZMAGTWF.js +0 -18
  70. package/dist/chunk-4O4MII5S.js +0 -4716
  71. package/dist/chunk-5EYJ2GIN.js +0 -122
  72. package/dist/chunk-7M2VOCYN.js +0 -1
  73. package/dist/chunk-BPQVTIUP.js +0 -105
  74. package/dist/chunk-BZZCNLT6.js +0 -12
  75. package/dist/chunk-CLDCYJQT.js +0 -1
  76. package/dist/chunk-E565XMTQ.js +0 -17
  77. package/dist/chunk-HRWLKKWM.js +0 -758
  78. package/dist/chunk-IGDYWFNE.js +0 -5198
  79. package/dist/chunk-IIMU5YAJ.js +0 -53
  80. package/dist/chunk-IVGI4GDL.js +0 -1593
  81. package/dist/chunk-JFL3GRD4.js +0 -39
  82. package/dist/chunk-LAWLB6CT.js +0 -951
  83. package/dist/chunk-LGKLC5MG.js +0 -44
  84. package/dist/chunk-LRWTWOGP.js +0 -1778
  85. package/dist/chunk-MP3GPBPX.js +0 -1874
  86. package/dist/chunk-N55DVMAG.js +0 -14
  87. package/dist/chunk-NLBQTDOW.js +0 -12051
  88. package/dist/chunk-O6JXQ6UQ.js +0 -468
  89. package/dist/chunk-OBBQ2JCM.js +0 -68
  90. package/dist/chunk-PDHTXPSF.js +0 -12
  91. package/dist/chunk-PLP3NYPL.js +0 -356
  92. package/dist/chunk-R2XR4FCV.js +0 -48
  93. package/dist/chunk-R66W5UDG.js +0 -26
  94. package/dist/chunk-RYTEQBAO.js +0 -37
  95. package/dist/chunk-SDXSB3HN.js +0 -425
  96. package/dist/chunk-TKAYX2SP.js +0 -204
  97. package/dist/chunk-TUMSNGTX.js +0 -35
  98. package/dist/chunk-VNAZTCHA.js +0 -65
  99. package/dist/chunk-VNFR57DF.js +0 -87
  100. package/dist/chunk-VTXTZXAU.js +0 -539
  101. package/dist/chunk-W73ZABT6.js +0 -85
  102. package/dist/chunk-WU4FNWCW.js +0 -2281
  103. package/dist/chunk-XZGSCABI.js +0 -383
  104. package/dist/chunk-YNWZIWJL.js +0 -1863
  105. /package/dist/{chunk-2RJMVWFJ.js → chunk-GEFWMU26.js} +0 -0
  106. /package/dist/{chunk-22UVE3RA.js → chunk-HENXLGVD.js} +0 -0
@@ -0,0 +1,2050 @@
1
+ import { createContext, useMemo, useState, useCallback, useEffect, useContext, useRef } from 'react';
2
+ import { Box, Progress, Text, Group, Button, Kbd, Modal, Stack, Transition, Title, UnstyledButton, TextInput, Textarea, Center, Alert, Card, ActionIcon, Paper } from '@mantine/core';
3
+ import { IconArrowLeft, IconCheck, IconArrowRight, IconPlus, IconPencil, IconTrash, IconX } from '@tabler/icons-react';
4
+ import { createPortal } from 'react-dom';
5
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
6
+
7
+ // src/components/typeform/TypeformSurvey.tsx
8
+ function normalizeToPages(config) {
9
+ if (config.pages && config.pages.length > 0) {
10
+ return config.pages;
11
+ }
12
+ if (config.questions && config.questions.length > 0) {
13
+ return config.questions.map((q) => ({
14
+ id: `page-${q.id}`,
15
+ questions: [q]
16
+ }));
17
+ }
18
+ return [];
19
+ }
20
+ function validateArrayQuestion(question, value, fieldErrors) {
21
+ const items = value || [];
22
+ const completedItems = items.filter((item) => item._status === "completed");
23
+ const editingItems = items.filter((item) => item._status === "editing");
24
+ if (editingItems.length > 0) {
25
+ return "Complete or remove all pending items before continuing";
26
+ }
27
+ if (question.minItems && completedItems.length < question.minItems) {
28
+ return `At least ${question.minItems} item(s) required`;
29
+ }
30
+ if (question.maxItems && items.length > question.maxItems) {
31
+ return `Maximum ${question.maxItems} item(s) allowed`;
32
+ }
33
+ let hasNestedError = false;
34
+ for (let i = 0; i < items.length; i++) {
35
+ const item = items[i];
36
+ if (item._status !== "completed") continue;
37
+ for (const field of question.itemTemplate.fields) {
38
+ if (field.type === "content") continue;
39
+ if (field.required) {
40
+ const fieldValue = item[field.id];
41
+ const isEmpty = !fieldValue || typeof fieldValue === "string" && !fieldValue.trim() || Array.isArray(fieldValue) && fieldValue.length === 0;
42
+ if (isEmpty) {
43
+ const errorKey = `${question.id}[${i}].${field.id}`;
44
+ fieldErrors[errorKey] = `${field.question || field.id} is required`;
45
+ hasNestedError = true;
46
+ }
47
+ }
48
+ }
49
+ }
50
+ if (hasNestedError) {
51
+ return "Please complete all required fields in each item";
52
+ }
53
+ return null;
54
+ }
55
+ function evaluateCondition(condition, answers) {
56
+ if (!condition) return true;
57
+ if (typeof condition === "function") return condition(answers);
58
+ const rawValue = answers[condition.field];
59
+ let value;
60
+ if (rawValue && typeof rawValue === "object" && "type" in rawValue) {
61
+ value = rawValue.value;
62
+ } else if (Array.isArray(rawValue) && rawValue.length > 0 && typeof rawValue[0] === "object" && "type" in rawValue[0]) {
63
+ value = rawValue.map((v) => v.value);
64
+ } else {
65
+ value = rawValue;
66
+ }
67
+ switch (condition.operator) {
68
+ case "equals":
69
+ return value === condition.value;
70
+ case "notEquals":
71
+ return value !== condition.value;
72
+ case "includes":
73
+ return Array.isArray(value) ? value.includes(condition.value) : String(value ?? "").includes(condition.value);
74
+ case "notIncludes":
75
+ return Array.isArray(value) ? !value.includes(condition.value) : !String(value ?? "").includes(condition.value);
76
+ case "isEmpty":
77
+ return !value || Array.isArray(value) && value.length === 0 || value === "";
78
+ case "isNotEmpty":
79
+ return !!value && (!Array.isArray(value) || value.length > 0) && value !== "";
80
+ default:
81
+ return true;
82
+ }
83
+ }
84
+ function useTypeform(config) {
85
+ const { schema, onSubmit, onStepChange, onPageChange, initialValues } = config;
86
+ const pages = useMemo(() => normalizeToPages(config), [config]);
87
+ const [currentPageIndex, setCurrentPageIndex] = useState(0);
88
+ const [answers, setAnswers] = useState(() => {
89
+ if (initialValues) {
90
+ return initialValues;
91
+ }
92
+ return {};
93
+ });
94
+ const [errors, setErrors] = useState({});
95
+ const [isSubmitting, setIsSubmitting] = useState(false);
96
+ const [isComplete, setIsComplete] = useState(false);
97
+ const [direction, setDirection] = useState("forward");
98
+ const visiblePages = useMemo(
99
+ () => pages.filter((page) => evaluateCondition(page.condition, answers)),
100
+ [pages, answers]
101
+ );
102
+ const currentVisiblePageIndex = useMemo(() => {
103
+ if (currentPageIndex >= visiblePages.length) {
104
+ return Math.max(0, visiblePages.length - 1);
105
+ }
106
+ return currentPageIndex;
107
+ }, [currentPageIndex, visiblePages.length]);
108
+ const currentPage = visiblePages[currentVisiblePageIndex] ?? null;
109
+ const currentPageQuestions = currentPage?.questions ?? [];
110
+ const currentQuestion = currentPageQuestions[0] ?? null;
111
+ const allQuestions = useMemo(
112
+ () => visiblePages.flatMap((p) => p.questions).filter((q) => q.type !== "content"),
113
+ [visiblePages]
114
+ );
115
+ const progress = visiblePages.length > 0 ? (currentVisiblePageIndex + 1) / visiblePages.length * 100 : 0;
116
+ const isFirstPage = currentVisiblePageIndex === 0;
117
+ const isLastPage = currentVisiblePageIndex === visiblePages.length - 1;
118
+ const isFirstQuestion = isFirstPage;
119
+ const isLastQuestion = isLastPage;
120
+ const validateQuestion = useCallback(
121
+ (question, fieldErrors) => {
122
+ if (question.type === "content") {
123
+ return null;
124
+ }
125
+ const answer = answers[question.id];
126
+ if (question.type === "array") {
127
+ const arrayQ = question;
128
+ const arrayValue = answer;
129
+ const errorsCollector = fieldErrors || {};
130
+ return validateArrayQuestion(arrayQ, arrayValue, errorsCollector);
131
+ }
132
+ if (question.required) {
133
+ if (answer === void 0 || answer === "" || Array.isArray(answer) && answer.length === 0) {
134
+ return "This field is required";
135
+ }
136
+ }
137
+ if (question.type === "email" || question.type === "text" && question.inputType === "email") {
138
+ if (answer && typeof answer === "string") {
139
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
140
+ if (!emailRegex.test(answer)) {
141
+ return "Please enter a valid email address";
142
+ }
143
+ }
144
+ }
145
+ if (question.type === "checkbox") {
146
+ const checkboxQ = question;
147
+ const selectedCount = Array.isArray(answer) ? answer.length : 0;
148
+ if (checkboxQ.minSelect && selectedCount < checkboxQ.minSelect) {
149
+ return `Please select at least ${checkboxQ.minSelect} option(s)`;
150
+ }
151
+ if (checkboxQ.maxSelect && selectedCount > checkboxQ.maxSelect) {
152
+ return `Please select at most ${checkboxQ.maxSelect} option(s)`;
153
+ }
154
+ }
155
+ return null;
156
+ },
157
+ [answers]
158
+ );
159
+ const validateCurrentPage = useCallback(() => {
160
+ const pageErrors = {};
161
+ for (const question of currentPageQuestions) {
162
+ if (question.type === "content") continue;
163
+ const error = validateQuestion(question, pageErrors);
164
+ if (error) {
165
+ pageErrors[question.id] = error;
166
+ }
167
+ }
168
+ return pageErrors;
169
+ }, [currentPageQuestions, validateQuestion]);
170
+ const canProceed = useMemo(() => {
171
+ if (!currentPage) return false;
172
+ for (const question of currentPageQuestions) {
173
+ if (question.type === "content") continue;
174
+ if (validateQuestion(question) !== null) {
175
+ return false;
176
+ }
177
+ }
178
+ return true;
179
+ }, [currentPage, currentPageQuestions, validateQuestion]);
180
+ const setAnswer = useCallback(
181
+ (questionId, value) => {
182
+ setAnswers((prev) => ({ ...prev, [questionId]: value }));
183
+ setErrors((prev) => {
184
+ const next2 = { ...prev };
185
+ delete next2[questionId];
186
+ return next2;
187
+ });
188
+ },
189
+ []
190
+ );
191
+ const setArrayItemAnswer = useCallback(
192
+ (questionId, itemIndex, fieldId, value) => {
193
+ setAnswers((prev) => {
194
+ const currentArray = prev[questionId] || [];
195
+ const newArray = [...currentArray];
196
+ if (!newArray[itemIndex]) {
197
+ newArray[itemIndex] = { _status: "editing" };
198
+ }
199
+ newArray[itemIndex] = { ...newArray[itemIndex], [fieldId]: value };
200
+ return { ...prev, [questionId]: newArray };
201
+ });
202
+ setErrors((prev) => {
203
+ const next2 = { ...prev };
204
+ const errorKey = `${questionId}[${itemIndex}].${fieldId}`;
205
+ delete next2[errorKey];
206
+ return next2;
207
+ });
208
+ },
209
+ []
210
+ );
211
+ const next = useCallback(() => {
212
+ if (!currentPage) return;
213
+ const pageErrors = validateCurrentPage();
214
+ if (Object.keys(pageErrors).length > 0) {
215
+ setErrors((prev) => ({ ...prev, ...pageErrors }));
216
+ return;
217
+ }
218
+ if (currentVisiblePageIndex < visiblePages.length - 1) {
219
+ const nextIndex = currentVisiblePageIndex + 1;
220
+ setDirection("forward");
221
+ setCurrentPageIndex(nextIndex);
222
+ const nextPage = visiblePages[nextIndex];
223
+ onPageChange?.(nextIndex, nextPage);
224
+ if (nextPage.questions[0]) {
225
+ onStepChange?.(nextIndex, nextPage.questions[0]);
226
+ }
227
+ }
228
+ }, [currentVisiblePageIndex, currentPage, visiblePages, validateCurrentPage, onPageChange, onStepChange]);
229
+ const back = useCallback(() => {
230
+ if (currentVisiblePageIndex > 0) {
231
+ const prevIndex = currentVisiblePageIndex - 1;
232
+ setDirection("backward");
233
+ setCurrentPageIndex(prevIndex);
234
+ const prevPage = visiblePages[prevIndex];
235
+ onPageChange?.(prevIndex, prevPage);
236
+ if (prevPage.questions[0]) {
237
+ onStepChange?.(prevIndex, prevPage.questions[0]);
238
+ }
239
+ }
240
+ }, [currentVisiblePageIndex, visiblePages, onPageChange, onStepChange]);
241
+ const goTo = useCallback(
242
+ (index) => {
243
+ if (index >= 0 && index < visiblePages.length) {
244
+ setCurrentPageIndex(index);
245
+ const page = visiblePages[index];
246
+ onPageChange?.(index, page);
247
+ if (page.questions[0]) {
248
+ onStepChange?.(index, page.questions[0]);
249
+ }
250
+ }
251
+ },
252
+ [visiblePages, onPageChange, onStepChange]
253
+ );
254
+ const submit = useCallback(async () => {
255
+ const allErrors = {};
256
+ for (const question of allQuestions) {
257
+ const error = validateQuestion(question);
258
+ if (error) {
259
+ allErrors[question.id] = error;
260
+ }
261
+ }
262
+ if (Object.keys(allErrors).length > 0) {
263
+ setErrors(allErrors);
264
+ for (let i = 0; i < visiblePages.length; i++) {
265
+ const page = visiblePages[i];
266
+ if (page.questions.some((q) => allErrors[q.id])) {
267
+ setCurrentPageIndex(i);
268
+ break;
269
+ }
270
+ }
271
+ return;
272
+ }
273
+ if (schema) {
274
+ const result = schema.safeParse(answers);
275
+ if (!result.success) {
276
+ const zodErrors = {};
277
+ for (const issue of result.error.issues) {
278
+ const pathStr = issue.path.join(".");
279
+ const topLevelField = issue.path[0];
280
+ if (typeof topLevelField === "string") {
281
+ if (zodErrors[topLevelField]) {
282
+ zodErrors[topLevelField] += `; ${issue.message}`;
283
+ } else {
284
+ zodErrors[topLevelField] = issue.message;
285
+ }
286
+ }
287
+ if (pathStr && pathStr !== String(topLevelField)) {
288
+ zodErrors[pathStr] = issue.message;
289
+ }
290
+ }
291
+ setErrors(zodErrors);
292
+ for (let i = 0; i < visiblePages.length; i++) {
293
+ const page = visiblePages[i];
294
+ const pageQuestionIds = page.questions.map((q) => q.id);
295
+ if (pageQuestionIds.some((qId) => zodErrors[qId])) {
296
+ setCurrentPageIndex(i);
297
+ break;
298
+ }
299
+ }
300
+ return;
301
+ }
302
+ }
303
+ setIsSubmitting(true);
304
+ try {
305
+ await onSubmit(answers);
306
+ setIsComplete(true);
307
+ } catch (error) {
308
+ console.error("[Typeform] Form submission error:", error);
309
+ setErrors({ _form: error instanceof Error ? error.message : "Submission failed. Please try again." });
310
+ } finally {
311
+ setIsSubmitting(false);
312
+ }
313
+ }, [answers, allQuestions, visiblePages, schema, onSubmit, validateQuestion]);
314
+ const reset = useCallback(() => {
315
+ setCurrentPageIndex(0);
316
+ setAnswers(initialValues ? initialValues : {});
317
+ setErrors({});
318
+ setIsSubmitting(false);
319
+ setIsComplete(false);
320
+ }, [initialValues]);
321
+ const terminateAndSubmit = useCallback(
322
+ async (reason) => {
323
+ if (!config.terminationAction?.onTerminate) {
324
+ console.warn("terminateAndSubmit called but no terminationAction.onTerminate configured");
325
+ return;
326
+ }
327
+ try {
328
+ setIsSubmitting(true);
329
+ const partialData = answers;
330
+ const currentPage2 = visiblePages[currentVisiblePageIndex];
331
+ const lastPageIndex = pages.findIndex((p) => p.id === currentPage2?.id);
332
+ await config.terminationAction.onTerminate({
333
+ partialData,
334
+ lastPageIndex: lastPageIndex >= 0 ? lastPageIndex : currentVisiblePageIndex,
335
+ reason
336
+ });
337
+ setIsComplete(true);
338
+ } catch (error) {
339
+ console.error("Termination failed:", error);
340
+ throw error;
341
+ } finally {
342
+ setIsSubmitting(false);
343
+ }
344
+ },
345
+ [answers, config, currentVisiblePageIndex, visiblePages, pages]
346
+ );
347
+ return {
348
+ // State
349
+ currentIndex: currentVisiblePageIndex,
350
+ // backwards compatibility
351
+ answers,
352
+ errors,
353
+ isSubmitting,
354
+ isComplete,
355
+ direction,
356
+ // Computed
357
+ currentQuestion,
358
+ currentPage,
359
+ currentPageIndex: currentVisiblePageIndex,
360
+ pages: visiblePages,
361
+ // Return visible pages for progress bar
362
+ progress,
363
+ isFirstQuestion,
364
+ isLastQuestion,
365
+ isFirstPage,
366
+ isLastPage,
367
+ canProceed,
368
+ // Actions
369
+ next,
370
+ back,
371
+ goTo,
372
+ setAnswer,
373
+ setArrayItemAnswer,
374
+ submit,
375
+ reset,
376
+ terminateAndSubmit
377
+ };
378
+ }
379
+
380
+ // src/components/typeform/theme.ts
381
+ var defaultTheme = {
382
+ colors: {
383
+ primary: "var(--mantine-color-blue-6)",
384
+ background: "var(--color-background)",
385
+ card: "var(--mantine-color-blue-9)",
386
+ cardBorder: "var(--mantine-color-dark-5)",
387
+ text: "var(--color-text)",
388
+ textMuted: "var(--color-text-dimmed)"
389
+ },
390
+ spacing: {
391
+ questionGap: 12,
392
+ contentMaxWidth: 800,
393
+ // Wider default for better multi-question support
394
+ pageGap: 32
395
+ // Gap between questions on same page
396
+ },
397
+ animation: {
398
+ duration: 300,
399
+ easing: "ease"
400
+ },
401
+ options: {
402
+ autoAdvance: false,
403
+ compact: false
404
+ // Compact mode for multi-question pages
405
+ }
406
+ };
407
+ function mergeTheme(theme) {
408
+ return {
409
+ colors: { ...defaultTheme.colors, ...theme?.colors },
410
+ spacing: { ...defaultTheme.spacing, ...theme?.spacing },
411
+ animation: { ...defaultTheme.animation, ...theme?.animation },
412
+ options: { ...defaultTheme.options, ...theme?.options }
413
+ };
414
+ }
415
+ function TypeformProgress({
416
+ current,
417
+ total,
418
+ showPercentage = false,
419
+ usePortal = false
420
+ }) {
421
+ const { styles } = useTypeformContext();
422
+ const percentage = total > 0 ? Math.round(current / total * 100) : 0;
423
+ const [mounted, setMounted] = useState(false);
424
+ useEffect(() => {
425
+ setMounted(true);
426
+ }, []);
427
+ const content = /* @__PURE__ */ jsxs(
428
+ Box,
429
+ {
430
+ style: {
431
+ position: "fixed",
432
+ top: 0,
433
+ left: 0,
434
+ right: 0,
435
+ zIndex: 1e3,
436
+ ...styles?.progress
437
+ },
438
+ children: [
439
+ /* @__PURE__ */ jsx(
440
+ Progress,
441
+ {
442
+ value: percentage,
443
+ size: 4,
444
+ radius: 0,
445
+ transitionDuration: 300,
446
+ style: styles?.progressBar,
447
+ styles: {
448
+ root: {
449
+ background: "var(--mantine-color-dark-6)"
450
+ }
451
+ }
452
+ }
453
+ ),
454
+ showPercentage && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", ta: "right", pr: "md", pt: 4, style: styles?.progressText, children: [
455
+ percentage,
456
+ "%"
457
+ ] })
458
+ ]
459
+ }
460
+ );
461
+ if (usePortal && mounted && typeof document !== "undefined") {
462
+ return createPortal(content, document.body);
463
+ }
464
+ return content;
465
+ }
466
+ function TypeformNavigation({
467
+ onBack,
468
+ onNext,
469
+ onSubmit,
470
+ canGoBack,
471
+ canGoNext,
472
+ isLastQuestion,
473
+ isSubmitting,
474
+ terminationAction,
475
+ onTerminate
476
+ }) {
477
+ const { styles } = useTypeformContext();
478
+ const [showTerminationModal, setShowTerminationModal] = useState(false);
479
+ return /* @__PURE__ */ jsxs(
480
+ Box,
481
+ {
482
+ style: {
483
+ position: "sticky",
484
+ bottom: 0,
485
+ padding: "var(--mantine-spacing-md)",
486
+ background: "var(--color-background)",
487
+ borderTop: "1px solid var(--color-border)",
488
+ borderRadius: "var(--mantine-radius-default)",
489
+ ...styles?.navigation
490
+ },
491
+ children: [
492
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", maw: 600, mx: "auto", children: [
493
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
494
+ terminationAction && onTerminate && !canGoBack && /* @__PURE__ */ jsx(
495
+ Button,
496
+ {
497
+ variant: terminationAction.variant || "subtle",
498
+ color: terminationAction.color || "red",
499
+ onClick: () => {
500
+ if (terminationAction.confirmText) {
501
+ setShowTerminationModal(true);
502
+ } else {
503
+ onTerminate();
504
+ }
505
+ },
506
+ style: styles?.buttonTerminate,
507
+ children: terminationAction.label
508
+ }
509
+ ),
510
+ /* @__PURE__ */ jsx(
511
+ Button,
512
+ {
513
+ variant: "subtle",
514
+ color: "gray",
515
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
516
+ onClick: onBack,
517
+ disabled: !canGoBack,
518
+ style: styles?.buttonBack,
519
+ styles: {
520
+ root: {
521
+ visibility: canGoBack ? "visible" : "hidden"
522
+ }
523
+ },
524
+ children: "Back"
525
+ }
526
+ )
527
+ ] }),
528
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
529
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
530
+ "Press ",
531
+ /* @__PURE__ */ jsx(Kbd, { size: "xs", children: "Enter" })
532
+ ] }),
533
+ isLastQuestion ? /* @__PURE__ */ jsx(
534
+ Button,
535
+ {
536
+ rightSection: /* @__PURE__ */ jsx(IconCheck, { size: 16 }),
537
+ onClick: onSubmit,
538
+ loading: isSubmitting,
539
+ disabled: !canGoNext,
540
+ style: {
541
+ background: "var(--color-primary)",
542
+ color: "white",
543
+ transition: "all 150ms ease",
544
+ ...styles?.buttonSubmit
545
+ },
546
+ children: "Submit"
547
+ }
548
+ ) : /* @__PURE__ */ jsx(
549
+ Button,
550
+ {
551
+ rightSection: /* @__PURE__ */ jsx(IconArrowRight, { size: 16 }),
552
+ onClick: onNext,
553
+ disabled: !canGoNext,
554
+ style: {
555
+ background: "var(--color-primary)",
556
+ color: "white",
557
+ transition: "all 150ms ease",
558
+ ...styles?.buttonNext
559
+ },
560
+ children: "Continue"
561
+ }
562
+ )
563
+ ] })
564
+ ] }),
565
+ terminationAction && onTerminate && /* @__PURE__ */ jsx(
566
+ Modal,
567
+ {
568
+ opened: showTerminationModal,
569
+ onClose: () => setShowTerminationModal(false),
570
+ title: terminationAction.label,
571
+ centered: true,
572
+ children: /* @__PURE__ */ jsxs(Stack, { children: [
573
+ /* @__PURE__ */ jsx(Text, { children: terminationAction.confirmText }),
574
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
575
+ /* @__PURE__ */ jsx(Button, { variant: "subtle", onClick: () => setShowTerminationModal(false), children: "Cancel" }),
576
+ /* @__PURE__ */ jsx(
577
+ Button,
578
+ {
579
+ color: terminationAction.color || "red",
580
+ onClick: async () => {
581
+ await onTerminate();
582
+ setShowTerminationModal(false);
583
+ },
584
+ children: "Confirm"
585
+ }
586
+ )
587
+ ] })
588
+ ] })
589
+ }
590
+ )
591
+ ]
592
+ }
593
+ );
594
+ }
595
+ var slideForward = {
596
+ in: { opacity: 1, transform: "translateY(0)" },
597
+ out: { opacity: 0, transform: "translateY(-40px)" },
598
+ transitionProperty: "opacity, transform"
599
+ };
600
+ var slideBackward = {
601
+ in: { opacity: 1, transform: "translateY(0)" },
602
+ out: { opacity: 0, transform: "translateY(40px)" },
603
+ transitionProperty: "opacity, transform"
604
+ };
605
+ function TypeformQuestionWrapper({
606
+ question,
607
+ description,
608
+ questionNumber,
609
+ isActive,
610
+ children,
611
+ error,
612
+ direction = "forward",
613
+ theme,
614
+ compact = false,
615
+ styles: customStyles
616
+ }) {
617
+ const maxWidth = theme?.spacing?.contentMaxWidth ?? 800;
618
+ return /* @__PURE__ */ jsx(
619
+ Transition,
620
+ {
621
+ mounted: isActive,
622
+ transition: direction === "backward" ? slideBackward : slideForward,
623
+ duration: theme?.animation?.duration ?? 300,
624
+ timingFunction: theme?.animation?.easing ?? "ease",
625
+ children: (transitionStyles) => /* @__PURE__ */ jsx(
626
+ Box,
627
+ {
628
+ style: {
629
+ ...transitionStyles,
630
+ display: "flex",
631
+ flexDirection: "column",
632
+ alignItems: "center",
633
+ justifyContent: "flex-start",
634
+ minHeight: "100vh",
635
+ padding: "var(--mantine-spacing-xl)",
636
+ paddingTop: "min(15vh, 80px)",
637
+ paddingBottom: 100,
638
+ // Space for navigation
639
+ overflow: "auto",
640
+ ...customStyles?.question
641
+ },
642
+ children: /* @__PURE__ */ jsxs(Box, { maw: maxWidth, w: "100%", children: [
643
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", mb: "xs", style: customStyles?.questionNumber, children: [
644
+ questionNumber,
645
+ " \u2192"
646
+ ] }),
647
+ /* @__PURE__ */ jsx(
648
+ Title,
649
+ {
650
+ order: 2,
651
+ mb: "sm",
652
+ style: {
653
+ fontSize: compact ? "clamp(1.25rem, 3vw, 1.5rem)" : "clamp(1.5rem, 4vw, 2rem)",
654
+ fontWeight: 500,
655
+ lineHeight: 1.3,
656
+ ...customStyles?.questionTitle
657
+ },
658
+ children: question
659
+ }
660
+ ),
661
+ description && /* @__PURE__ */ jsx(Text, { size: compact ? "md" : "lg", c: "dimmed", mb: "xl", style: customStyles?.questionDescription, children: description }),
662
+ /* @__PURE__ */ jsx(Box, { mt: "xl", children }),
663
+ error && /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", mt: "md", style: customStyles?.error, children: error })
664
+ ] })
665
+ }
666
+ )
667
+ }
668
+ );
669
+ }
670
+ function TypeformPageWrapper({
671
+ page,
672
+ pageNumber,
673
+ isActive,
674
+ direction = "forward",
675
+ theme,
676
+ compact = false,
677
+ styles: customStyles,
678
+ errors,
679
+ renderField
680
+ }) {
681
+ const maxWidth = theme?.spacing?.contentMaxWidth ?? 800;
682
+ const pageGap = theme?.spacing?.pageGap ?? 32;
683
+ const isMultiQuestion = page.questions.length > 1;
684
+ return /* @__PURE__ */ jsx(
685
+ Transition,
686
+ {
687
+ mounted: isActive,
688
+ transition: direction === "backward" ? slideBackward : slideForward,
689
+ duration: theme?.animation?.duration ?? 300,
690
+ timingFunction: theme?.animation?.easing ?? "ease",
691
+ children: (transitionStyles) => /* @__PURE__ */ jsx(
692
+ Box,
693
+ {
694
+ style: {
695
+ ...transitionStyles,
696
+ display: "flex",
697
+ flexDirection: "column",
698
+ alignItems: "center",
699
+ justifyContent: "flex-start",
700
+ minHeight: "100vh",
701
+ padding: "var(--mantine-spacing-xl)",
702
+ paddingTop: "min(15vh, 80px)",
703
+ paddingBottom: 100,
704
+ // Space for navigation
705
+ overflow: "auto",
706
+ ...customStyles?.question
707
+ },
708
+ children: /* @__PURE__ */ jsxs(Box, { maw: maxWidth, w: "100%", children: [
709
+ page.title && /* @__PURE__ */ jsxs(Fragment, { children: [
710
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", mb: "xs", style: customStyles?.questionNumber, children: [
711
+ pageNumber,
712
+ " \u2192"
713
+ ] }),
714
+ /* @__PURE__ */ jsx(
715
+ Title,
716
+ {
717
+ order: 2,
718
+ mb: "sm",
719
+ style: {
720
+ fontSize: "clamp(1.5rem, 4vw, 2rem)",
721
+ fontWeight: 600,
722
+ lineHeight: 1.3,
723
+ ...customStyles?.questionTitle
724
+ },
725
+ children: page.title
726
+ }
727
+ ),
728
+ page.description && /* @__PURE__ */ jsx(Text, { size: "md", c: "dimmed", mb: "lg", style: customStyles?.questionDescription, children: page.description })
729
+ ] }),
730
+ /* @__PURE__ */ jsx(Stack, { gap: pageGap, children: page.questions.map((question) => {
731
+ const error = errors[question.id];
732
+ const showQuestionNumber = !page.title;
733
+ if (question.type === "content") {
734
+ return /* @__PURE__ */ jsx(Box, { mt: isMultiQuestion ? "sm" : "md", children: renderField(question) }, question.id);
735
+ }
736
+ return /* @__PURE__ */ jsxs(Box, { children: [
737
+ showQuestionNumber && !isMultiQuestion && /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", mb: "xs", style: customStyles?.questionNumber, children: [
738
+ pageNumber,
739
+ " \u2192"
740
+ ] }),
741
+ /* @__PURE__ */ jsxs(
742
+ Title,
743
+ {
744
+ order: isMultiQuestion ? 3 : 2,
745
+ mb: "xs",
746
+ style: {
747
+ fontSize: isMultiQuestion ? "clamp(1.125rem, 2.5vw, 1.25rem)" : compact ? "clamp(1.25rem, 3vw, 1.5rem)" : "clamp(1.5rem, 4vw, 2rem)",
748
+ fontWeight: 500,
749
+ lineHeight: 1.4
750
+ },
751
+ children: [
752
+ question.question,
753
+ question.required && /* @__PURE__ */ jsx(Text, { component: "span", c: "red", ml: 6, children: "*" })
754
+ ]
755
+ }
756
+ ),
757
+ question.description && /* @__PURE__ */ jsx(
758
+ Text,
759
+ {
760
+ size: isMultiQuestion ? "sm" : compact ? "md" : "lg",
761
+ c: "dimmed",
762
+ mb: "md",
763
+ style: customStyles?.questionDescription,
764
+ children: question.description
765
+ }
766
+ ),
767
+ /* @__PURE__ */ jsx(Box, { mt: isMultiQuestion ? "sm" : "xl", children: renderField(question) }),
768
+ error && /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", mt: "md", style: customStyles?.error, children: error })
769
+ ] }, question.id);
770
+ }) })
771
+ ] })
772
+ }
773
+ )
774
+ }
775
+ );
776
+ }
777
+
778
+ // src/components/typeform/hooks.ts
779
+ function useCardStyle() {
780
+ const { config, styles } = useTypeformContext();
781
+ const theme = config.theme;
782
+ const getCardStyle = (isSelected, isHovered) => {
783
+ const base = {
784
+ display: "block",
785
+ width: "100%",
786
+ padding: "var(--mantine-spacing-sm) var(--mantine-spacing-md)",
787
+ borderRadius: "var(--mantine-radius-md)",
788
+ border: "1px solid var(--color-border)",
789
+ backgroundColor: "transparent",
790
+ ...styles?.card,
791
+ // Force-disable any preset transition (instant state changes)
792
+ transition: "none"
793
+ };
794
+ const fallbackSelected = {
795
+ border: "var(--active-border)",
796
+ backgroundColor: "var(--active-background)"
797
+ };
798
+ const fallbackHovered = {
799
+ backgroundColor: "var(--color-surface)"
800
+ };
801
+ if (isSelected) {
802
+ return {
803
+ ...base,
804
+ ...fallbackSelected,
805
+ ...styles?.cardSelected
806
+ };
807
+ }
808
+ if (isHovered) {
809
+ return {
810
+ ...base,
811
+ ...fallbackHovered,
812
+ ...styles?.cardHovered
813
+ };
814
+ }
815
+ return base;
816
+ };
817
+ const getKeyStyle = (isSelected, isHovered) => ({
818
+ minWidth: 24,
819
+ height: 24,
820
+ display: "inline-flex",
821
+ alignItems: "center",
822
+ justifyContent: "center",
823
+ fontSize: "var(--mantine-font-size-xs)",
824
+ backgroundColor: isSelected || isHovered ? "var(--color-primary)" : "var(--mantine-color-dark-5)",
825
+ color: isSelected || isHovered ? "#ffffff" : void 0,
826
+ border: "none",
827
+ flexShrink: 0,
828
+ ...styles?.cardKey,
829
+ transition: "none",
830
+ ...isSelected || isHovered ? { backgroundColor: "var(--color-primary)", color: "#ffffff" } : null
831
+ });
832
+ return { getCardStyle, getKeyStyle, theme, styles };
833
+ }
834
+
835
+ // src/components/typeform/types.ts
836
+ function createPresetValue(value) {
837
+ return { type: "preset", value };
838
+ }
839
+ function createCustomValue(value) {
840
+ return { type: "custom", value };
841
+ }
842
+ function isCustomValue(answer) {
843
+ return answer.type === "custom";
844
+ }
845
+ function isPresetValue(answer) {
846
+ return answer.type === "preset";
847
+ }
848
+ function getAnswerString(answer) {
849
+ return answer?.value ?? "";
850
+ }
851
+ function getMultiAnswerStrings(answers) {
852
+ return answers.map((a) => a.value);
853
+ }
854
+ function hasCustomValue(answers) {
855
+ return answers.some((a) => a.type === "custom");
856
+ }
857
+ function getCustomValueText(answers) {
858
+ const custom = answers.find((a) => a.type === "custom");
859
+ return custom?.value;
860
+ }
861
+ function hasPresetValue(answers, value) {
862
+ return answers.some((a) => a.type === "preset" && a.value === value);
863
+ }
864
+ function extractAnswerValue(answer) {
865
+ return answer.value;
866
+ }
867
+ function extractMultiAnswerValues(answers) {
868
+ return answers.map((a) => a.value);
869
+ }
870
+ function createSurveyConfig(config) {
871
+ return config;
872
+ }
873
+ function TypeformRadioGroup({ question, value, onChange, error }) {
874
+ const { getCardStyle, getKeyStyle, styles } = useCardStyle();
875
+ const { options } = question;
876
+ const [hoveredIndex, setHoveredIndex] = useState(null);
877
+ const [otherText, setOtherText] = useState(() => {
878
+ if (value && isCustomValue(value)) {
879
+ return value.value;
880
+ }
881
+ return "";
882
+ });
883
+ useEffect(() => {
884
+ if (value && isCustomValue(value)) {
885
+ setOtherText(value.value);
886
+ } else if (!value || !isCustomValue(value)) {
887
+ setOtherText("");
888
+ }
889
+ }, [value]);
890
+ const isOtherSelected = value && isCustomValue(value);
891
+ const selectedPresetValue = value && !isCustomValue(value) ? value.value : null;
892
+ const handleOptionClick = (optionValue) => {
893
+ const isOther = optionValue.toLowerCase() === "other";
894
+ if (isOther) {
895
+ onChange(createCustomValue(otherText));
896
+ } else {
897
+ onChange(createPresetValue(optionValue));
898
+ setOtherText("");
899
+ }
900
+ };
901
+ const handleOtherTextChange = (text) => {
902
+ setOtherText(text);
903
+ onChange(createCustomValue(text));
904
+ };
905
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
906
+ options.map((option, index) => {
907
+ const isOther = option.value.toLowerCase() === "other";
908
+ const isSelected = isOther ? isOtherSelected : selectedPresetValue === option.value;
909
+ const letterKey = String.fromCharCode(65 + index);
910
+ return /* @__PURE__ */ jsx(
911
+ UnstyledButton,
912
+ {
913
+ onClick: () => handleOptionClick(option.value),
914
+ onMouseEnter: () => setHoveredIndex(index),
915
+ onMouseLeave: () => setHoveredIndex(null),
916
+ style: getCardStyle(!!isSelected, hoveredIndex === index),
917
+ children: /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", children: [
918
+ /* @__PURE__ */ jsx(Kbd, { size: "xs", style: getKeyStyle(!!isSelected, hoveredIndex === index), children: letterKey }),
919
+ /* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
920
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, style: styles?.cardLabel, children: option.label }),
921
+ option.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mt: 2, style: styles?.cardDescription, children: option.description })
922
+ ] }),
923
+ isSelected && /* @__PURE__ */ jsx(IconCheck, { size: 16, style: { color: "var(--color-primary)", ...styles?.cardCheckmark } })
924
+ ] })
925
+ },
926
+ option.value
927
+ );
928
+ }),
929
+ isOtherSelected && /* @__PURE__ */ jsx(Box, { mt: "md", children: /* @__PURE__ */ jsx(
930
+ TextInput,
931
+ {
932
+ placeholder: "Please specify...",
933
+ value: otherText,
934
+ onChange: (e) => handleOtherTextChange(e.target.value),
935
+ styles: {
936
+ input: {
937
+ ...styles?.input,
938
+ fontSize: 16
939
+ }
940
+ }
941
+ }
942
+ ) }),
943
+ error && /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", mt: "sm", style: styles?.error, children: error })
944
+ ] });
945
+ }
946
+ function TypeformCheckboxGroup({ question, value, onChange, error }) {
947
+ const { getCardStyle, getKeyStyle, styles } = useCardStyle();
948
+ const { options } = question;
949
+ const [hoveredIndex, setHoveredIndex] = useState(null);
950
+ const [otherText, setOtherText] = useState(() => getCustomValueText(value) ?? "");
951
+ useEffect(() => {
952
+ const customText = getCustomValueText(value);
953
+ if (customText !== void 0) {
954
+ setOtherText(customText);
955
+ } else if (!hasCustomValue(value)) {
956
+ setOtherText("");
957
+ }
958
+ }, [value]);
959
+ const isOtherSelected = hasCustomValue(value);
960
+ const handleToggle = (optionValue) => {
961
+ const isOther = optionValue.toLowerCase() === "other";
962
+ if (isOther) {
963
+ if (isOtherSelected) {
964
+ onChange(value.filter((v) => v.type !== "custom"));
965
+ setOtherText("");
966
+ } else {
967
+ onChange([...value, createCustomValue("")]);
968
+ }
969
+ } else {
970
+ const hasValue = hasPresetValue(value, optionValue);
971
+ if (hasValue) {
972
+ onChange(value.filter((v) => !(v.type === "preset" && v.value === optionValue)));
973
+ } else {
974
+ onChange([...value, createPresetValue(optionValue)]);
975
+ }
976
+ }
977
+ };
978
+ const handleOtherTextChange = (text) => {
979
+ setOtherText(text);
980
+ const withoutCustom = value.filter((v) => v.type !== "custom");
981
+ onChange([...withoutCustom, createCustomValue(text)]);
982
+ };
983
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
984
+ options.map((option, index) => {
985
+ const isOther = option.value.toLowerCase() === "other";
986
+ const isSelected = isOther ? isOtherSelected : hasPresetValue(value, option.value);
987
+ const letterKey = String.fromCharCode(65 + index);
988
+ return /* @__PURE__ */ jsx(
989
+ UnstyledButton,
990
+ {
991
+ onClick: () => handleToggle(option.value),
992
+ onMouseEnter: () => setHoveredIndex(index),
993
+ onMouseLeave: () => setHoveredIndex(null),
994
+ style: getCardStyle(isSelected, hoveredIndex === index),
995
+ children: /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", children: [
996
+ /* @__PURE__ */ jsx(Kbd, { size: "xs", style: getKeyStyle(isSelected, hoveredIndex === index), children: letterKey }),
997
+ /* @__PURE__ */ jsx(
998
+ Box,
999
+ {
1000
+ style: {
1001
+ width: 20,
1002
+ height: 20,
1003
+ borderRadius: 4,
1004
+ border: `2px solid ${isSelected ? "var(--color-primary)" : "var(--mantine-color-dark-4)"}`,
1005
+ backgroundColor: isSelected ? "var(--color-primary)" : "transparent",
1006
+ display: "flex",
1007
+ alignItems: "center",
1008
+ justifyContent: "center",
1009
+ transition: "all 150ms ease",
1010
+ flexShrink: 0
1011
+ },
1012
+ children: isSelected && /* @__PURE__ */ jsx(IconCheck, { size: 14, style: { color: "white" } })
1013
+ }
1014
+ ),
1015
+ /* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
1016
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, style: styles?.cardLabel, children: option.label }),
1017
+ option.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", mt: 2, style: styles?.cardDescription, children: option.description })
1018
+ ] })
1019
+ ] })
1020
+ },
1021
+ option.value
1022
+ );
1023
+ }),
1024
+ isOtherSelected && /* @__PURE__ */ jsx(Box, { mt: "md", children: /* @__PURE__ */ jsx(
1025
+ TextInput,
1026
+ {
1027
+ placeholder: "Please specify...",
1028
+ value: otherText,
1029
+ onChange: (e) => handleOtherTextChange(e.target.value),
1030
+ styles: {
1031
+ input: {
1032
+ ...styles?.input,
1033
+ fontSize: 16
1034
+ }
1035
+ }
1036
+ }
1037
+ ) }),
1038
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mt: "xs", children: "Select all that apply" }),
1039
+ error && /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", mt: "sm", style: styles?.error, children: error })
1040
+ ] });
1041
+ }
1042
+ function TypeformTextInput({ question, value, onChange, error, onSubmit }) {
1043
+ const { config, styles } = useTypeformContext();
1044
+ const theme = config.theme;
1045
+ const handleKeyDown = (e) => {
1046
+ if (e.key === "Enter" && !e.shiftKey && question.type !== "textarea") {
1047
+ e.preventDefault();
1048
+ onSubmit?.();
1049
+ }
1050
+ };
1051
+ const focusBorderColor = theme?.colors?.primary ?? "var(--mantine-color-blue-6)";
1052
+ const textColor = theme?.colors?.text ?? void 0;
1053
+ if (question.type === "textarea") {
1054
+ const textareaQuestion = question;
1055
+ return /* @__PURE__ */ jsx(
1056
+ Textarea,
1057
+ {
1058
+ value,
1059
+ onChange: (e) => onChange(e.target.value),
1060
+ placeholder: textareaQuestion.placeholder || "Type your answer here...",
1061
+ error,
1062
+ rows: textareaQuestion.rows || 4,
1063
+ autoFocus: true,
1064
+ styles: {
1065
+ input: {
1066
+ ...styles?.textarea,
1067
+ color: textColor,
1068
+ "&:focus": {
1069
+ borderColor: focusBorderColor
1070
+ }
1071
+ }
1072
+ }
1073
+ }
1074
+ );
1075
+ }
1076
+ const textQuestion = question;
1077
+ return /* @__PURE__ */ jsx(
1078
+ TextInput,
1079
+ {
1080
+ value,
1081
+ onChange: (e) => onChange(e.target.value),
1082
+ placeholder: textQuestion.placeholder || "Type your answer here...",
1083
+ type: textQuestion.inputType || "text",
1084
+ error,
1085
+ onKeyDown: handleKeyDown,
1086
+ autoFocus: true,
1087
+ styles: {
1088
+ input: {
1089
+ ...styles?.input,
1090
+ color: textColor,
1091
+ "&:focus": {
1092
+ borderBottomColor: focusBorderColor
1093
+ }
1094
+ }
1095
+ }
1096
+ }
1097
+ );
1098
+ }
1099
+ function TypeformArrayField({
1100
+ question,
1101
+ value = [],
1102
+ onChange,
1103
+ errors,
1104
+ renderField,
1105
+ theme: _theme
1106
+ }) {
1107
+ const {
1108
+ itemTemplate,
1109
+ minItems = 0,
1110
+ maxItems,
1111
+ addLabel = "Add item",
1112
+ removeLabel = "Remove",
1113
+ itemLabel,
1114
+ summaryFields
1115
+ } = question;
1116
+ const [localErrors, setLocalErrors] = useState({});
1117
+ const hasEditingItems = value.some((item) => item._status === "editing");
1118
+ const canAdd = (maxItems === void 0 || value.length < maxItems) && !hasEditingItems;
1119
+ const getCanRemove = (item) => {
1120
+ const completedCount = value.filter((i) => i._status === "completed").length;
1121
+ if (item._status === "editing") return true;
1122
+ return completedCount > minItems;
1123
+ };
1124
+ const handleAdd = () => {
1125
+ if (!canAdd) return;
1126
+ const newItem = { _status: "editing" };
1127
+ itemTemplate.fields.forEach((field) => {
1128
+ if (field.type !== "content") {
1129
+ if (field.type === "checkbox") {
1130
+ newItem[field.id] = [];
1131
+ } else {
1132
+ newItem[field.id] = "";
1133
+ }
1134
+ }
1135
+ });
1136
+ onChange([...value, newItem]);
1137
+ };
1138
+ const handleRemove = (index) => {
1139
+ const newValue = value.filter((_, i) => i !== index);
1140
+ onChange(newValue);
1141
+ const newLocalErrors = { ...localErrors };
1142
+ Object.keys(newLocalErrors).forEach((key) => {
1143
+ if (key.startsWith(`${question.id}[${index}]`)) {
1144
+ delete newLocalErrors[key];
1145
+ }
1146
+ });
1147
+ setLocalErrors(newLocalErrors);
1148
+ };
1149
+ const handleCancel = (index) => {
1150
+ handleRemove(index);
1151
+ };
1152
+ const handleItemChange = (index, fieldId, fieldValue) => {
1153
+ const newValue = [...value];
1154
+ newValue[index] = { ...newValue[index], [fieldId]: fieldValue };
1155
+ onChange(newValue);
1156
+ const errorKey = `${question.id}[${index}].${fieldId}`;
1157
+ if (localErrors[errorKey]) {
1158
+ const newLocalErrors = { ...localErrors };
1159
+ delete newLocalErrors[errorKey];
1160
+ setLocalErrors(newLocalErrors);
1161
+ }
1162
+ };
1163
+ const validateItem = (index) => {
1164
+ const item = value[index];
1165
+ if (!item) return false;
1166
+ const newErrors = {};
1167
+ let hasError = false;
1168
+ for (const field of itemTemplate.fields) {
1169
+ if (field.type === "content") continue;
1170
+ if (field.required) {
1171
+ const fieldValue = item[field.id];
1172
+ const isEmpty = !fieldValue || typeof fieldValue === "string" && !fieldValue.trim() || Array.isArray(fieldValue) && fieldValue.length === 0;
1173
+ if (isEmpty) {
1174
+ const errorKey = `${question.id}[${index}].${field.id}`;
1175
+ newErrors[errorKey] = `${field.question || field.id} is required`;
1176
+ hasError = true;
1177
+ }
1178
+ }
1179
+ }
1180
+ setLocalErrors((prev) => ({ ...prev, ...newErrors }));
1181
+ return !hasError;
1182
+ };
1183
+ const handleComplete = (index) => {
1184
+ if (validateItem(index)) {
1185
+ const newValue = [...value];
1186
+ newValue[index] = { ...newValue[index], _status: "completed" };
1187
+ onChange(newValue);
1188
+ }
1189
+ };
1190
+ const handleEdit = (index) => {
1191
+ const newValue = [...value];
1192
+ newValue[index] = { ...newValue[index], _status: "editing" };
1193
+ onChange(newValue);
1194
+ };
1195
+ const getItemLabel = (index) => {
1196
+ if (itemLabel) return itemLabel(index);
1197
+ return `Item ${index + 1}`;
1198
+ };
1199
+ const getFieldError = (index, fieldId) => {
1200
+ const errorKey = `${question.id}[${index}].${fieldId}`;
1201
+ return localErrors[errorKey] || errors?.[errorKey];
1202
+ };
1203
+ const getFieldValue = (item, field) => {
1204
+ if (field.type === "content") return "";
1205
+ const val = item[field.id];
1206
+ if (val === void 0) {
1207
+ if (field.type === "checkbox") return [];
1208
+ return "";
1209
+ }
1210
+ if (typeof val === "string" || Array.isArray(val)) return val;
1211
+ return "";
1212
+ };
1213
+ const getFieldLabel = (fieldId) => {
1214
+ const field = itemTemplate.fields.find((f) => f.id === fieldId);
1215
+ if (!field || field.type === "content") return fieldId;
1216
+ return field.question || fieldId;
1217
+ };
1218
+ const renderSummary = (item, index) => {
1219
+ const fieldsToShow = summaryFields || itemTemplate.fields.slice(0, 4).map((f) => f.id);
1220
+ const summaryLines = [];
1221
+ for (const fieldId of fieldsToShow) {
1222
+ if (fieldId === "_status") continue;
1223
+ const val = item[fieldId];
1224
+ if (!val) continue;
1225
+ const label = getFieldLabel(fieldId);
1226
+ let displayValue = "";
1227
+ if (typeof val === "string") {
1228
+ displayValue = val.length > 60 ? val.substring(0, 60) + "..." : val;
1229
+ } else if (Array.isArray(val)) {
1230
+ displayValue = val.join(", ");
1231
+ }
1232
+ if (displayValue) {
1233
+ summaryLines.push({ label, value: displayValue });
1234
+ }
1235
+ }
1236
+ return /* @__PURE__ */ jsxs(
1237
+ Card,
1238
+ {
1239
+ withBorder: true,
1240
+ padding: "md",
1241
+ style: {
1242
+ backgroundColor: "var(--color-surface)",
1243
+ borderColor: "rgba(255, 255, 255, 0.12)",
1244
+ borderRadius: 12
1245
+ },
1246
+ children: [
1247
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", mb: "xs", children: [
1248
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", c: "dimmed", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: getItemLabel(index) }),
1249
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1250
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", color: "gray", onClick: () => handleEdit(index), "aria-label": "Edit", size: "sm", children: /* @__PURE__ */ jsx(IconPencil, { size: 14 }) }),
1251
+ getCanRemove(item) && /* @__PURE__ */ jsx(
1252
+ ActionIcon,
1253
+ {
1254
+ variant: "subtle",
1255
+ color: "red",
1256
+ onClick: () => handleRemove(index),
1257
+ "aria-label": removeLabel,
1258
+ size: "sm",
1259
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
1260
+ }
1261
+ )
1262
+ ] })
1263
+ ] }),
1264
+ /* @__PURE__ */ jsx(
1265
+ Paper,
1266
+ {
1267
+ p: "sm",
1268
+ style: {
1269
+ backgroundColor: "var(--glass-background)",
1270
+ borderRadius: 8
1271
+ },
1272
+ children: summaryLines.length > 0 ? /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
1273
+ summaryLines[0] && /* @__PURE__ */ jsx(Text, { size: "sm", style: { color: "var(--color-text)" }, children: summaryLines[0].value }),
1274
+ summaryLines.length > 1 && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: summaryLines.slice(1).map((line) => line.value).join(" \xB7 ") })
1275
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fs: "italic", children: "No data" })
1276
+ }
1277
+ )
1278
+ ]
1279
+ },
1280
+ index
1281
+ );
1282
+ };
1283
+ const renderEditingForm = (item, index) => {
1284
+ return /* @__PURE__ */ jsxs(
1285
+ Card,
1286
+ {
1287
+ withBorder: true,
1288
+ padding: "md",
1289
+ style: {
1290
+ backgroundColor: "var(--color-surface)",
1291
+ borderColor: "rgba(0, 153, 255, 0.3)",
1292
+ borderRadius: 12
1293
+ },
1294
+ children: [
1295
+ /* @__PURE__ */ jsx(Text, { fw: 500, mb: "md", children: getItemLabel(index) }),
1296
+ /* @__PURE__ */ jsx(Stack, { gap: "sm", children: itemTemplate.fields.map((field) => /* @__PURE__ */ jsx(Box, { children: renderField(
1297
+ field,
1298
+ index,
1299
+ `${question.id}[${index}].${field.id}`,
1300
+ getFieldValue(item, field),
1301
+ (fieldValue) => handleItemChange(index, field.id, fieldValue),
1302
+ getFieldError(index, field.id)
1303
+ ) }, field.id)) }),
1304
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mt: "lg", children: [
1305
+ /* @__PURE__ */ jsx(Button, { variant: "filled", leftSection: /* @__PURE__ */ jsx(IconCheck, { size: 16 }), onClick: () => handleComplete(index), children: "Complete" }),
1306
+ /* @__PURE__ */ jsx(Button, { variant: "subtle", color: "gray", leftSection: /* @__PURE__ */ jsx(IconX, { size: 16 }), onClick: () => handleCancel(index), children: "Cancel" })
1307
+ ] })
1308
+ ]
1309
+ },
1310
+ index
1311
+ );
1312
+ };
1313
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1314
+ value.map(
1315
+ (item, index) => item._status === "completed" ? renderSummary(item, index) : renderEditingForm(item, index)
1316
+ ),
1317
+ canAdd && /* @__PURE__ */ jsx(Button, { variant: "light", leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: handleAdd, children: addLabel })
1318
+ ] });
1319
+ }
1320
+ var TypeformContext = createContext(null);
1321
+ function useTypeformContext() {
1322
+ const context = useContext(TypeformContext);
1323
+ if (!context) {
1324
+ throw new Error("useTypeformContext must be used within a TypeformSurvey");
1325
+ }
1326
+ return context;
1327
+ }
1328
+ function TypeformSurvey({
1329
+ config,
1330
+ className,
1331
+ styles,
1332
+ hideProgress,
1333
+ mode = "paginated",
1334
+ renderPageSection
1335
+ }) {
1336
+ const typeform = useTypeform(config);
1337
+ const {
1338
+ currentPage,
1339
+ currentPageIndex,
1340
+ pages,
1341
+ answers,
1342
+ errors,
1343
+ isFirstPage,
1344
+ isLastPage,
1345
+ isSubmitting,
1346
+ isComplete,
1347
+ canProceed,
1348
+ direction,
1349
+ next,
1350
+ back,
1351
+ submit,
1352
+ setAnswer,
1353
+ terminateAndSubmit
1354
+ } = typeform;
1355
+ const nextRef = useRef(next);
1356
+ nextRef.current = next;
1357
+ const mergedTheme = mergeTheme(config.theme);
1358
+ const isCompact = mergedTheme.options?.compact ?? false;
1359
+ const isMultiQuestion = (currentPage?.questions.length ?? 0) > 1;
1360
+ const parseMarkdown = (text) => {
1361
+ const lines = text.split("\n");
1362
+ return lines.map((line, idx) => {
1363
+ const parts = line.split(/(\*\*.*?\*\*)/);
1364
+ const renderedLine = parts.map((part, partIdx) => {
1365
+ if (part.startsWith("**") && part.endsWith("**")) {
1366
+ return /* @__PURE__ */ jsx(
1367
+ Text,
1368
+ {
1369
+ component: "span",
1370
+ fw: 700,
1371
+ style: {
1372
+ color: "var(--color-text)"
1373
+ },
1374
+ children: part.slice(2, -2)
1375
+ },
1376
+ partIdx
1377
+ );
1378
+ }
1379
+ return part;
1380
+ });
1381
+ return /* @__PURE__ */ jsxs("span", { children: [
1382
+ renderedLine,
1383
+ idx < lines.length - 1 && /* @__PURE__ */ jsx("br", {})
1384
+ ] }, idx);
1385
+ });
1386
+ };
1387
+ const renderContent = (question) => {
1388
+ const { content, style = "default" } = question;
1389
+ switch (style) {
1390
+ case "callout":
1391
+ return /* @__PURE__ */ jsx(
1392
+ Paper,
1393
+ {
1394
+ p: "lg",
1395
+ style: {
1396
+ backgroundColor: "var(--color-surface)",
1397
+ border: "1px solid rgba(255, 255, 255, 0.07)",
1398
+ borderRadius: 12,
1399
+ backdropFilter: "blur(24px)",
1400
+ WebkitBackdropFilter: "blur(24px)"
1401
+ },
1402
+ children: /* @__PURE__ */ jsx(Text, { size: "sm", style: { lineHeight: 1.6, color: "rgb(212, 212, 216)" }, children: parseMarkdown(content) })
1403
+ },
1404
+ question.id
1405
+ );
1406
+ case "script":
1407
+ return /* @__PURE__ */ jsx(
1408
+ Text,
1409
+ {
1410
+ fs: "italic",
1411
+ size: "sm",
1412
+ style: {
1413
+ color: "rgb(161, 161, 170)",
1414
+ padding: "8px 16px",
1415
+ borderLeft: "3px solid rgba(0, 153, 255, 0.3)"
1416
+ },
1417
+ children: parseMarkdown(content)
1418
+ },
1419
+ question.id
1420
+ );
1421
+ case "info":
1422
+ return /* @__PURE__ */ jsx(
1423
+ Paper,
1424
+ {
1425
+ p: "lg",
1426
+ style: {
1427
+ backgroundColor: "var(--color-surface)",
1428
+ border: "1px solid rgba(255, 255, 255, 0.07)",
1429
+ borderRadius: 12,
1430
+ backdropFilter: "blur(24px)",
1431
+ WebkitBackdropFilter: "blur(24px)"
1432
+ },
1433
+ children: /* @__PURE__ */ jsx(Text, { size: "sm", style: { lineHeight: 1.6, color: "rgb(212, 212, 216)" }, children: parseMarkdown(content) })
1434
+ },
1435
+ question.id
1436
+ );
1437
+ case "warning":
1438
+ return /* @__PURE__ */ jsxs(
1439
+ Paper,
1440
+ {
1441
+ p: "md",
1442
+ style: {
1443
+ backgroundColor: "color-mix(in srgb, var(--color-warning) 10%, transparent)",
1444
+ border: "1px solid rgba(249, 115, 22, 0.2)",
1445
+ borderRadius: 12
1446
+ },
1447
+ children: [
1448
+ /* @__PURE__ */ jsx(
1449
+ Text,
1450
+ {
1451
+ size: "sm",
1452
+ fw: 600,
1453
+ mb: "xs",
1454
+ style: { color: "rgb(251, 146, 60)", fontFamily: "var(--mantine-font-family-headings)" },
1455
+ children: "Note"
1456
+ }
1457
+ ),
1458
+ /* @__PURE__ */ jsx(Text, { size: "sm", style: { lineHeight: 1.6, color: "var(--color-text)" }, children: parseMarkdown(content) })
1459
+ ]
1460
+ },
1461
+ question.id
1462
+ );
1463
+ default:
1464
+ return /* @__PURE__ */ jsx(Text, { style: { color: "var(--color-text)" }, children: parseMarkdown(content) }, question.id);
1465
+ }
1466
+ };
1467
+ const renderField = (question) => {
1468
+ const questionId = question.id;
1469
+ const error = errors[questionId];
1470
+ switch (question.type) {
1471
+ case "content":
1472
+ return renderContent(question);
1473
+ case "radio": {
1474
+ const rawValue = answers[questionId];
1475
+ let answerValue;
1476
+ if (rawValue && typeof rawValue === "object" && "type" in rawValue) {
1477
+ answerValue = rawValue;
1478
+ } else if (typeof rawValue === "string" && rawValue) {
1479
+ answerValue = createPresetValue(rawValue);
1480
+ }
1481
+ const handleRadioChange = (value) => {
1482
+ setAnswer(questionId, value);
1483
+ if (mergedTheme.options?.autoAdvance && !isLastPage && !isMultiQuestion && !isCustomValue(value)) {
1484
+ setTimeout(() => {
1485
+ nextRef.current();
1486
+ }, 400);
1487
+ }
1488
+ };
1489
+ return /* @__PURE__ */ jsx(
1490
+ TypeformRadioGroup,
1491
+ {
1492
+ question,
1493
+ value: answerValue,
1494
+ onChange: handleRadioChange,
1495
+ error
1496
+ },
1497
+ questionId
1498
+ );
1499
+ }
1500
+ case "checkbox": {
1501
+ const rawValue = answers[questionId];
1502
+ let multiValue = [];
1503
+ if (Array.isArray(rawValue)) {
1504
+ if (rawValue.length > 0 && typeof rawValue[0] === "object" && "type" in rawValue[0]) {
1505
+ multiValue = rawValue;
1506
+ } else {
1507
+ multiValue = rawValue.map((v) => createPresetValue(v));
1508
+ }
1509
+ }
1510
+ return /* @__PURE__ */ jsx(
1511
+ TypeformCheckboxGroup,
1512
+ {
1513
+ question,
1514
+ value: multiValue,
1515
+ onChange: (value) => setAnswer(questionId, value),
1516
+ error
1517
+ },
1518
+ questionId
1519
+ );
1520
+ }
1521
+ case "text":
1522
+ case "email":
1523
+ case "textarea":
1524
+ return /* @__PURE__ */ jsx(
1525
+ TypeformTextInput,
1526
+ {
1527
+ question,
1528
+ value: answers[questionId] || "",
1529
+ onChange: (value) => setAnswer(questionId, value),
1530
+ error,
1531
+ onSubmit: () => {
1532
+ if (isLastPage) {
1533
+ submit();
1534
+ } else if (canProceed) {
1535
+ next();
1536
+ }
1537
+ }
1538
+ },
1539
+ questionId
1540
+ );
1541
+ case "array":
1542
+ return /* @__PURE__ */ jsx(
1543
+ TypeformArrayField,
1544
+ {
1545
+ question,
1546
+ value: answers[questionId] || [],
1547
+ onChange: (value) => setAnswer(questionId, value),
1548
+ errors,
1549
+ renderField: renderNestedField,
1550
+ theme: mergedTheme
1551
+ },
1552
+ questionId
1553
+ );
1554
+ default:
1555
+ return null;
1556
+ }
1557
+ };
1558
+ const renderNestedField = (field, _itemIndex, fieldId, value, onFieldChange, error) => {
1559
+ switch (field.type) {
1560
+ case "content":
1561
+ return renderContent(field);
1562
+ case "radio": {
1563
+ const answerValue = typeof value === "string" && value ? createPresetValue(value) : void 0;
1564
+ return /* @__PURE__ */ jsxs(Box, { mt: "md", children: [
1565
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, mb: 4, children: [
1566
+ field.question,
1567
+ field.required && /* @__PURE__ */ jsx(Text, { component: "span", c: "red", ml: 4, children: "*" })
1568
+ ] }),
1569
+ /* @__PURE__ */ jsx(
1570
+ TypeformRadioGroup,
1571
+ {
1572
+ question: field,
1573
+ value: answerValue,
1574
+ onChange: (newValue) => onFieldChange(newValue.value),
1575
+ error
1576
+ }
1577
+ )
1578
+ ] }, fieldId);
1579
+ }
1580
+ case "checkbox": {
1581
+ const multiValue = Array.isArray(value) ? value.map((v) => createPresetValue(v)) : [];
1582
+ return /* @__PURE__ */ jsxs(Box, { mt: "md", children: [
1583
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, mb: 4, children: [
1584
+ field.question,
1585
+ field.required && /* @__PURE__ */ jsx(Text, { component: "span", c: "red", ml: 4, children: "*" })
1586
+ ] }),
1587
+ /* @__PURE__ */ jsx(
1588
+ TypeformCheckboxGroup,
1589
+ {
1590
+ question: field,
1591
+ value: multiValue,
1592
+ onChange: (newValue) => onFieldChange(newValue.map((v) => v.value)),
1593
+ error
1594
+ }
1595
+ )
1596
+ ] }, fieldId);
1597
+ }
1598
+ case "text":
1599
+ case "email":
1600
+ case "textarea":
1601
+ return /* @__PURE__ */ jsxs(Box, { mt: "md", children: [
1602
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, mb: 4, children: [
1603
+ field.question,
1604
+ field.required && /* @__PURE__ */ jsx(Text, { component: "span", c: "red", ml: 4, children: "*" })
1605
+ ] }),
1606
+ /* @__PURE__ */ jsx(
1607
+ TypeformTextInput,
1608
+ {
1609
+ question: field,
1610
+ value: value || "",
1611
+ onChange: onFieldChange,
1612
+ error
1613
+ }
1614
+ )
1615
+ ] }, fieldId);
1616
+ default:
1617
+ return null;
1618
+ }
1619
+ };
1620
+ const handleKeyDown = useCallback(
1621
+ (e) => {
1622
+ if (isComplete) return;
1623
+ if (mode === "all") return;
1624
+ if (e.key === "Enter" && !e.shiftKey) {
1625
+ const activeElement = document.activeElement;
1626
+ if (activeElement?.tagName === "TEXTAREA") return;
1627
+ if (isMultiQuestion) return;
1628
+ if (isLastPage) {
1629
+ submit();
1630
+ } else if (canProceed) {
1631
+ next();
1632
+ }
1633
+ return;
1634
+ }
1635
+ if (!isMultiQuestion && currentPage?.questions[0]) {
1636
+ const question = currentPage.questions[0];
1637
+ if (question.type === "radio" || question.type === "checkbox") {
1638
+ const key = e.key.toUpperCase();
1639
+ const index = key.charCodeAt(0) - 65;
1640
+ const options = question.type === "radio" ? question.options : question.options;
1641
+ if (index >= 0 && index < options.length) {
1642
+ const option = options[index];
1643
+ if (question.type === "radio") {
1644
+ const newValue = createPresetValue(option.value);
1645
+ setAnswer(question.id, newValue);
1646
+ if (mergedTheme.options?.autoAdvance && !isLastPage && option.value.toLowerCase() !== "other") {
1647
+ setTimeout(() => nextRef.current(), 400);
1648
+ }
1649
+ } else {
1650
+ const rawValue = answers[question.id];
1651
+ let currentValue = [];
1652
+ if (Array.isArray(rawValue)) {
1653
+ if (rawValue.length > 0 && typeof rawValue[0] === "object" && "type" in rawValue[0]) {
1654
+ currentValue = rawValue;
1655
+ } else {
1656
+ currentValue = rawValue.map((v) => createPresetValue(v));
1657
+ }
1658
+ }
1659
+ const hasValue = currentValue.some((v) => v.type === "preset" && v.value === option.value);
1660
+ if (hasValue) {
1661
+ setAnswer(
1662
+ question.id,
1663
+ currentValue.filter((v) => !(v.type === "preset" && v.value === option.value))
1664
+ );
1665
+ } else {
1666
+ setAnswer(question.id, [...currentValue, createPresetValue(option.value)]);
1667
+ }
1668
+ }
1669
+ }
1670
+ }
1671
+ }
1672
+ },
1673
+ [
1674
+ currentPage,
1675
+ answers,
1676
+ isLastPage,
1677
+ isComplete,
1678
+ canProceed,
1679
+ isMultiQuestion,
1680
+ mode,
1681
+ next,
1682
+ submit,
1683
+ setAnswer,
1684
+ mergedTheme
1685
+ ]
1686
+ );
1687
+ useEffect(() => {
1688
+ window.addEventListener("keydown", handleKeyDown);
1689
+ return () => window.removeEventListener("keydown", handleKeyDown);
1690
+ }, [handleKeyDown]);
1691
+ useEffect(() => {
1692
+ if (typeof window === "undefined") return;
1693
+ if (mode === "all") return;
1694
+ window.scrollTo({ top: 0, left: 0, behavior: "auto" });
1695
+ }, [currentPageIndex, mode]);
1696
+ if (isComplete) {
1697
+ return /* @__PURE__ */ jsx(Box, { className, style: styles?.container, children: /* @__PURE__ */ jsx(
1698
+ Center,
1699
+ {
1700
+ style: {
1701
+ // minHeight: '100vh',
1702
+ padding: "var(--mantine-spacing-xl)"
1703
+ // ...styles?.completion,
1704
+ },
1705
+ children: /* @__PURE__ */ jsxs(Stack, { align: "center", gap: "lg", children: [
1706
+ /* @__PURE__ */ jsx(
1707
+ Box,
1708
+ {
1709
+ style: {
1710
+ width: 80,
1711
+ height: 80,
1712
+ borderRadius: "50%",
1713
+ background: "var(--mantine-color-green-6)",
1714
+ display: "flex",
1715
+ alignItems: "center",
1716
+ justifyContent: "center",
1717
+ ...styles?.completionIcon
1718
+ },
1719
+ children: /* @__PURE__ */ jsx(IconCheck, { size: 40, color: "white" })
1720
+ }
1721
+ ),
1722
+ /* @__PURE__ */ jsx(Title, { order: 3, style: styles?.completionTitle, children: "Thank you!" }),
1723
+ /* @__PURE__ */ jsx(Text, { size: "lg", c: "dimmed", ta: "center", maw: 400, style: styles?.completionText, children: "Your response has been recorded." })
1724
+ ] })
1725
+ }
1726
+ ) });
1727
+ }
1728
+ const contextValue = {
1729
+ ...typeform,
1730
+ config,
1731
+ styles
1732
+ };
1733
+ return /* @__PURE__ */ jsx(TypeformContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsxs(
1734
+ Box,
1735
+ {
1736
+ className,
1737
+ style: {
1738
+ minHeight: "100vh",
1739
+ background: mergedTheme.colors?.background,
1740
+ ...styles?.container
1741
+ },
1742
+ children: [
1743
+ !hideProgress && mode !== "all" && /* @__PURE__ */ jsx(TypeformProgress, { current: currentPageIndex + 1, total: pages.length, usePortal: true }),
1744
+ errors._form && /* @__PURE__ */ jsx(Box, { px: "xl", pt: "md", children: /* @__PURE__ */ jsx(Alert, { color: "red", variant: "light", title: "Submission Error", children: errors._form }) }),
1745
+ mode === "all" ? /* @__PURE__ */ jsx(Fragment, { children: pages.map((page, idx) => {
1746
+ const wrapper = /* @__PURE__ */ jsx(
1747
+ TypeformPageWrapper,
1748
+ {
1749
+ page,
1750
+ pageNumber: idx + 1,
1751
+ isActive: true,
1752
+ direction: "forward",
1753
+ theme: mergedTheme,
1754
+ compact: isCompact,
1755
+ styles: {
1756
+ // Override minHeight so each section doesn't force full viewport height
1757
+ question: { minHeight: "auto", paddingTop: "var(--mantine-spacing-xl)", ...styles?.question },
1758
+ questionNumber: styles?.questionNumber,
1759
+ questionTitle: styles?.questionTitle,
1760
+ questionDescription: styles?.questionDescription,
1761
+ error: styles?.error
1762
+ },
1763
+ errors,
1764
+ renderField
1765
+ },
1766
+ page.id
1767
+ );
1768
+ return renderPageSection ? renderPageSection(page, wrapper) : wrapper;
1769
+ }) }) : currentPage && /* @__PURE__ */ jsx(
1770
+ TypeformPageWrapper,
1771
+ {
1772
+ page: currentPage,
1773
+ pageNumber: currentPageIndex + 1,
1774
+ isActive: true,
1775
+ direction,
1776
+ theme: mergedTheme,
1777
+ compact: isCompact,
1778
+ styles: {
1779
+ question: styles?.question,
1780
+ questionNumber: styles?.questionNumber,
1781
+ questionTitle: styles?.questionTitle,
1782
+ questionDescription: styles?.questionDescription,
1783
+ error: styles?.error
1784
+ },
1785
+ errors,
1786
+ renderField
1787
+ }
1788
+ ),
1789
+ /* @__PURE__ */ jsx(
1790
+ TypeformNavigation,
1791
+ {
1792
+ onBack: back,
1793
+ onNext: next,
1794
+ onSubmit: submit,
1795
+ canGoBack: mode === "all" ? false : !isFirstPage,
1796
+ canGoNext: canProceed,
1797
+ isLastQuestion: mode === "all" ? true : isLastPage,
1798
+ isSubmitting,
1799
+ terminationAction: config.terminationAction,
1800
+ onTerminate: terminateAndSubmit
1801
+ }
1802
+ )
1803
+ ]
1804
+ }
1805
+ ) });
1806
+ }
1807
+
1808
+ // src/components/typeform/presets/brochure-style.ts
1809
+ var brochureTheme = {
1810
+ colors: {
1811
+ primary: "#0099ff",
1812
+ background: "transparent",
1813
+ // Use parent container background
1814
+ card: "rgba(24, 24, 27, 0.4)",
1815
+ // zinc-900/40
1816
+ cardBorder: "rgba(255, 255, 255, 0.07)",
1817
+ text: "#ffffff",
1818
+ textMuted: "rgb(161, 161, 170)"
1819
+ // zinc-400
1820
+ },
1821
+ spacing: {
1822
+ questionGap: 14,
1823
+ contentMaxWidth: 900,
1824
+ // Wider for better multi-question support
1825
+ pageGap: 36
1826
+ // Gap between questions on same page
1827
+ },
1828
+ animation: {
1829
+ duration: 400,
1830
+ easing: "cubic-bezier(0.4, 0, 0.2, 1)"
1831
+ },
1832
+ options: {
1833
+ autoAdvance: false,
1834
+ compact: false
1835
+ // Can be enabled for multi-question pages
1836
+ }
1837
+ };
1838
+ var brochureStyles = {
1839
+ // Container - transparent, no min-height when inside glass card
1840
+ container: {
1841
+ backgroundColor: "transparent",
1842
+ minHeight: "auto"
1843
+ },
1844
+ // Question wrapper - centered content with generous padding
1845
+ question: {
1846
+ minHeight: "auto",
1847
+ padding: "56px 40px",
1848
+ paddingBottom: 120
1849
+ },
1850
+ // Question number - subtle badge style
1851
+ questionNumber: {
1852
+ fontSize: 13,
1853
+ fontWeight: 600,
1854
+ textTransform: "uppercase",
1855
+ letterSpacing: "0.15em",
1856
+ color: "#0099ff",
1857
+ marginBottom: 16
1858
+ },
1859
+ // Question title - cleaner, more modern sizing
1860
+ questionTitle: {
1861
+ fontSize: "clamp(1.5rem, 3.5vw, 1.875rem)",
1862
+ fontWeight: 600,
1863
+ letterSpacing: "-0.025em",
1864
+ lineHeight: 1.3,
1865
+ color: "#ffffff",
1866
+ marginBottom: 12
1867
+ },
1868
+ // Question description - muted text
1869
+ questionDescription: {
1870
+ fontSize: 16,
1871
+ lineHeight: 1.5,
1872
+ color: "rgb(161, 161, 170)"
1873
+ // zinc-400
1874
+ },
1875
+ // Option cards - glass morphism effect with comfortable padding
1876
+ card: {
1877
+ backgroundColor: "rgba(24, 24, 27, 0.4)",
1878
+ backdropFilter: "blur(24px)",
1879
+ WebkitBackdropFilter: "blur(24px)",
1880
+ border: "1px solid rgba(255, 255, 255, 0.07)",
1881
+ borderRadius: 12,
1882
+ padding: "16px 20px",
1883
+ boxShadow: "0 8px 32px rgba(0, 0, 0, 0.2), inset 0 1px 0 rgba(255, 255, 255, 0.03)",
1884
+ transition: "all 300ms cubic-bezier(0.4, 0, 0.2, 1)"
1885
+ },
1886
+ // Selected card - solid blue fill, no glow
1887
+ cardSelected: {
1888
+ backgroundColor: "rgba(0, 153, 255, 0.32)",
1889
+ border: "1px solid rgba(0, 153, 255, 0.85)",
1890
+ boxShadow: "none"
1891
+ },
1892
+ // Hovered card - instant subtle highlight (no transform/lift)
1893
+ cardHovered: {
1894
+ backgroundColor: "rgba(24, 24, 27, 0.6)",
1895
+ border: "1px solid rgba(255, 255, 255, 0.12)"
1896
+ },
1897
+ // Card label text - more readable
1898
+ cardLabel: {
1899
+ fontSize: 15,
1900
+ fontWeight: 500,
1901
+ lineHeight: 1.4,
1902
+ color: "#ffffff"
1903
+ },
1904
+ // Card description text
1905
+ cardDescription: {
1906
+ fontSize: 14,
1907
+ lineHeight: 1.5,
1908
+ color: "rgb(113, 113, 122)"
1909
+ // zinc-500
1910
+ },
1911
+ // Keyboard hint badge
1912
+ cardKey: {
1913
+ backgroundColor: "rgba(255, 255, 255, 0.08)",
1914
+ border: "none",
1915
+ borderRadius: 6,
1916
+ fontSize: 12,
1917
+ fontWeight: 600
1918
+ },
1919
+ // Checkmark icon
1920
+ cardCheckmark: {
1921
+ color: "#0099ff"
1922
+ },
1923
+ // Text input styling - cleaner, modern sizing
1924
+ input: {
1925
+ backgroundColor: "transparent",
1926
+ border: "none",
1927
+ borderBottom: "2px solid rgba(255, 255, 255, 0.1)",
1928
+ borderRadius: 0,
1929
+ fontSize: 16,
1930
+ fontWeight: 400,
1931
+ color: "#ffffff",
1932
+ padding: "12px 0",
1933
+ transition: "border-color 200ms ease"
1934
+ },
1935
+ // Textarea styling
1936
+ textarea: {
1937
+ backgroundColor: "rgba(24, 24, 27, 0.4)",
1938
+ backdropFilter: "blur(24px)",
1939
+ WebkitBackdropFilter: "blur(24px)",
1940
+ border: "1px solid rgba(255, 255, 255, 0.07)",
1941
+ borderRadius: 12,
1942
+ fontSize: 16,
1943
+ lineHeight: 1.5,
1944
+ color: "#ffffff",
1945
+ padding: 16
1946
+ },
1947
+ // Progress bar container - fixed at top of viewport
1948
+ progress: {
1949
+ position: "fixed",
1950
+ top: 0,
1951
+ left: 0,
1952
+ right: 0,
1953
+ zIndex: 1e3,
1954
+ backgroundColor: "transparent"
1955
+ },
1956
+ // Progress bar itself
1957
+ progressBar: {
1958
+ height: 3
1959
+ },
1960
+ // Progress percentage text
1961
+ progressText: {
1962
+ color: "rgb(113, 113, 122)",
1963
+ // zinc-500
1964
+ fontSize: 11
1965
+ },
1966
+ // Navigation footer - relative positioning inside glass card
1967
+ navigation: {
1968
+ position: "relative",
1969
+ backgroundColor: "rgba(0, 0, 0, 0.4)",
1970
+ backdropFilter: "blur(24px)",
1971
+ WebkitBackdropFilter: "blur(24px)",
1972
+ borderTop: "1px solid rgba(255, 255, 255, 0.05)",
1973
+ borderRadius: "0 0 16px 16px",
1974
+ padding: "20px 40px"
1975
+ },
1976
+ // Back button
1977
+ buttonBack: {
1978
+ color: "rgb(161, 161, 170)",
1979
+ // zinc-400
1980
+ backgroundColor: "transparent",
1981
+ border: "none"
1982
+ },
1983
+ // Next/Continue button
1984
+ buttonNext: {
1985
+ backgroundColor: "#0099ff",
1986
+ color: "#ffffff",
1987
+ border: "none",
1988
+ borderRadius: 8,
1989
+ padding: "12px 24px",
1990
+ fontSize: 15,
1991
+ fontWeight: 600,
1992
+ boxShadow: "0 4px 20px rgba(0, 153, 255, 0.3)",
1993
+ transition: "all 200ms ease"
1994
+ },
1995
+ // Submit button (uses gradient, so keep background shorthand)
1996
+ buttonSubmit: {
1997
+ background: "linear-gradient(135deg, #0099ff 0%, #0066cc 100%)",
1998
+ color: "#ffffff",
1999
+ border: "none",
2000
+ borderRadius: 8,
2001
+ padding: "12px 28px",
2002
+ fontSize: 15,
2003
+ fontWeight: 600,
2004
+ boxShadow: "0 4px 20px rgba(0, 153, 255, 0.4)",
2005
+ transition: "all 200ms ease"
2006
+ },
2007
+ // Terminate button (No Show) - true red, not pink
2008
+ buttonTerminate: {
2009
+ backgroundColor: "#dc2626",
2010
+ color: "#ffffff",
2011
+ border: "none",
2012
+ borderRadius: 8,
2013
+ padding: "10px 20px",
2014
+ fontSize: 14,
2015
+ fontWeight: 600,
2016
+ transition: "all 200ms ease"
2017
+ },
2018
+ // Completion screen
2019
+ completion: {
2020
+ backgroundColor: "transparent"
2021
+ },
2022
+ // Completion icon (uses gradient, so keep background shorthand)
2023
+ completionIcon: {
2024
+ width: 100,
2025
+ height: 100,
2026
+ background: "linear-gradient(135deg, #0099ff 0%, #0066cc 100%)",
2027
+ boxShadow: "0 8px 40px rgba(0, 153, 255, 0.4)"
2028
+ },
2029
+ // Completion title
2030
+ completionTitle: {
2031
+ fontSize: 32,
2032
+ fontWeight: 600,
2033
+ color: "#ffffff"
2034
+ },
2035
+ // Completion text
2036
+ completionText: {
2037
+ fontSize: 18,
2038
+ color: "rgb(161, 161, 170)"
2039
+ // zinc-400
2040
+ },
2041
+ // Error message
2042
+ error: {
2043
+ color: "rgb(248, 113, 113)",
2044
+ // red-400
2045
+ fontSize: 14,
2046
+ marginTop: 12
2047
+ }
2048
+ };
2049
+
2050
+ export { TypeformArrayField, TypeformCheckboxGroup, TypeformNavigation, TypeformProgress, TypeformQuestionWrapper, TypeformRadioGroup, TypeformSurvey, TypeformTextInput, brochureStyles, brochureTheme, createCustomValue, createPresetValue, createSurveyConfig, defaultTheme, extractAnswerValue, extractMultiAnswerValues, getAnswerString, getCustomValueText, getMultiAnswerStrings, hasCustomValue, hasPresetValue, isCustomValue, isPresetValue, mergeTheme, useCardStyle, useTypeform, useTypeformContext };