@explorer02/cfm-survey-sdk 0.2.1 → 0.2.2

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 (88) hide show
  1. package/dist/cli/index.js +18 -18
  2. package/dist/cli/index.mjs +14 -14
  3. package/dist/index.d.mts +465 -580
  4. package/dist/index.d.ts +465 -580
  5. package/dist/index.js +1 -1
  6. package/dist/index.mjs +1 -1
  7. package/package.json +6 -4
  8. package/postinstall.js +96 -69
  9. package/templates/AGENT.md +14 -8
  10. package/templates/docs/00-integration/answer-logic-and-navigation.md +50 -0
  11. package/templates/docs/00-integration/aws-deploy.md +281 -0
  12. package/templates/docs/00-integration/client-integration-guide.md +351 -0
  13. package/templates/docs/00-integration/component-checklist.md +45 -22
  14. package/templates/docs/00-integration/constraints.md +49 -4
  15. package/templates/docs/00-integration/custom-field-logic-and-navigation.md +174 -0
  16. package/templates/docs/00-integration/display-logic-and-navigation.md +49 -0
  17. package/templates/docs/00-integration/end-page-logic.md +64 -0
  18. package/templates/docs/00-integration/partial-save-and-recovery.md +74 -0
  19. package/templates/docs/00-integration/placeholders-and-tokens.md +116 -0
  20. package/templates/docs/00-integration/progress.md +61 -0
  21. package/templates/docs/00-integration/question-display-variants.md +65 -0
  22. package/templates/docs/00-integration/question-numbering.md +51 -0
  23. package/templates/docs/00-integration/question-type-sdk-matrix.md +242 -0
  24. package/templates/docs/00-integration/setup.md +84 -0
  25. package/templates/docs/00-integration/skip-logic-and-navigation.md +80 -0
  26. package/templates/docs/00-integration/survey-lifecycle-analytics.md +94 -0
  27. package/templates/docs/00-integration/useSurveySDK.md +151 -23
  28. package/templates/docs/01-components/01-survey-page.md +76 -54
  29. package/templates/docs/01-components/02-question.md +61 -58
  30. package/templates/docs/01-components/03-rating-scale.md +11 -1
  31. package/templates/docs/01-components/04-star-rating-scale.md +45 -0
  32. package/templates/docs/01-components/05-csat-matrix-scale.md +20 -11
  33. package/templates/docs/01-components/06-likert-matrix-scale.md +12 -3
  34. package/templates/docs/01-components/07-slider-matrix-scale.md +11 -2
  35. package/templates/docs/01-components/08-file-upload-scale.md +10 -1
  36. package/templates/docs/01-components/09-custom-slider-track.md +2 -2
  37. package/templates/docs/01-components/11-progress-bar.md +10 -4
  38. package/templates/docs/01-components/13-matrix-dropdown.md +3 -1
  39. package/templates/docs/01-components/14-intro-page.md +34 -0
  40. package/templates/docs/01-components/15-end-page.md +31 -0
  41. package/templates/docs/01-components/16-paused-page.md +27 -0
  42. package/templates/docs/01-components/17-heatmap-scale.md +75 -0
  43. package/templates/docs/01-components/18-rank-order-scale.md +100 -0
  44. package/templates/docs/01-components/README.md +42 -36
  45. package/templates/docs/02-reference/config-field-index.md +141 -139
  46. package/templates/docs/02-reference/exports.md +149 -0
  47. package/templates/docs/02-reference/question-types/01-rating.md +31 -32
  48. package/templates/docs/02-reference/question-types/04-csat.md +51 -42
  49. package/templates/docs/02-reference/question-types/05-rating-scale.md +16 -11
  50. package/templates/docs/02-reference/question-types/06-slider.md +2 -2
  51. package/templates/docs/02-reference/question-types/07-matrix-cfm.md +44 -30
  52. package/templates/docs/02-reference/question-types/08-matrix-csat.md +4 -26
  53. package/templates/docs/02-reference/question-types/09-matrix-rating.md +29 -13
  54. package/templates/docs/02-reference/question-types/10-slider-matrix.md +15 -4
  55. package/templates/docs/02-reference/question-types/11-file-upload.md +13 -2
  56. package/templates/docs/02-reference/question-types/12-heatmap.md +59 -0
  57. package/templates/docs/02-reference/question-types/13-rank-order.md +101 -0
  58. package/templates/docs/02-reference/question-types/README.md +86 -47
  59. package/templates/docs/02-reference/routing-table.md +33 -18
  60. package/templates/docs/02-reference/value-derivation.md +63 -0
  61. package/templates/docs/03-ui-specs/00-question-shell.md +19 -88
  62. package/templates/docs/03-ui-specs/01-rating.md +12 -54
  63. package/templates/docs/03-ui-specs/02-radio.md +21 -33
  64. package/templates/docs/03-ui-specs/03-text.md +2 -2
  65. package/templates/docs/03-ui-specs/04-csat.md +38 -33
  66. package/templates/docs/03-ui-specs/05-rating-scale.md +21 -18
  67. package/templates/docs/03-ui-specs/06-slider.md +3 -1
  68. package/templates/docs/03-ui-specs/07-matrix-cfm.md +24 -21
  69. package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +17 -45
  70. package/templates/docs/03-ui-specs/09-slider-matrix.md +1 -1
  71. package/templates/docs/03-ui-specs/10-file-upload.md +1 -1
  72. package/templates/docs/03-ui-specs/11-text-and-media.md +29 -29
  73. package/templates/docs/03-ui-specs/12-survey-chrome.md +20 -14
  74. package/templates/docs/03-ui-specs/13-heatmap.md +73 -0
  75. package/templates/docs/03-ui-specs/14-rank-order.md +59 -0
  76. package/templates/docs/03-ui-specs/README.md +13 -13
  77. package/templates/docs/03-ui-specs/shared/custom-slider-track.md +2 -2
  78. package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +5 -0
  79. package/templates/docs/MANIFEST.json +451 -69
  80. package/templates/docs/index.md +80 -29
  81. package/templates/docs/templates/Question.tsx +221 -154
  82. package/templates/docs/templates/deploy-to-aws.sh +114 -0
  83. package/templates/docs/templates/heatmapCoords.ts +58 -0
  84. package/templates/docs/templates/implementation_plan.md +108 -69
  85. package/templates/docs/templates/survey-inventory.schema.json +72 -0
  86. package/templates/docs/templates/verify-agent-build.sh +53 -0
  87. package/templates/docs/01-components/04-csat-scale.md +0 -40
  88. package/templates/docs/02-question-types/01-rating.md +0 -44
package/dist/index.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- import React from 'react';
2
-
3
1
  /**
4
2
  * Enum representing all action types supported by the survey SDK dispatcher.
5
3
  */
@@ -7,650 +5,510 @@ declare enum ACTIONS {
7
5
  NEXT = "NEXT",
8
6
  PREVIOUS = "PREVIOUS",
9
7
  SUBMIT = "SUBMIT",
10
- CHANGE = "CHANGE"
8
+ START = "START",
9
+ CHANGE = "CHANGE",
10
+ SCROLL = "SCROLL",
11
+ RECORD_QUESTION_VIEW = "RECORD_QUESTION_VIEW"
11
12
  }
12
13
 
