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