13
- /**
14
- * Visual display type for scale/rating input controls.
15
- * Determines how individual answer options are rendered.
16
- *
17
- * - `'emoji'` — Sentiment emoji faces (😞 → 😐 → 😊)
18
- * - `'star'` — Star icons (☆ → ★)
19
- * - `'radio'` — Standard radio-button circles
20
- * - `'numbered'` — Numeric badge buttons (1, 2, 3 …)
21
- * - `'number'` — Alias for `'numbered'` (legacy value from API)
22
- * - `'dropdown'` — Collapsed select dropdown
23
- * - `'selectbox'` — Expanded list of selectable cards
24
- * - `'graphics'` — Continuous slider with emoji thumb
25
- */
26
- type SurveyButtonType = 'emoji' | 'star' | 'radio' | 'numbered' | 'number' | 'dropdown' | 'selectbox' | 'graphics';
27
- /**
28
- * A single selectable option used by rating, radio, CSAT, and matrix question types.
29
- */
30
- type SurveyOption = {
31
- /**
32
- * Unique identifier for this option, sourced from the API's `answerDetail.id`.
33
- * Falls back to the option's index position as a string if the API omits it.
34
- */
14
+ /** Logic filter and rule types shared by skip logic and display logic. */
15
+ type LogicFilterValue = string | number;
16
+ type CustomFieldType = 'TEXT' | 'TEXT_MULTI' | 'TEXTAREA' | 'NUMBER' | 'PICKLIST' | 'PICKLIST_MULTISELECT' | 'DATETIME';
17
+ type LogicConditionEntity = {
35
18
  id: string;
36
- /** The text label displayed to the respondent */
37
- label: string;
38
- /** The underlying value stored in the answer payload when this option is selected */
39
- value: string | number | null;
40
- /** Optional color hint (e.g. NPS traffic-light hex, or HSL scale color) */
41
- color?: string;
19
+ entityType: 'QUESTION';
20
+ answerType?: string;
21
+ } | {
22
+ id: string;
23
+ entityType: 'CUSTOM_FIELD';
24
+ fieldType: CustomFieldType;
25
+ assetClass?: string;
42
26
  };
43
- /**
44
- * Fields present on every question variant.
45
- *
46
- * All question-specific types extend this via intersection (`&`).
47
- */
48
- type QuestionBase = {
49
- /**
50
- * Unique identifier for this question.
51
- *
52
- * ⚠️ CRITICAL: Set this as the `id` attribute on the outermost DOM element
53
- * so the SDK's scroll-to-error logic can find it via `document.getElementById`.
54
- */
27
+ /** Option-scoped entity for rank-order logic leaves. */
28
+ type LogicSubConditionEntity = {
55
29
  id: string;
56
- /**
57
- * Question text — may contain HTML markup.
58
- * Always render with `dangerouslySetInnerHTML` or an HTML-safe renderer.
59
- */
60
- text: string;
61
- /**
62
- * Optional description / supplementary instruction text — may contain HTML markup.
63
- * Rendered below the main question text.
64
- */
65
- description?: string;
66
- /** Whether the respondent must answer this question before proceeding */
67
- required?: boolean;
68
- /** Localised error message shown when a required question is left unanswered */
69
- requiredErrorMessage?: string;
70
- /**
71
- * Ordinal position of this question in the survey (1-indexed).
72
- * Useful for displaying question numbers in the UI.
73
- */
74
- questionNumber?: number;
75
- /**
76
- * URL of a media asset displayed alongside the question (container image/video).
77
- * This field is present on ANY question type that has an attached container asset —
78
- * not just TEXT_AND_MEDIA questions.
79
- */
80
- containerMediaUrl?: string;
81
- /**
82
- * MIME type of the container asset.
83
- * Use this to decide between `<img>` and `<video>` rendering.
84
- */
85
- containerMediaMimeType?: string;
86
- /**
87
- * Layout alignment of the container media relative to the question text.
88
- * Sourced from the `QUESTION_CONTAINER_MEDIA_ALIGNMENT` question config.
89
- * Common values: `'LEFT_CENTER'`, `'RIGHT_CENTER'`, `'TOP'`, `'BOTTOM'`
90
- */
91
- containerMediaAlignment?: string;
92
- /**
93
- * Width of the container media as a percentage of the question card width.
94
- * Sourced from the `TEXT_AND_MEDIA_SIZE` question config.
95
- * e.g. `50` means the media takes up 50% of the width.
96
- */
97
- containerMediaSize?: number;
30
+ entityType: 'OPTION';
98
31
  };
99
-
100
- /**
101
- * NPS Rating question — a 0-to-10 numeric badge scale.
102
- *
103
- * API source: `SCALE` answerType with `SCALE_TYPE=TEN_POINT` config (or `NPS_SCALE`).
104
- * Answer shape: `number` — the selected badge value (e.g. `7`).
105
- *
106
- * The `options` array is auto-generated (0–10) if the API omits it;
107
- * each option carries a color from the NPS traffic-light palette
108
- * (red for 0–6, amber for 7–8, green for 9–10).
109
- */
110
- type RatingQuestion = QuestionBase & {
111
- type: 'rating';
112
- /** Selectable rating options (0–10), each with an NPS traffic-light color */
113
- options: SurveyOption[];
114
- /** Label shown at the left/low end of the scale (e.g. "Not Likely") */
115
- minLabel?: string;
116
- /** Label shown at the middle of the scale (e.g. "Neutral") */
117
- midLabel?: string;
118
- /** Label shown at the right/high end of the scale (e.g. "Extremely Likely") */
119
- maxLabel?: string;
120
- /**
121
- * Fractional position index for the mid label within the option list.
122
- * Used to compute the CSS `left` percentage offset of the mid-label element.
123
- * Formula: `(midLabelIndex / (options.length - 1)) * 100`%
124
- */
125
- midLabelIndex?: number;
126
- /** Whether the scale options should be rendered in reverse order (high → low) */
127
- reverseScaleOrder?: boolean;
128
- /** Visual style for each option button */
129
- buttonVariant?: 'radio' | 'numbered' | 'emoji';
32
+ type LogicFilterGroup = {
33
+ filterType: 'AND' | 'OR';
34
+ filters: LogicFilterNode[];
130
35
  };
131
-
132
- /**
133
- * Multiple Choice Question (MCQ) — a single-select radio list.
134
- *
135
- * API source: `MCQ` answerType (and any unrecognised answerType as a safe fallback).
136
- * Answer shape: `string | number` — the `.value` of the selected option.
137
- */
138
- type RadioQuestion = QuestionBase & {
139
- type: 'radio';
140
- /** Selectable answer choices rendered as radio buttons or option cards */
141
- options: SurveyOption[];
142
- /**
143
- * Whether the respondent can select more than one option.
144
- * When `true`, the answer shape becomes `(string | number)[]`.
145
- */
146
- isMultiSelect?: boolean;
36
+ type LogicFilterLeaf = {
37
+ filterType: string;
38
+ field?: string;
39
+ values?: LogicFilterValue[];
40
+ details?: {
41
+ conditionEntity?: LogicConditionEntity;
42
+ subConditionEntity?: LogicSubConditionEntity;
43
+ valueAdditional?: {
44
+ timezone?: string;
45
+ };
46
+ };
47
+ };
48
+ type LogicFilterNode = LogicFilterGroup | LogicFilterLeaf;
49
+ type SkipLogic = {
50
+ id: string;
51
+ skipTo: {
52
+ id: string;
53
+ entityType: 'QUESTION' | 'END_OF_SURVEY';
54
+ };
55
+ condition: LogicFilterGroup;
56
+ };
57
+ type DisplayLogic = {
58
+ condition: LogicFilterGroup;
59
+ isDynamicAppearanceEnabled: boolean;
60
+ };
61
+ /** Sub-entity logic (options, statement rows, scale columns) — mapped from API sub-entity displayLogic. */
62
+ type AnswerLogic = {
63
+ condition: LogicFilterGroup;
64
+ };
65
+ type QuestionDisplayVariant = {
66
+ id: string;
67
+ questionText: string;
68
+ displayLogic?: DisplayLogic;
69
+ };
70
+ type QuestionWithLogics = {
71
+ skipLogics?: SkipLogic[];
72
+ displayLogic?: DisplayLogic;
73
+ displayVariants?: QuestionDisplayVariant[];
147
74
  };
148
75
 
149
- /**
150
- * Text Field question — short or long free-text input.
151
- *
152
- * API source: `TEXTFIELD` answerType.
153
- * Answer shape: `string` — the raw text typed by the respondent.
154
- *
155
- * Both "Short Text Field" and "Long Text Field" from the survey builder
156
- * map to this type. UI components use `maxCharacterCount` to decide
157
- * between a single-line `<input>` and a multi-line `<textarea>`.
158
- */
159
- type TextQuestion = QuestionBase & {
160
- type: 'text';
161
- /** Maximum number of characters allowed; should be enforced client-side */
162
- maxCharacterCount?: number;
163
- /** Placeholder hint shown inside the empty input field */
164
- placeholder?: string;
165
- /**
166
- * Text input variant.
167
- * - `'short'` — Rendered as a single-line text input.
168
- * - `'long'` — Rendered as a multi-line textarea.
169
- */
170
- inputVariant?: 'short' | 'long';
76
+ type ContainerMedia = {
77
+ url?: string;
78
+ mimeType?: string;
79
+ alignment?: string;
80
+ size?: number;
81
+ };
82
+ type QuestionMedia = ContainerMedia & {
83
+ title?: string;
171
84
  };
172
85
 
173
- /**
174
- * A single row (sub-question) in a matrix question.
175
- * Each row represents an independent statement the respondent rates
176
- * by selecting one of the shared column options.
177
- */
178
- type MatrixRow = {
179
- /** Unique row ID — used as the key in the `Record<rowId, value>` answer map */
86
+ type StatementRow = {
180
87
  id: string;
181
- /** Primary statement text shown at the start of the row. May contain HTML. */
182
- text: string;
183
- /** Right-side statement for bipolar scales (e.g. "Agree" ↔ "Disagree") */
184
- rightText?: string;
88
+ statementText: string;
89
+ answerLogic?: AnswerLogic;
185
90
  };
186
- /**
187
- * A single column header in a matrix question.
188
- * Columns are shared across all rows; selecting a cell in a column records
189
- * that column's `value` for the corresponding row.
190
- */
191
- type MatrixColumn = {
192
- /** Unique column identifier */
91
+ type ScaleColumn = {
193
92
  id: string;
194
- /** Display label shown in the column header (e.g. "Strongly Agree") */
195
93
  label: string;
196
- /** Value recorded in the payload when this column is selected for any given row */
197
- value: string | number | null;
198
- /** Optional color hint — used by RATING_MATRIX scale columns (HSL or hex) */
199
- color?: string;
94
+ answerLogic?: AnswerLogic;
200
95
  };
201
- /**
202
- * CFM_MATRIX / CSAT_MATRIX — a grid of rows × columns where the respondent
203
- * selects exactly one column per row (or N/A).
204
- *
205
- * API sources: `CFM_MATRIX`, `CSAT_MATRIX` answerType.
206
- * Answer shape: `Record<rowId, columnValue | null>` — one entry per row.
207
- * - `null` means the respondent selected the N/A option for that row.
208
- *
209
- * Use `subType` to distinguish visual styling:
210
- * - `'CSAT_MATRIX'` → rendered with emoji/star/numbered buttons per cell.
211
- * - `'CFM_MATRIX'` → rendered as a Likert-style text-label grid.
212
- * - `'RATING_MATRIX'` → rendered with color-coded NPS-style rating buttons.
213
- */
214
- type MatrixQuestion = QuestionBase & {
215
- type: 'matrix';
216
- /** Original API sub-type — use this to apply the correct visual variant */
217
- subType: 'CFM_MATRIX' | 'CSAT_MATRIX' | 'RATING_MATRIX';
218
- /** Ordered list of row sub-questions (statements to rate) */
219
- rows: MatrixRow[];
220
- /**
221
- * Shared column header options (same columns appear for every row).
222
- * Columns with `value === null` represent the N/A column.
223
- */
224
- columns: MatrixColumn[];
225
- /** Visual display type for cell input controls (only applies to CSAT_MATRIX) */
226
- buttonType?: SurveyButtonType;
227
- /** Whether the last column is a Not Applicable (N/A) option */
228
- hasNotApplicable?: boolean;
229
- /** Whether the scale columns should be displayed in reverse order (high → low) */
230
- reverseScaleOrder?: boolean;
231
- /**
232
- * Anchor labels displayed above the scale columns at evenly distributed positions.
233
- * (e.g. `['Strongly Disagree', 'Neutral', 'Strongly Agree']`)
234
- */
235
- labels?: string[];
236
- /**
237
- * Layout format for the matrix.
238
- * - `'standard'` — All rows displayed as a grid at once.
239
- * - `'carousel'` — One row shown at a time with prev/next navigation.
240
- * - `'dropdown'` — Each row's answer is selected via a dropdown menu.
241
- */
242
- matrixFormat?: 'standard' | 'carousel' | 'dropdown';
243
- /**
244
- * Scale polarity for CFM_MATRIX.
245
- * - `'likert'` — Standard unipolar scale (e.g. Strongly Agree → Strongly Disagree).
246
- * - `'bipolar'` — Two-sided scale with opposite statements at each end.
247
- */
248
- matrixType?: 'likert' | 'bipolar';
249
- /**
250
- * Answer selection mode for CFM_MATRIX.
251
- * - `'single'` — One selection per row.
252
- * - `'multiple'` — Multiple selections allowed per row.
253
- */
254
- answerType?: 'single' | 'multiple';
255
- /** Whether to transpose the table (rows become columns and vice versa) */
256
- transposeTable?: boolean;
257
- /** Whether to repeat the column header row at regular intervals */
258
- repeatScale?: boolean;
259
- /** Whether to show the scale header row at all */
260
- enableScale?: boolean;
96
+
97
+ declare const QUESTION_TYPE: {
98
+ readonly MCQ: "MCQ";
99
+ readonly TEXTFIELD: "TEXTFIELD";
100
+ readonly NPS_SCALE: "NPS_SCALE";
101
+ readonly CFM_MATRIX: "CFM_MATRIX";
102
+ readonly CSAT_MATRIX: "CSAT_MATRIX";
103
+ readonly RATING_MATRIX: "RATING_MATRIX";
104
+ readonly SLIDER_MATRIX: "SLIDER_MATRIX";
105
+ readonly FILE_UPLOAD: "FILE_UPLOAD";
106
+ readonly TEXT_AND_MEDIA: "TEXT_AND_MEDIA";
107
+ readonly HEATMAP: "HEATMAP";
108
+ readonly RANK_ORDER: "RANK_ORDER";
261
109
  };
110
+ type QuestionType = (typeof QUESTION_TYPE)[keyof typeof QUESTION_TYPE];
262
111
 
263
- /**
264
- * RATING_MATRIX — a grid of rows × NPS-style rating columns.
265
- * Visually similar to `MatrixQuestion` (CSAT_MATRIX), but specifically
266
- * for rating scales where columns carry traffic-light colors and endpoint labels.
267
- *
268
- * API source: `RATING_MATRIX` answerType.
269
- * Answer shape: `Record<rowId, columnValue | null>` — one entry per row.
270
- * - `null` means the respondent selected the N/A option for that row.
271
- */
272
- type RatingMatrixQuestion = QuestionBase & {
273
- type: 'rating_matrix';
274
- /** Ordered list of row sub-questions (statements to rate) */
275
- rows: MatrixRow[];
276
- /**
277
- * Rating-scale column options — each may carry a `color` for visual emphasis.
278
- * Columns with `value === null` represent the N/A column.
279
- */
280
- columns: MatrixColumn[];
281
- /** Label for the lowest end of the rating scale (e.g. "Poor") */
112
+ /** Multiple-choice question (API: MCQ). */
113
+ type McqQuestion = {
114
+ type: typeof QUESTION_TYPE.MCQ;
115
+ id: string;
116
+ questionText: string;
117
+ questionDescription?: string;
118
+ questionHint?: string;
119
+ required: boolean;
120
+ requiredErrorMessage?: string;
121
+ questionNumber?: number;
122
+ containerMedia?: ContainerMedia;
123
+ referencedQuestionIds?: string[];
124
+ options: McqOption[];
125
+ selectionMode: 'single' | 'multiple';
126
+ displayFormat: 'list' | 'grid';
127
+ shuffleOptions: boolean;
128
+ columnCount?: number;
129
+ defaultOptionIds?: string[];
130
+ minSelections?: number;
131
+ maxSelections?: number;
132
+ answerConditionErrorMessage?: string;
133
+ };
134
+
135
+ type McqOption = {
136
+ id: string;
137
+ optionLabel: string;
138
+ answerLogic?: AnswerLogic;
139
+ };
140
+
141
+ /** NPS 0–10 scale question (API: NPS_SCALE). */
142
+ type NpsQuestion = {
143
+ type: typeof QUESTION_TYPE.NPS_SCALE;
144
+ id: string;
145
+ questionText: string;
146
+ questionDescription?: string;
147
+ questionHint?: string;
148
+ required: boolean;
149
+ requiredErrorMessage?: string;
150
+ questionNumber?: number;
151
+ containerMedia?: ContainerMedia;
152
+ referencedQuestionIds?: string[];
153
+ options: NpsScalePoint[];
282
154
  minLabel?: string;
283
- /** Label for the highest end of the rating scale (e.g. "Excellent") */
155
+ midLabel?: string;
284
156
  maxLabel?: string;
285
- /** Visual display type for each cell's input control */
286
- buttonType?: SurveyButtonType;
287
- /** Whether the last column is a Not Applicable (N/A) option */
288
- hasNotApplicable?: boolean;
289
- /** Whether the scale columns should be displayed in reverse order (high → low) */
290
- reverseScaleOrder?: boolean;
291
- /**
292
- * Anchor labels displayed above the scale columns at evenly distributed positions.
293
- * (e.g. `['Strongly Disagree', 'Neutral', 'Strongly Agree']`)
294
- */
295
- labels?: string[];
157
+ midLabelIndex?: number;
158
+ reverseScaleOrder: boolean;
159
+ buttonStyle: 'standard' | 'numbered' | 'emoji';
296
160
  };
297
-
298
- /**
299
- * A single row in a SLIDER_MATRIX question.
300
- * Each row carries its own independent slider range configuration.
301
- */
302
- type SliderMatrixRow = MatrixRow & {
303
- /** Minimum value of this row's slider track */
304
- min: number;
305
- /** Maximum value of this row's slider track */
306
- max: number;
307
- /** Step increment between selectable values (e.g. `1` for integers) */
308
- step: number;
309
- /** Optional initial position of the slider handle before interaction */
310
- defaultValue?: number;
161
+ type NpsScalePoint = {
162
+ id: string;
163
+ optionLabel: string;
311
164
  };
312
- /**
313
- * A discrete tick mark on a slider track, carrying a display label and color.
314
- * Used by `SliderMatrixQuestion.tickValues` for rich visual scales.
315
- */
316
- type TickValue = {
317
- /** Numeric position on the slider track */
318
- value: number;
319
- /** Display label shown at this tick (e.g. `"0"`, `"Neutral"`) */
320
- label: string;
321
- /** HSL or hex color for the tick / emoji at this position */
322
- color: string;
165
+
166
+ /** CSAT matrix grid (API: CSAT_MATRIX only). */
167
+ type CsatQuestion = {
168
+ type: typeof QUESTION_TYPE.CSAT_MATRIX;
169
+ id: string;
170
+ questionText: string;
171
+ questionDescription?: string;
172
+ questionHint?: string;
173
+ required: boolean;
174
+ requiredErrorMessage?: string;
175
+ questionNumber?: number;
176
+ containerMedia?: ContainerMedia;
177
+ referencedQuestionIds?: string[];
178
+ statementRows: CsatStatementRow[];
179
+ scaleColumns: CsatScaleColumn[];
180
+ scaleAnchorLabels?: string[];
181
+ displayStyle: 'emoji' | 'star' | 'standard' | 'numbered' | 'dropdown' | 'selectbox' | 'graphics';
182
+ hasNotApplicableOption: boolean;
183
+ reverseScaleOrder: boolean;
184
+ gridLayout: 'standard' | 'carousel' | 'dropdown';
323
185
  };
324
- /**
325
- * SLIDER_MATRIX — a grid of rows where each row has an independent range slider.
326
- * The respondent drags a handle to set a numeric position per row.
327
- *
328
- * API source: `SLIDER_MATRIX` answerType.
329
- * Answer shape: `Record<rowId, number | null>` — one numeric value per row,
330
- * or `null` when the respondent selects the N/A option for that row.
331
- */
332
- type SliderMatrixQuestion = QuestionBase & {
333
- type: 'slider_matrix';
334
- /** Rows — each row carries its own min/max/step slider configuration */
335
- rows: SliderMatrixRow[];
336
- /**
337
- * Anchor text labels displayed above the slider tracks at evenly distributed positions.
338
- * (e.g. `['Label 1', 'Label 3', 'Label 5']`)
339
- */
340
- labels?: string[];
341
- /**
342
- * Number of discrete tick marks rendered on the slider track.
343
- * Defaults to `10` if not set by the survey configuration.
344
- */
345
- ticks?: number;
346
- /**
347
- * Pre-calculated tick values with display labels and HSL color mapping.
348
- * The colors transition Red → Amber → Green from index 0 to the last tick.
349
- */
350
- tickValues?: TickValue[];
351
- /** Whether to show a numeric text input box alongside the slider handle */
352
- enableInputBox?: boolean;
353
- /** Whether to display the current value as a tooltip on the slider thumb */
354
- displayValues?: boolean;
355
- /** Whether to include a Not Applicable (N/A) option per row */
356
- enableNotApplicable?: boolean;
357
- /**
358
- * Whether this is a Graphics Slider (renders an emoji thumb instead of a plain handle).
359
- * When `'graphics'`, the slider thumb shows a sentiment emoji that changes with the value.
360
- */
361
- sliderType?: 'graphics';
186
+ type CsatStatementRow = StatementRow;
187
+ type CsatScaleColumn = ScaleColumn;
188
+
189
+ /** Free-text input (API: TEXTFIELD). */
190
+ type TextInputQuestion = {
191
+ type: typeof QUESTION_TYPE.TEXTFIELD;
192
+ id: string;
193
+ questionText: string;
194
+ questionDescription?: string;
195
+ questionHint?: string;
196
+ required: boolean;
197
+ requiredErrorMessage?: string;
198
+ questionNumber?: number;
199
+ containerMedia?: ContainerMedia;
200
+ referencedQuestionIds?: string[];
201
+ placeholder?: string;
202
+ maxCharacterCount?: number;
203
+ inputVariant: 'short' | 'long';
362
204
  };
363
205
 
364
- /**
365
- * Text and Media — a display-only informational card.
366
- * No answer is recorded for this type it is purely presentational.
367
- *
368
- * API source: `TEXT_AND_MEDIA` answerType.
369
- * ⚠️ Do NOT dispatch a CHANGE action for this question type.
370
- * ⚠️ This type is excluded from validation and response progress counting.
371
- *
372
- * The heading text is sourced from `answerDetails` where
373
- * `additional.textAndMediaFieldType === 'HEADER'`, not from `questionText`.
374
- */
375
- type TextAndMediaQuestion = QuestionBase & {
376
- type: 'text_and_media';
377
- /**
378
- * Public URL of the image or video asset to display.
379
- * Sourced from `questionContainerAssets[0].source`.
380
- */
381
- mediaUrl?: string;
382
- /**
383
- * MIME type of the media asset.
384
- * - `'image/*'` for photos.
385
- * - `'video/*'` for video clips.
386
- * Use this to decide between `<img>` and `<video>` rendering.
387
- */
388
- mediaMimeType?: 'image/*' | 'video/*' | string;
389
- /** Optional caption or alt text rendered beneath the media asset */
390
- mediaTitle?: string;
391
- /**
392
- * Layout position of the media relative to the text content.
393
- * Sourced from the `TEXT_AND_MEDIA_ALIGNMENT` question config.
394
- * (e.g. `'BOTTOM_LEFT'`, `'TOP_CENTER'`, `'LEFT_CENTER'`)
395
- */
396
- mediaAlignment?: string;
397
- /**
398
- * Width of the media container as a percentage of the card width.
399
- * Sourced from the `TEXT_AND_MEDIA_SIZE` question config.
400
- * (e.g. `50` means the image takes up 50% of the width)
401
- */
402
- mediaSize?: number;
206
+ /** CFM matrix grid (API: CFM_MATRIX). */
207
+ type CfmMatrixQuestion = {
208
+ type: typeof QUESTION_TYPE.CFM_MATRIX;
209
+ id: string;
210
+ questionText: string;
211
+ questionDescription?: string;
212
+ questionHint?: string;
213
+ required: boolean;
214
+ requiredErrorMessage?: string;
215
+ questionNumber?: number;
216
+ containerMedia?: ContainerMedia;
217
+ referencedQuestionIds?: string[];
218
+ statementRows: CfmMatrixStatementRow[];
219
+ scaleColumns: CfmMatrixScaleColumn[];
220
+ statementLayout: 'likert' | 'bipolar';
221
+ selectionMode: 'single' | 'multiple';
222
+ gridLayout: 'standard' | 'carousel' | 'dropdown';
223
+ transposeTable: boolean;
224
+ repeatColumnHeaders: boolean;
225
+ hasNotApplicableOption: boolean;
226
+ showColumnHeaders: boolean;
227
+ scaleAnchorLabels?: string[];
403
228
  };
229
+ type CfmMatrixStatementRow = StatementRow & {
230
+ oppositeStatementText?: string;
231
+ };
232
+ type CfmMatrixScaleColumn = ScaleColumn;
404
233
 
405
- /**
406
- * CSAT Rating — a short customer satisfaction scale, typically 1–5.
407
- * Usually rendered with emoji face icons (😞 → 😐 → 😊).
408
- *
409
- * API source: `SCALE` answerType with `SCALE_TYPE=CSAT` config,
410
- * or heuristically detected when the option count is ≤ 5.
411
- * Answer shape: `string | number | null` — the selected satisfaction value,
412
- * or `null` when the respondent selects the N/A option.
413
- */
414
- type CsatQuestion = QuestionBase & {
415
- type: 'csat';
416
- /**
417
- * Selectable satisfaction options — usually 1 to 5.
418
- * The UI should render these as emoji/face icons rather than numeric badges.
419
- */
420
- options: SurveyOption[];
421
- /** Label for the lowest satisfaction level (e.g. "Very Dissatisfied") */
234
+ /** NPS-style rating matrix grid (API: RATING_MATRIX). */
235
+ type RatingMatrixQuestion = {
236
+ type: typeof QUESTION_TYPE.RATING_MATRIX;
237
+ id: string;
238
+ questionText: string;
239
+ questionDescription?: string;
240
+ questionHint?: string;
241
+ required: boolean;
242
+ requiredErrorMessage?: string;
243
+ questionNumber?: number;
244
+ containerMedia?: ContainerMedia;
245
+ referencedQuestionIds?: string[];
246
+ statementRows: RatingMatrixStatementRow[];
247
+ scaleColumns: RatingMatrixScaleColumn[];
248
+ scaleAnchorLabels?: string[];
422
249
  minLabel?: string;
423
- /** Label for the highest satisfaction level (e.g. "Very Satisfied") */
424
250
  maxLabel?: string;
425
- /** Visual display type for the scale options */
426
- buttonType?: SurveyButtonType;
427
- /** Whether the user can select an N/A (Not Applicable) option */
428
- hasNotApplicable?: boolean;
429
- /** Whether the options should be displayed in reverse order (high → low) */
430
- reverseScaleOrder?: boolean;
431
- /**
432
- * Where the min/max labels are positioned relative to the scale buttons.
433
- * - `'top'` — Labels appear above the scale
434
- * - `'bottom'` — Labels appear below the scale
435
- * - `'hidden'` — Labels are not shown
436
- */
437
- labelPosition?: 'top' | 'bottom' | 'hidden';
251
+ displayStyle: 'emoji' | 'star' | 'standard' | 'numbered' | 'dropdown' | 'selectbox' | 'graphics';
252
+ hasNotApplicableOption: boolean;
253
+ reverseScaleOrder: boolean;
254
+ gridLayout: 'standard' | 'carousel' | 'dropdown';
438
255
  };
256
+ type RatingMatrixStatementRow = StatementRow;
257
+ type RatingMatrixScaleColumn = ScaleColumn;
439
258
 
440
- /**
441
- * Standalone Slider — a single continuous range input.
442
- * The respondent drags a handle to set a numeric value along a track.
443
- *
444
- * API source: `SCALE` answerType with `INPUT_TYPE=SLIDER` questionConfig.
445
- * Answer shape: `number` — the position of the slider handle on the track.
446
- */
447
- type SliderQuestion = QuestionBase & {
448
- type: 'slider';
449
- /** Minimum value at the left end of the slider track */
259
+ /** Slider matrix grid — one slider per row (API: SLIDER_MATRIX). */
260
+ type SliderMatrixQuestion = {
261
+ type: typeof QUESTION_TYPE.SLIDER_MATRIX;
262
+ id: string;
263
+ questionText: string;
264
+ questionDescription?: string;
265
+ questionHint?: string;
266
+ required: boolean;
267
+ requiredErrorMessage?: string;
268
+ questionNumber?: number;
269
+ containerMedia?: ContainerMedia;
270
+ referencedQuestionIds?: string[];
271
+ statementRows: SliderMatrixStatementRow[];
272
+ scaleAnchorLabels?: string[];
273
+ ticks: {
274
+ count: number;
275
+ marks: SliderMatrixTickMark[];
276
+ };
277
+ enableInputBox: boolean;
278
+ displayValues?: boolean;
279
+ hasNotApplicableOption: boolean;
280
+ sliderStyle?: 'standard' | 'graphics';
281
+ };
282
+ type SliderMatrixStatementRow = StatementRow & {
450
283
  min: number;
451
- /** Maximum value at the right end of the slider track */
452
284
  max: number;
453
- /** Step increment between selectable positions (e.g. `1` for whole numbers) */
454
285
  step: number;
455
- /** Optional initial position of the slider handle before interaction */
456
286
  defaultValue?: number;
457
- /** Label displayed at the minimum (left) end of the track */
458
- minLabel?: string;
459
- /** Label displayed at the maximum (right) end of the track */
460
- maxLabel?: string;
461
- /** Whether to show a numeric text input box alongside the slider handle */
462
- enableInputBox?: boolean;
463
- /** Whether to display the current value as a floating tooltip on the thumb */
464
- displayValues?: boolean;
465
287
  };
466
-
467
- /**
468
- * Rating Scale — a star, emoji, or icon-based rating question (e.g. 1–5 stars).
469
- *
470
- * Unlike the NPS `'rating'` type, this does NOT apply traffic-light colors to options
471
- * and is visually rendered as stars, emojis, thumbs, or similar icons.
472
- *
473
- * API source: `SCALE` answerType with `SCALE_TYPE=STAR`, `SCALE_TYPE=EMOJI`,
474
- * or `SCALE_TYPE=FIVE_POINT` config.
475
- * Answer shape: `number` — the selected star/icon value.
476
- */
477
- type RatingScaleQuestion = QuestionBase & {
478
- type: 'rating_scale';
479
- /**
480
- * Selectable rating options (typically 1–5 or 1–10).
481
- * These carry no NPS colors — the UI should render them as stars or custom icons.
482
- */
483
- options: SurveyOption[];
484
- /** Label for the lowest rating end (e.g. "Poor") */
485
- minLabel?: string;
486
- /** Label for the midpoint of the scale (e.g. "Average") */
487
- midLabel?: string;
488
- /** Label for the highest rating end (e.g. "Excellent") */
489
- maxLabel?: string;
490
- /**
491
- * Fractional position index for the mid label within the option list.
492
- * Used to compute the CSS `left` percentage offset of the mid-label element.
493
- * Formula: `(midLabelIndex / (options.length - 1)) * 100`%
494
- */
495
- midLabelIndex?: number;
496
- /** Whether the scale options should be displayed in reverse order (high → low) */
497
- reverseScaleOrder?: boolean;
498
- /**
499
- * The specific icon style used for this scale.
500
- * - `'star'` — Classic star icons
501
- * - `'emoji'` — Sentiment emoji faces
502
- */
503
- scaleStyle?: 'star' | 'emoji';
288
+ type SliderMatrixTickMark = {
289
+ tickPosition: number;
290
+ tickLabel: string;
504
291
  };
505
292
 
506
- /**
507
- * A file uploaded by the respondent in response to a `FILE_UPLOAD` question.
508
- * This is the shape that should be passed to `onSelect` after a successful upload.
509
- *
510
- * @example
511
- * ```ts
512
- * const handleUpload = (file: File) => {
513
- * uploadToServer(file).then((result) => {
514
- * onSelect([{ id: result.id, name: file.name, mediaUrl: result.url }]);
515
- * });
516
- * };
517
- * ```
518
- */
293
+ /** File attachment question (API: FILE_UPLOAD). */
294
+ type FileUploadQuestion = {
295
+ type: typeof QUESTION_TYPE.FILE_UPLOAD;
296
+ id: string;
297
+ questionText: string;
298
+ questionDescription?: string;
299
+ questionHint?: string;
300
+ required: boolean;
301
+ requiredErrorMessage?: string;
302
+ questionNumber?: number;
303
+ containerMedia?: ContainerMedia;
304
+ referencedQuestionIds?: string[];
305
+ uploadMessage?: string;
306
+ supportedFileFormats: string[];
307
+ maxFileCount?: number;
308
+ fileSizeLimit?: number;
309
+ fileSizeLimitType: 'PER_FILE' | 'IN_TOTAL';
310
+ };
519
311
  type UploadedFile = {
520
- /** Unique asset ID returned by the upload server */
521
312
  id: string;
522
- /** Original filename of the uploaded file */
523
313
  name: string;
524
- /** Public URL to access the uploaded file */
525
314
  mediaUrl: string;
526
- /** MIME type of the uploaded file (e.g. `'image/png'`, `'application/pdf'`) */
527
315
  mimeType?: string;
528
- /** File size in bytes */
529
316
  size?: number;
530
317
  };
531
- /**
532
- * File Upload question prompts the respondent to attach one or more files.
533
- *
534
- * API source: `FILE_UPLOAD` answerType.
535
- * Answer shape: `UploadedFile[]` — an array of successfully uploaded file descriptors.
536
- * Submit target: `quesIdVsAttachmentDetails[questionId]` (NOT `questionToAnswers`).
537
- */
538
- type FileUploadQuestion = QuestionBase & {
539
- type: 'file_upload';
540
- /**
541
- * Custom instruction text displayed above the upload area.
542
- * May contain HTML markup; render with `dangerouslySetInnerHTML`.
543
- */
544
- uploadMessage?: string;
545
- /**
546
- * List of accepted file extensions in uppercase without dots (e.g. `['PDF', 'PNG', 'DOCX']`).
547
- * Use these to set the `accept` attribute on the `<input type="file">` element.
548
- */
549
- supportedFileFormats?: string[];
550
- /**
551
- * Maximum number of files the respondent can attach to this question.
552
- * If `undefined`, no limit is enforced by the SDK.
553
- */
554
- maxFileCount?: number;
555
- /**
556
- * Maximum file size in megabytes (MB).
557
- * Applies either per-file or in total, depending on `fileSizeLimitType`.
558
- */
559
- fileSizeLimit?: number;
560
- /**
561
- * Determines how `fileSizeLimit` is applied.
562
- * - `'PER_FILE'` — Each individual file must not exceed `fileSizeLimit` MB.
563
- * - `'IN_TOTAL'` — The combined size of all uploads must not exceed `fileSizeLimit` MB.
564
- */
565
- fileSizeLimitType?: 'PER_FILE' | 'IN_TOTAL';
318
+
319
+ /** Display-only text and media card (API: TEXT_AND_MEDIA). No answer recorded. */
320
+ type TextAndMediaQuestion = {
321
+ type: typeof QUESTION_TYPE.TEXT_AND_MEDIA;
322
+ id: string;
323
+ questionText: string;
324
+ questionDescription?: string;
325
+ questionHint?: string;
326
+ required: boolean;
327
+ requiredErrorMessage?: string;
328
+ questionNumber?: number;
329
+ referencedQuestionIds?: string[];
330
+ media?: QuestionMedia;
566
331
  };
567
332
 
568
- /**
569
- * Discriminated union of all question types surfaced by the SDK.
570
- */
571
- type SurveyQuestion = RatingQuestion | RadioQuestion | TextQuestion | MatrixQuestion | RatingMatrixQuestion | SliderMatrixQuestion | TextAndMediaQuestion | CsatQuestion | SliderQuestion | RatingScaleQuestion | FileUploadQuestion;
572
- /**
573
- * A single survey page containing an ordered list of questions.
574
- */
575
- type SurveyPageData = {
576
- /** Unique page identifier */
333
+ type HeatmapRegion = {
334
+ id: string;
335
+ label: string;
336
+ x: number;
337
+ y: number;
338
+ width: number;
339
+ height: number;
340
+ color?: string;
341
+ };
342
+ /** Image click-map question (API: HEATMAP). */
343
+ type HeatmapQuestion = {
344
+ type: typeof QUESTION_TYPE.HEATMAP;
345
+ id: string;
346
+ questionText: string;
347
+ questionDescription?: string;
348
+ questionHint?: string;
349
+ required: boolean;
350
+ requiredErrorMessage?: string;
351
+ questionNumber?: number;
352
+ imageUrl: string;
353
+ regions: HeatmapRegion[];
354
+ maxClicksAllowed: number;
355
+ referenceWidth: number;
356
+ referenceHeight: number;
357
+ };
358
+
359
+ type RankOrderInteractionMode = 'dropdown' | 'dragAndDrop';
360
+ type RankOrderOptionDisplay = 'textOnly' | 'imageOnly' | 'textAndImage';
361
+ type RankOrderOption = {
362
+ id: string;
363
+ optionLabel: string;
364
+ imageUrl?: string;
365
+ previewImageUrl?: string;
366
+ answerLogic?: AnswerLogic;
367
+ };
368
+ /** Rank-order question (API: RANK_ORDER). */
369
+ type RankOrderQuestion = {
370
+ type: typeof QUESTION_TYPE.RANK_ORDER;
371
+ id: string;
372
+ questionText: string;
373
+ questionDescription?: string;
374
+ questionHint?: string;
375
+ required: boolean;
376
+ requiredErrorMessage?: string;
377
+ questionNumber?: number;
378
+ containerMedia?: ContainerMedia;
379
+ referencedQuestionIds?: string[];
380
+ options: RankOrderOption[];
381
+ interactionMode: RankOrderInteractionMode;
382
+ optionDisplay: RankOrderOptionDisplay;
383
+ requireRankAll: boolean;
384
+ shuffleOptions: boolean;
385
+ };
386
+
387
+ type SpecialPage = {
388
+ id: string;
389
+ header: string;
390
+ title?: string;
391
+ description?: string;
392
+ ctaLabel?: string;
393
+ disabled?: boolean;
394
+ displayLogic?: DisplayLogic;
395
+ };
396
+ type SurveyPhase = {
397
+ kind: 'intro';
398
+ } | {
399
+ kind: 'content';
400
+ pageIndex: number;
401
+ } | {
402
+ kind: 'end';
403
+ endPageId: string;
404
+ } | {
405
+ kind: 'paused';
406
+ } | {
407
+ kind: 'submitted';
408
+ } | {
409
+ kind: 'expired';
410
+ } | {
411
+ kind: 'quota_fulfilled';
412
+ };
413
+ type SurveyPhaseFlags = {
414
+ expired: boolean;
415
+ alreadyFilled: boolean;
416
+ quotaFulfilled: boolean;
417
+ paused: boolean;
418
+ };
419
+ type SurveyQuestion = (McqQuestion & QuestionWithLogics) | (NpsQuestion & QuestionWithLogics) | (CsatQuestion & QuestionWithLogics) | (TextInputQuestion & QuestionWithLogics) | (CfmMatrixQuestion & QuestionWithLogics) | (RatingMatrixQuestion & QuestionWithLogics) | (SliderMatrixQuestion & QuestionWithLogics) | (FileUploadQuestion & QuestionWithLogics) | (TextAndMediaQuestion & QuestionWithLogics) | (HeatmapQuestion & QuestionWithLogics) | (RankOrderQuestion & QuestionWithLogics);
420
+ type SurveyPage = {
577
421
  id: string;
578
- /** Optional page title displayed as a section header */
579
422
  title?: string;
580
- /** Ordered list of questions on this page */
581
423
  questions: SurveyQuestion[];
582
424
  };
583
- /**
584
- * A language option available for this survey.
585
- */
586
425
  type SurveyLanguage = {
587
- /** BCP-47 language code (e.g. `'en'`, `'de'`, `'fr'`) */
588
426
  code: string;
589
- /** Human-readable language name (e.g. `'English'`, `'Deutsch'`) */
590
427
  name: string;
591
428
  };
592
- /**
593
- * The fully parsed and normalised survey structure returned by the SDK.
594
- */
595
429
  type Survey = {
596
- /** Unique survey identifier */
597
430
  id: string;
598
- /** Active language code for this response session */
599
431
  language: string;
600
- /** All languages configured for this survey */
601
432
  languages: SurveyLanguage[];
602
- /** Ordered list of pages that make up the survey flow */
603
- pages: SurveyPageData[];
433
+ pages: SurveyPage[];
434
+ introPage?: SpecialPage;
435
+ endPages: SpecialPage[];
436
+ pausedPage?: SpecialPage;
437
+ phaseFlags: SurveyPhaseFlags;
604
438
  };
605
439
 
606
440
  /**
607
- * Answer value for matrix questions (CFM_MATRIX, CSAT_MATRIX, RATING_MATRIX, SLIDER_MATRIX).
608
- * Maps each row sub-question ID to the selected column value or slider position.
609
- * For multi-select grids, the value can be an array of selected column values.
610
- */
611
- type MatrixAnswerMap = Record<string, string | number | null | Array<string | number | null>>;
612
- /**
613
- * Union of all possible answer value types across all question variants.
614
- * - `string | number | null` — standard single-value questions (rating, radio, text, csat N/A)
615
- * - `MatrixAnswerMap` — grid questions (matrix, rating_matrix, slider_matrix)
441
+ * Row-level answers for matrix question types.
442
+ * Scale-matrix rows store selected column IDs (strings); slider-matrix rows store numbers.
616
443
  */
617
- type AnswerValue = string | number | null | MatrixAnswerMap | any[];
444
+ type MatrixRowAnswers = Record<string, string | number | null | Array<string | number | null>>;
445
+ type HeatmapClickPoint = {
446
+ id: string;
447
+ x: number;
448
+ y: number;
449
+ };
450
+ type HeatmapAnswer = HeatmapClickPoint[];
451
+ /** optionId → 1-based rank. Partial map allowed when requireRankAll is false. */
452
+ type RankOrderAnswers = Record<string, number>;
618
453
  /**
619
- * The final output result resolved after a successful submit response.
454
+ * Union of all possible answer values across question variants.
620
455
  */
456
+ type AnswerValue = string | string[] | number | null | MatrixRowAnswers | RankOrderAnswers | UploadedFileAnswer[] | HeatmapAnswer;
457
+ type UploadedFileAnswer = {
458
+ id: string;
459
+ name: string;
460
+ mediaUrl: string;
461
+ mimeType?: string;
462
+ size?: number;
463
+ };
464
+ /** Key-value mapping of question IDs to their answer values (client-selected ids or numbers). */
465
+ type SurveyAnswers = Record<string, AnswerValue>;
621
466
  type SubmitResult = {
622
467
  success: boolean;
623
468
  responseId: string;
624
469
  };
625
470
 
626
- /**
627
- * Union type representing all dispatch actions for the survey SDK.
628
- */
471
+ type SavePartialResponseOption = boolean | {
472
+ debounceMs?: number;
473
+ };
474
+
475
+ /** A single client-supplied custom field value. */
476
+ type CustomFieldValue = string | number | string[];
477
+ /** Client-supplied values keyed by custom field id (e.g. `_c_6a436c1244764c9d4a6ce2fc`). */
478
+ type CustomFieldValueMap = Record<string, CustomFieldValue>;
479
+
629
480
  type SurveyAction = {
630
481
  type: ACTIONS.NEXT | 'NEXT';
631
482
  } | {
632
483
  type: ACTIONS.PREVIOUS | 'PREVIOUS';
633
484
  } | {
634
485
  type: ACTIONS.SUBMIT | 'SUBMIT';
486
+ } | {
487
+ type: ACTIONS.START | 'START';
488
+ } | {
489
+ type: ACTIONS.SCROLL | 'SCROLL';
635
490
  } | {
636
491
  type: ACTIONS.CHANGE | 'CHANGE';
637
492
  payload: {
638
493
  questionId: string;
639
- value: AnswerValue;
494
+ answerValue: AnswerValue;
495
+ };
496
+ } | {
497
+ type: ACTIONS.RECORD_QUESTION_VIEW | 'RECORD_QUESTION_VIEW';
498
+ payload: {
499
+ questionIds: string[];
640
500
  };
641
501
  };
642
- /**
643
- * Configuration settings for useSurveySDK hook behavior and layout parameters.
644
- */
645
502
  type UseSurveySDKProps = {
646
503
  options?: {
647
504
  instanceId?: string;
648
505
  language?: string;
649
506
  placeholders?: Record<string, string>;
507
+ customFieldValues?: CustomFieldValueMap;
650
508
  debug?: boolean;
509
+ savePartialResponse?: SavePartialResponseOption;
651
510
  };
652
511
  };
653
- /** Return shape of the useSurveySDK hook — the agent integration contract. */
654
512
  type UseSurveySDKReturn = {
655
513
  surveyQueryResults: {
656
514
  data: Survey | null;
@@ -662,43 +520,70 @@ type UseSurveySDKReturn = {
662
520
  error: Error | null;
663
521
  isLoading: boolean;
664
522
  };
523
+ partialSaveResults: {
524
+ data: SubmitResult | null;
525
+ error: Error | null;
526
+ isLoading: boolean;
527
+ };
665
528
  state: {
529
+ phase: SurveyPhase;
666
530
  currentPageIndex: number;
667
531
  currentQuestions: SurveyQuestion[];
668
- values: Record<string, AnswerValue>;
532
+ answers: Record<string, AnswerValue>;
669
533
  validationErrors: Record<string, string>;
670
534
  progressPercentage: number;
535
+ totalQuestionsCount: number;
536
+ answeredQuestionsCount: number;
537
+ canGoBack: boolean;
538
+ primaryButtonType: 'next' | 'submit';
539
+ specialPage?: SpecialPage;
671
540
  };
672
541
  onAction: (action: SurveyAction) => void;
673
542
  };
674
543
 
675
544
  /**
676
545
  * The main entry-point custom React hook for the survey SDK.
677
- * Handles fetching survey configurations, active session state, validation,
678
- * page pagination, response submission, and user progress tracking.
679
- *
680
- * @param props Configuration settings for hook behavior and layout parameters.
681
- * @returns Unified state structures, submission indicators, and action triggers.
682
546
  */
683
547
  declare function useSurveySDK({ options }?: UseSurveySDKProps): UseSurveySDKReturn;
684
548
 
685
- /**
686
- * Extended 11-level CSAT emoji set.
687
- * Each entry is a pre-built React element with colour and sizing.
688
- */
689
- declare const CsatEmojiSet: Record<number, React.ReactNode>;
690
- /**
691
- * Maps a 0-based column index within a scale of `total` items
692
- * to the correct professional face icon from the 11-level set.
693
- *
694
- * Works for any scale length. Uses specific curated subsets for 3-6 lengths.
695
- */
696
- declare function getEmojiForIndex(index: number, total: number): React.ReactNode;
697
- /** Legacy 1–5 mapping kept for backward compatibility with CsatScale (standalone) */
698
- declare const CsatEmojiMapping: Record<number, React.ReactNode>;
699
- declare const CsatStarIcons: {
700
- filled: React.ReactNode;
701
- empty: React.ReactNode;
549
+ declare const QUESTION_ACTIVITY_STATE: {
550
+ readonly VIEWED: "VIEWED";
702
551
  };
703
552
 
704
- export { ACTIONS, type AnswerValue, CsatEmojiMapping, CsatEmojiSet, type CsatQuestion, CsatStarIcons, type FileUploadQuestion, type MatrixAnswerMap, type MatrixColumn, type MatrixQuestion, type MatrixRow, type QuestionBase, type RadioQuestion, type RatingMatrixQuestion, type RatingQuestion, type RatingScaleQuestion, type SliderMatrixQuestion, type SliderMatrixRow, type SliderQuestion, type Survey, type SurveyAction, type SurveyButtonType, type SurveyLanguage, type SurveyOption, type SurveyQuestion, type TextAndMediaQuestion, type TextQuestion, type TickValue, type UploadedFile, type UseSurveySDKProps, type UseSurveySDKReturn, getEmojiForIndex, useSurveySDK };
553
+ declare function formatAnswerForDisplay(question: SurveyQuestion, answerValue: AnswerValue | undefined): string;
554
+ declare function resolveSurveyQuestionPlaceholders(html: string, answers: SurveyAnswers, questionsById: Map<string, SurveyQuestion>): string;
555
+
556
+ type LogicContext = {
557
+ answers: SurveyAnswers;
558
+ questionsById: ReadonlyMap<string, SurveyQuestion>;
559
+ customFieldValues?: Readonly<CustomFieldValueMap>;
560
+ };
561
+
562
+ declare function getVisibleStatementRows(question: SurveyQuestion, context: LogicContext): StatementRow[];
563
+ declare function getVisibleMcqOptions(question: SurveyQuestion, context: LogicContext): McqOption[];
564
+ declare function getVisibleRankOrderOptions(question: SurveyQuestion, context: LogicContext): RankOrderOption[];
565
+ declare function getVisibleScaleColumns(question: SurveyQuestion, context: LogicContext): ScaleColumn[];
566
+
567
+ declare function getVisibleStatementRowsForAnswers(question: SurveyQuestion, answers: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): StatementRow[];
568
+ declare function getVisibleMcqOptionsForAnswers(question: SurveyQuestion, answers: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): McqOption[];
569
+ declare function getVisibleRankOrderOptionsForAnswers(question: SurveyQuestion, answers: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): RankOrderOption[];
570
+ declare function getVisibleScaleColumnsForAnswers(question: SurveyQuestion, answers: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): ScaleColumn[];
571
+ declare function getVisibleMatrixItemsForAnswers(question: SurveyQuestion, answers: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): {
572
+ statementRows: StatementRow[];
573
+ scaleColumns: ScaleColumn[];
574
+ };
575
+
576
+ declare function resolveQuestionDisplayText(question: SurveyQuestion, context: LogicContext): string;
577
+ declare function applyQuestionDisplayVariants(questions: SurveyQuestion[], context: LogicContext): SurveyQuestion[];
578
+
579
+ declare function computeActivePathQuestionNumbers(pages: SurveyPage[], values: SurveyAnswers, allQuestions: SurveyQuestion[], customFieldValues?: CustomFieldValueMap): Map<string, number>;
580
+ declare function applyActivePathQuestionNumbers(questions: SurveyQuestion[], numbers: Map<string, number>): SurveyQuestion[];
581
+
582
+ declare function matrixColumnStoredValue(column: ScaleColumn): string | null;
583
+
584
+ declare function normalizeRankOrderAnswers(value: unknown): RankOrderAnswers;
585
+ declare function buildRankOrderFromOrderedOptionIds(optionIds: string[]): RankOrderAnswers;
586
+ declare function getOrderedOptionIdsFromRanks(answers: RankOrderAnswers, optionIds: string[]): string[];
587
+ declare function assignRankWithoutDuplicates(currentAnswers: RankOrderAnswers, optionId: string, rank: number | undefined): RankOrderAnswers;
588
+
589
+ export { ACTIONS, type AnswerLogic, type AnswerValue, type CfmMatrixQuestion, type CfmMatrixScaleColumn, type CfmMatrixStatementRow, type ContainerMedia, type CsatQuestion, type CsatScaleColumn, type CsatStatementRow, type CustomFieldType, type CustomFieldValue, type CustomFieldValueMap, type DisplayLogic, type FileUploadQuestion, type HeatmapAnswer, type HeatmapClickPoint, type HeatmapQuestion, type HeatmapRegion, type LogicConditionEntity, type MatrixRowAnswers, type McqOption, type McqQuestion, type NpsQuestion, type NpsScalePoint, QUESTION_ACTIVITY_STATE, QUESTION_TYPE, type QuestionDisplayVariant, type QuestionMedia, type QuestionType, type RankOrderAnswers, type RankOrderInteractionMode, type RankOrderOption, type RankOrderOptionDisplay, type RankOrderQuestion, type RatingMatrixQuestion, type RatingMatrixScaleColumn, type RatingMatrixStatementRow, type SavePartialResponseOption, type ScaleColumn, type SkipLogic, type SliderMatrixQuestion, type SliderMatrixStatementRow, type SliderMatrixTickMark, type SpecialPage, type StatementRow, type Survey, type SurveyAction, type SurveyAnswers, type SurveyLanguage, type SurveyPage, type SurveyPhase, type SurveyPhaseFlags, type SurveyQuestion, type TextAndMediaQuestion, type TextInputQuestion, type UploadedFile, type UploadedFileAnswer, type UseSurveySDKProps, type UseSurveySDKReturn, applyActivePathQuestionNumbers, applyQuestionDisplayVariants, assignRankWithoutDuplicates, buildRankOrderFromOrderedOptionIds, computeActivePathQuestionNumbers, formatAnswerForDisplay, getOrderedOptionIdsFromRanks, getVisibleMatrixItemsForAnswers, getVisibleMcqOptions, getVisibleMcqOptionsForAnswers, getVisibleRankOrderOptions, getVisibleRankOrderOptionsForAnswers, getVisibleScaleColumns, getVisibleScaleColumnsForAnswers, getVisibleStatementRows, getVisibleStatementRowsForAnswers, matrixColumnStoredValue, normalizeRankOrderAnswers, resolveQuestionDisplayText, resolveSurveyQuestionPlaceholders, useSurveySDK };