@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
@@ -1,26 +1,31 @@
1
- # Rating Scale Question (Stars/Emoji)
1
+ # Star Rating Question (Stars/Emoji)
2
2
 
3
- > **Type**: `'rating_scale'` | **API Source**: `SCALE` with `SCALE_TYPE=STAR/EMOJI/FIVE_POINT`
4
- > **Mapper**: `ratingMapper.ts` (rating_scale branch) | **Component**: `RatingScale`
3
+ > **Type**: `'star_rating'` | **API Source**: page `RATING`
4
+ > **SDK type file**: `fetchSurvey/types/starRating.ts` | **Component**: `RatingScale`
5
5
 
6
6
  ## TypeScript Type
7
7
 
8
8
  ```typescript
9
- type RatingScaleQuestion = QuestionBase & {
10
- type: 'rating_scale';
11
- options: SurveyOption[]; // Typically 1-5 or 1-10 (no NPS colors)
9
+ type StarRatingQuestion = {
10
+ type: 'star_rating';
11
+ id: string;
12
+ questionText: string;
13
+ options: StarRatingPoint[];
12
14
  minLabel?: string;
13
15
  midLabel?: string;
14
16
  maxLabel?: string;
15
17
  midLabelIndex?: number;
16
- reverseScaleOrder?: boolean;
17
- scaleStyle?: 'star' | 'emoji';
18
+ reverseScaleOrder: boolean;
19
+ scaleStyle: 'star' | 'emoji';
20
+ required: boolean;
21
+ // ... shell fields
18
22
  };
19
23
  ```
20
24
 
21
25
  ## Answer Shape: `number`
22
26
 
23
- ## Key Difference from `'rating'`
27
+ ## Key Difference from `'nps'`
28
+
24
29
  - No NPS traffic-light colors on options
25
- - Rendered as stars, emojis, or plain icons — not numbered badges
26
- - Use `scaleStyle` to determine icon type
30
+ - Rendered as stars or emojis per `scaleStyle`
31
+ - See `03-ui-specs/05-rating-scale.md`
@@ -1,7 +1,7 @@
1
1
  # Slider Question (Single Range)
2
2
 
3
- > **Type**: `'slider'` | **API Source**: `SCALE` with `INPUT_TYPE=SLIDER`
4
- > **Mapper**: `ratingMapper.ts` (slider branch) | **Component**: `CustomSliderTrack` or native `<input type="range">`
3
+ > **Type**: `'slider'` | **API Source**: page `SLIDER`
4
+ > **Mapper**: `sliderMapper.ts` | **Component**: `CustomSliderTrack` or native `<input type="range">`
5
5
 
6
6
  ## TypeScript Type
7
7
 
@@ -1,43 +1,57 @@
1
- # Matrix CFM Question (Likert Grid)
1
+ # CFM Matrix Question (Likert Grid)
2
2
 
3
- > **Type**: `'matrix'` with `subType: 'CFM_MATRIX'` | **API Source**: `CFM_MATRIX`
4
- > **Mapper**: `cfmMatrixMapper.ts` | **Component**: `LikertMatrixScale`
3
+ > **Type**: `'CFM_MATRIX'` | **API Source**: `CFM_MATRIX`
4
+ > **SDK type file**: `fetchSurvey/types/cfmMatrix.ts` | **Component**: `LikertMatrixScale`
5
5
 
6
6
  ## TypeScript Type
7
7
 
8
8
  ```typescript
9
- type MatrixQuestion = QuestionBase & {
10
- type: 'matrix';
11
- subType: 'CFM_MATRIX';
12
- rows: MatrixRow[]; // Statements to rate
13
- columns: MatrixColumn[]; // Shared answer options per row
14
- buttonType?: SurveyButtonType;
15
- hasNotApplicable?: boolean;
16
- reverseScaleOrder?: boolean;
17
- labels?: string[]; // Anchor labels above columns
18
- matrixFormat?: 'standard' | 'carousel' | 'dropdown';
19
- matrixType?: 'likert' | 'bipolar';
20
- answerType?: 'single' | 'multiple';
21
- transposeTable?: boolean;
22
- repeatScale?: boolean;
23
- enableScale?: boolean;
9
+ type CfmMatrixQuestion = {
10
+ type: 'CFM_MATRIX';
11
+ id: string;
12
+ questionText: string;
13
+ statementRows: CfmMatrixStatementRow[];
14
+ scaleColumns: CfmMatrixScaleColumn[];
15
+ statementLayout: 'likert' | 'bipolar';
16
+ selectionMode: 'single' | 'multiple';
17
+ gridLayout: 'standard' | 'carousel' | 'dropdown';
18
+ transposeTable: boolean;
19
+ repeatColumnHeaders: boolean;
20
+ hasNotApplicableOption: boolean;
21
+ showColumnHeaders: boolean;
22
+ scaleAnchorLabels?: string[];
23
+ required: boolean;
24
+ // ... shell fields
24
25
  };
25
26
 
26
- type MatrixRow = { id: string; text: string; rightText?: string; };
27
- type MatrixColumn = { id: string; label: string; value: string | number | null; color?: string; };
27
+ type CfmMatrixStatementRow = {
28
+ id: string;
29
+ statementText: string;
30
+ oppositeStatementText?: string;
31
+ };
28
32
  ```
29
33
 
30
- ## Answer Shape: `MatrixAnswerMap`
34
+ ## Answer Shape: `MatrixRowAnswers`
35
+
31
36
  ```typescript
32
- { "row1_id": "column_value", "row2_id": "column_value", "row3_id": null }
33
- // null = N/A selected for that row
37
+ { "row1_id": columnValue, "row2_id": null }
34
38
  ```
35
39
 
36
40
  ## Rendering Guidance
37
- - **Standard format**: Grid table — rows on left, columns as headers
38
- - **Carousel format**: Show one row at a time with prev/next
39
- - **Dropdown format**: Each row has a dropdown selector for its column value
40
- - Likert: unipolar text labels (e.g. "Strongly Disagree" → "Strongly Agree")
41
- - Bipolar: `row.text` on left + `row.rightText` on right
42
- - If `hasNotApplicable` add N/A column with `value: null`
43
- - `onSelect` receives the full `MatrixAnswerMap` object on each change
41
+
42
+ - **standard**: Grid table rows on left, columns as headers
43
+ - **carousel**: One row at a time with prev/next
44
+ - **dropdown**: Each row has a dropdown (`MatrixDropdown`)
45
+ - **bipolar**: `statementText` left + `oppositeStatementText` right
46
+ - `onSelect` receives the full `MatrixRowAnswers` object on each change
47
+
48
+ ## SDK Integration Checklist (agent)
49
+
50
+ - [ ] Type literal: `QUESTION_TYPE.CFM_MATRIX`
51
+ - [ ] Answer stored as: `MatrixRowAnswers` — column **`id`** via `matrixColumnStoredValue`
52
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: MatrixRowAnswers }`
53
+ - [ ] Visibility helper: `getVisibleMatrixItemsForAnswers(question, answers, allQuestions, customFieldValues?)`
54
+ - [ ] Custom fields: 4th arg on matrix visibility helper when logic references CRM fields
55
+ - [ ] Logic features: skip ✓ display ✓ answer ✓ (rows + columns) variants ✓ numbering ✓
56
+ - [ ] Performance: filter rows/cols before render; lazy-load large matrices
57
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#cfm_matrix`](../../00-integration/question-type-sdk-matrix.md#cfm_matrix)
@@ -1,29 +1,7 @@
1
- # Matrix CSAT Question (Satisfaction Grid)
1
+ # CSAT Matrix Question (legacy reference)
2
2
 
3
- > **Type**: `'matrix'` with `subType: 'CSAT_MATRIX'` | **API Source**: `CSAT_MATRIX`
4
- > **Mapper**: `csatMatrixMapper.ts` | **Component**: `CsatMatrixScale`
3
+ > **Deprecated alias.** CSAT matrix grids use `type: 'CSAT_MATRIX'` see [04-csat.md](04-csat.md).
5
4
 
6
- ## TypeScript Type
7
- Same as `MatrixQuestion` (see `07-matrix-cfm.md`) but with `subType: 'CSAT_MATRIX'`.
5
+ For rating-style matrix grids use `type: 'RATING_MATRIX'` — see [09-matrix-rating.md](09-matrix-rating.md).
8
6
 
9
- ## Key Difference from CFM_MATRIX
10
- - Columns represent satisfaction levels (not text labels)
11
- - Uses `buttonType` to determine visual: emoji faces, stars, numbered, etc.
12
- - Uses `getEmojiForIndex(colIndex, totalCols)` for emoji rendering per cell
13
-
14
- ## Rendering by `buttonType`
15
-
16
- | `buttonType` | Cell Rendering |
17
- |-------------|---------------|
18
- | `'emoji'` | Sentiment face icons via `getEmojiForIndex` |
19
- | `'star'` | Star icons via `CsatStarIcons` |
20
- | `'numbered'` | Numeric badge buttons |
21
- | `'radio'` | Standard radio circles |
22
- | `'dropdown'` | Dropdown per row (uses `MatrixDropdown`) |
23
- | `'graphics'` | Emoji slider per row (uses `CustomSliderTrack`) |
24
-
25
- ## Answer Shape: `MatrixAnswerMap`
26
- Same as CFM_MATRIX — `{ "row_id": column_value | null }`
27
-
28
- ## N/A Column
29
- If `hasNotApplicable` is true, the last column has `value: null`. Selecting it records `null` for that row, which is a valid answer (passes validation).
7
+ There is no `subType` field. Each matrix variant is a flat `question.type` literal.
@@ -1,28 +1,44 @@
1
1
  # Rating Matrix Question
2
2
 
3
- > **Type**: `'rating_matrix'` | **API Source**: `RATING_MATRIX`
4
- > **Mapper**: `ratingMatrixMapper.ts` → routed to `mapMatrixQuestion` | **Component**: `CsatMatrixScale`
3
+ > **Type**: `'RATING_MATRIX'` | **API Source**: `RATING_MATRIX`
4
+ > **Component**: `CsatMatrixScale`
5
5
 
6
6
  ## TypeScript Type
7
7
 
8
8
  ```typescript
9
- type RatingMatrixQuestion = QuestionBase & {
10
- type: 'rating_matrix';
11
- rows: MatrixRow[];
12
- columns: MatrixColumn[]; // Rating columns with NPS-style colors
9
+ type RatingMatrixQuestion = {
10
+ type: 'RATING_MATRIX';
11
+ statementRows: StatementRow[];
12
+ scaleColumns: ScaleColumn[];
13
13
  minLabel?: string;
14
14
  maxLabel?: string;
15
- buttonType?: SurveyButtonType;
16
- hasNotApplicable?: boolean;
17
- reverseScaleOrder?: boolean;
18
- labels?: string[];
15
+ displayStyle: CsatQuestion['displayStyle'];
16
+ gridLayout: 'standard' | 'carousel' | 'dropdown';
17
+ hasNotApplicableOption: boolean;
18
+ reverseScaleOrder: boolean;
19
+ scaleAnchorLabels?: string[];
20
+ // + shell fields (id, questionText, required, containerMedia?, etc.)
19
21
  };
20
22
  ```
21
23
 
22
24
  ## Key Difference from CSAT_MATRIX
23
- - Columns carry traffic-light `color` values (like NPS rating)
25
+
24
26
  - Has `minLabel`/`maxLabel` endpoint labels
27
+ - Column badge colors derived client-side via `columnAccentColor(col)` — see `02-reference/value-derivation.md`
25
28
  - Rendered by the same `CsatMatrixScale` component
26
29
 
27
- ## Answer Shape: `MatrixAnswerMap`
28
- Same pattern: `{ "row_id": column_value | null }`
30
+ ## Answer Shape: `MatrixRowAnswers`
31
+
32
+ `Record<statementRows[].id, matrixColumnStoredValue(col) | null>` — stored value is always the column **`id`**; submit maps id → label/number via `resolveSubmitValues`.
33
+
34
+ ## SDK Integration Checklist (agent)
35
+
36
+ - [ ] Type literal: `QUESTION_TYPE.RATING_MATRIX`
37
+ - [ ] Answer stored as: `MatrixRowAnswers` — column **`id`** via `matrixColumnStoredValue`
38
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: MatrixRowAnswers }`
39
+ - [ ] Visibility helper: `getVisibleMatrixItemsForAnswers(question, answers, allQuestions, customFieldValues?)`
40
+ - [ ] Custom fields: 4th arg on matrix visibility helper when logic references CRM fields
41
+ - [ ] Logic features: skip ✓ display ✓ answer ✓ (rows; column logic may be limited) variants ✓ numbering ✓
42
+ - [ ] Performance: reuse `CsatMatrixScale`; render only visible rows/cols
43
+ - [ ] Known limitation: column-level answer logic gap — verify fetched survey rules
44
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#rating_matrix`](../../00-integration/question-type-sdk-matrix.md#rating_matrix)
@@ -1,13 +1,13 @@
1
1
  # Slider Matrix Question
2
2
 
3
- > **Type**: `'slider_matrix'` | **API Source**: `SLIDER_MATRIX`
3
+ > **Type**: `'SLIDER_MATRIX'` | **API Source**: `SLIDER_MATRIX`
4
4
  > **Mapper**: `sliderMatrixMapper.ts` | **Component**: `SliderMatrixScale`
5
5
 
6
6
  ## TypeScript Type
7
7
 
8
8
  ```typescript
9
9
  type SliderMatrixQuestion = QuestionBase & {
10
- type: 'slider_matrix';
10
+ type: 'SLIDER_MATRIX';
11
11
  rows: SliderMatrixRow[]; // Each row has independent slider config
12
12
  labels?: string[]; // Anchor labels above track
13
13
  ticks?: number; // Number of tick marks (default 10)
@@ -25,7 +25,7 @@ type SliderMatrixRow = MatrixRow & {
25
25
  type TickValue = { value: number; label: string; color: string; };
26
26
  ```
27
27
 
28
- ## Answer Shape: `MatrixAnswerMap`
28
+ ## Answer Shape: `MatrixRowAnswers`
29
29
  ```typescript
30
30
  { "row1_id": 75, "row2_id": 30, "row3_id": null }
31
31
  // number = slider position, null = N/A
@@ -37,4 +37,15 @@ type TickValue = { value: number; label: string; color: string; };
37
37
  - If `tickValues` available → render tick marks with labels and colors
38
38
  - If `enableInputBox` → show numeric input alongside slider
39
39
  - If `enableNotApplicable` → add N/A checkbox per row
40
- - `onSelect` receives the full `MatrixAnswerMap` with all row values
40
+ - `onSelect` receives the full `MatrixRowAnswers` with all row values
41
+
42
+ ## SDK Integration Checklist (agent)
43
+
44
+ - [ ] Type literal: `QUESTION_TYPE.SLIDER_MATRIX`
45
+ - [ ] Answer stored as: `MatrixRowAnswers` — numeric slider value or `null` for N/A per row
46
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: MatrixRowAnswers }`
47
+ - [ ] Visibility helper: `getVisibleStatementRowsForAnswers(question, answers, allQuestions, customFieldValues?)`
48
+ - [ ] Custom fields: 4th arg on statement-row helper when logic references CRM fields
49
+ - [ ] Logic features: skip ✓ display ✓ answer ✓ (rows) variants ✓ numbering ✓
50
+ - [ ] Performance: debounce drag events if partial save enabled; one slider per visible row
51
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#slider_matrix`](../../00-integration/question-type-sdk-matrix.md#slider_matrix)
@@ -1,13 +1,13 @@
1
1
  # File Upload Question
2
2
 
3
- > **Type**: `'file_upload'` | **API Source**: `FILE_UPLOAD`
3
+ > **Type**: `'FILE_UPLOAD'` | **API Source**: `FILE_UPLOAD`
4
4
  > **Mapper**: `fileUploadMapper.ts` | **Component**: `FileUploadScale`
5
5
 
6
6
  ## TypeScript Type
7
7
 
8
8
  ```typescript
9
9
  type FileUploadQuestion = QuestionBase & {
10
- type: 'file_upload';
10
+ type: 'FILE_UPLOAD';
11
11
  uploadMessage?: string; // Instruction text (HTML)
12
12
  supportedFileFormats?: string[]; // ['PDF', 'PNG', 'DOCX'] (uppercase, no dots)
13
13
  maxFileCount?: number; // Max files allowed
@@ -32,3 +32,14 @@ Array of uploaded file descriptors. Submitted via `quesIdVsAttachmentDetails` (N
32
32
  - Show file list with name, size, and remove button
33
33
  - Enforce `fileSizeLimit` with appropriate error messages
34
34
  - `onSelect` receives the full `UploadedFile[]` array
35
+
36
+ ## SDK Integration Checklist (agent)
37
+
38
+ - [ ] Type literal: `QUESTION_TYPE.FILE_UPLOAD`
39
+ - [ ] Answer stored as: `UploadedFile[]`
40
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: UploadedFile[] }` after upload completes
41
+ - [ ] Visibility helper: N/A
42
+ - [ ] Custom fields: skip/display rules only — no visibility helper
43
+ - [ ] Logic features: skip ✓ display ✓ answer ✗ variants ✓ numbering ✓
44
+ - [ ] Performance: upload to presigned URL before CHANGE; show progress UI
45
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#file_upload`](../../00-integration/question-type-sdk-matrix.md#file_upload)
@@ -0,0 +1,59 @@
1
+ # Heatmap Question (`HEATMAP`)
2
+
3
+ > **SDK type:** `HeatmapQuestion` in `fetchSurvey/types/heatmap.ts`
4
+ > **UI spec:** `03-ui-specs/13-heatmap.md`
5
+
6
+ ## API Source
7
+
8
+ - `answerType: "HEATMAP"`
9
+ - `questionAssets[0]` → image URL
10
+ - `surveyHeatmapMetadata` → regions, max clicks, canvas dimensions
11
+
12
+ ## Question Fields
13
+
14
+ | Field | Type | Description |
15
+ |-------|------|-------------|
16
+ | `type` | `'HEATMAP'` | Dispatch literal |
17
+ | `imageUrl` | `string` | Required image for click map |
18
+ | `regions` | `HeatmapRegion[]` | Normalized 0–1 rects for logic |
19
+ | `maxClicksAllowed` | `number` | 1–20, from `totalClickAllowed` |
20
+ | `referenceWidth` | `number` | Canvas width used for region normalization |
21
+ | `referenceHeight` | `number` | Canvas height used for region normalization |
22
+
23
+ ## Answer Shape
24
+
25
+ ```typescript
26
+ type HeatmapClickPoint = { id: string; x: number; y: number };
27
+ type HeatmapAnswer = HeatmapClickPoint[];
28
+ ```
29
+
30
+ Stored in `state.answers[questionId]`. Submit serializes to:
31
+
32
+ ```typescript
33
+ questionToAnswers[questionId] = [JSON.stringify(clicks)];
34
+ ```
35
+
36
+ ## Logic Fields
37
+
38
+ | Field | Operators | Semantics |
39
+ |-------|-----------|-----------|
40
+ | `HEATMAP` | EXISTS / MISSING | Any click points present |
41
+ | `HEATMAP_REGION` | CONTAINS / DOES_NOT_CONTAIN | Any listed region label has ≥1 click inside |
42
+
43
+ Logic values use region **labels** (e.g. `"Region 1"`), not shape ids.
44
+
45
+ ## Component
46
+
47
+ `HeatmapScale` — see `01-components/17-heatmap-scale.md`
48
+
49
+ ## SDK Integration Checklist (agent)
50
+
51
+ - [ ] Type literal: `QUESTION_TYPE.HEATMAP`
52
+ - [ ] Answer stored as: `HeatmapAnswer` (`HeatmapClickPoint[]`)
53
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: HeatmapClickPoint[] }` on click add/remove
54
+ - [ ] Visibility helper: N/A
55
+ - [ ] Custom fields: skip/display rules only
56
+ - [ ] Logic features: skip ✓ display ✓ answer ✗ variants ✓ numbering ✓
57
+ - [ ] Performance: normalize coords 0–1; copy [`templates/heatmapCoords.ts`](../../templates/heatmapCoords.ts)
58
+ - [ ] Respect `maxClicksAllowed`; use `findSpotNearClick` for spot hit testing
59
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#heatmap`](../../00-integration/question-type-sdk-matrix.md#heatmap)
@@ -0,0 +1,101 @@
1
+ # Rank Order Question (`RANK_ORDER`)
2
+
3
+ > **SDK type:** `RankOrderQuestion` in `fetchSurvey/types/rankOrder.ts`
4
+ > **UI spec:** `03-ui-specs/14-rank-order.md`
5
+
6
+ ## API Source
7
+
8
+ - `answerType: "RANK_ORDER"`
9
+ - `answerDetails[]` → options (text + optional `answerAsset`)
10
+ - `questionConfigs`:
11
+ - `RANK_ORDER_ANSWER_TYPE` → `DROPDOWN` | `DRAG_AND_DROP`
12
+ - `OPTION_TYPE` → `TEXT_ONLY` | `IMAGE_ONLY` | `TEXT_AND_IMAGE`
13
+ - `REQUIRE_RANK_ALL` → boolean
14
+ - `SHUFFLE_ORDER` → boolean
15
+ - `additionalInfo.hasOptionLevelAnswers: true` → submit uses `optionLevelAnswers`
16
+
17
+ ## Question Fields
18
+
19
+ | Field | Type | API config |
20
+ |-------|------|------------|
21
+ | `type` | `'RANK_ORDER'` | `answerType` |
22
+ | `options` | `RankOrderOption[]` | `answerDetails[]` |
23
+ | `interactionMode` | `'dropdown' \| 'dragAndDrop'` | `RANK_ORDER_ANSWER_TYPE` |
24
+ | `optionDisplay` | `'textOnly' \| 'imageOnly' \| 'textAndImage'` | `OPTION_TYPE` |
25
+ | `requireRankAll` | `boolean` | `REQUIRE_RANK_ALL` |
26
+ | `shuffleOptions` | `boolean` | `SHUFFLE_ORDER` |
27
+
28
+ ### RankOrderOption
29
+
30
+ | Field | Source |
31
+ |-------|--------|
32
+ | `id` | `answerDetails[].id` |
33
+ | `optionLabel` | `answerDetails[].answerText` |
34
+ | `imageUrl` | `answerAsset.source` |
35
+ | `previewImageUrl` | `answerAsset.previewImageUrl` |
36
+ | `answerLogic` | option `controlConfig.displayLogic` |
37
+
38
+ ## Answer Shape
39
+
40
+ ```typescript
41
+ /** optionId → 1-based rank. Partial map allowed when requireRankAll is false. */
42
+ type RankOrderAnswers = Record<string, number>;
43
+ ```
44
+
45
+ Stored in `state.answers[questionId]`.
46
+
47
+ ## Submit Shape
48
+
49
+ Both fields are populated for rank-order questions:
50
+
51
+ ```typescript
52
+ // Ordered option ids from rank 1 → N
53
+ questionToAnswers[questionId] = ['optionIdRank1', 'optionIdRank2', ...];
54
+
55
+ // Per-option rank (API key uses -:- separator)
56
+ optionLevelAnswers[`${questionId}-:-${optionId}`] = [String(rank)];
57
+ ```
58
+
59
+ ## Logic Field: `RANK_ORDER`
60
+
61
+ Conditions target a **specific option** via `details.subConditionEntity` (`entityType: 'OPTION'`).
62
+
63
+ | UI label | API operator | Values | Semantics |
64
+ |----------|--------------|--------|-----------|
65
+ | Ranked as | `EQUALS` | rank number | Subject option rank equals value |
66
+ | Ranked more than | `GT` | rank number | Subject rank > value |
67
+ | Ranked less than | `LT` | rank number | Subject rank < value |
68
+ | Ranked above | `BEFORE` | reference option id | Subject rank < reference rank |
69
+ | Ranked below | `AFTER` | reference option id | Subject rank > reference rank |
70
+
71
+ Also supports `EXISTS` / `MISSING` for the whole question answer.
72
+
73
+ Works in skip, display, answer, question variant, and end-page logic via the shared `evaluateCondition` pipeline.
74
+
75
+ ## SDK Helpers (client-safe)
76
+
77
+ ```typescript
78
+ import {
79
+ assignRankWithoutDuplicates,
80
+ buildRankOrderFromOrderedOptionIds,
81
+ getOrderedOptionIdsFromRanks,
82
+ getVisibleRankOrderOptionsForAnswers,
83
+ normalizeRankOrderAnswers,
84
+ } from '@explorer02/cfm-survey-sdk';
85
+ ```
86
+
87
+ ## Component
88
+
89
+ `RankOrderScale` — see `01-components/18-rank-order-scale.md`
90
+
91
+ ## SDK Integration Checklist (agent)
92
+
93
+ - [ ] Type literal: `QUESTION_TYPE.RANK_ORDER`
94
+ - [ ] Answer stored as: `RankOrderAnswers` (`Record<optionId, rank>`)
95
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: RankOrderAnswers }` after reorder
96
+ - [ ] Visibility helper: `getVisibleRankOrderOptionsForAnswers(question, answers, allQuestions, customFieldValues?)`
97
+ - [ ] Custom fields: 4th arg on rank visibility helper when logic references CRM fields
98
+ - [ ] Logic features: skip ✓ display ✓ answer ✓ (options) variants ✓ numbering ✓
99
+ - [ ] Performance: prefer `option.imageUrl` over `previewImageUrl`; install `@dnd-kit/*` for drag mode
100
+ - [ ] Value utils: `assignRankWithoutDuplicates`, `buildRankOrderFromOrderedOptionIds`, `getOrderedOptionIdsFromRanks`, `normalizeRankOrderAnswers`
101
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#rank_order`](../../00-integration/question-type-sdk-matrix.md#rank_order)
@@ -1,71 +1,110 @@
1
1
  # Question Types Reference
2
2
 
3
3
  > Read **on demand** — only for types present in the fetched survey.
4
- > UI implementation: `01-components/`. Routing table: `02-reference/routing-table.md`.
5
4
 
6
- ## Discriminated Union
5
+ ## Discriminated Union (11 types)
7
6
 
8
7
  ```typescript
9
8
  type SurveyQuestion =
10
- | RatingQuestion // 'rating'
11
- | RadioQuestion // 'radio'
12
- | TextQuestion // 'text'
13
- | CsatQuestion // 'csat'
14
- | RatingScaleQuestion // 'rating_scale'
15
- | SliderQuestion // 'slider'
16
- | MatrixQuestion // 'matrix' (check subType)
17
- | RatingMatrixQuestion // 'rating_matrix'
18
- | SliderMatrixQuestion // 'slider_matrix'
19
- | FileUploadQuestion // 'file_upload'
20
- | TextAndMediaQuestion; // 'text_and_media'
9
+ | McqQuestion // 'MCQ'
10
+ | NpsQuestion // 'NPS_SCALE'
11
+ | TextInputQuestion // 'TEXTFIELD'
12
+ | CsatQuestion // 'CSAT_MATRIX'
13
+ | CfmMatrixQuestion // 'CFM_MATRIX'
14
+ | RatingMatrixQuestion // 'RATING_MATRIX'
15
+ | SliderMatrixQuestion // 'SLIDER_MATRIX'
16
+ | FileUploadQuestion // 'FILE_UPLOAD'
17
+ | TextAndMediaQuestion // 'TEXT_AND_MEDIA'
18
+ | HeatmapQuestion // 'HEATMAP'
19
+ | RankOrderQuestion; // 'RANK_ORDER'
21
20
  ```
22
21
 
23
- ## Shared `QuestionBase` Properties
22
+ Use `QUESTION_TYPE` from the SDK for dispatch comparisons.
24
23
 
25
- | Property | Type | Notes |
26
- |----------|------|-------|
27
- | `id` | `string` | **MUST** be DOM `id` on wrapper |
28
- | `text` | `string` | HTML — use `dangerouslySetInnerHTML` |
29
- | `description` | `string?` | HTML |
30
- | `required` | `boolean?` | |
31
- | `requiredErrorMessage` | `string?` | Custom validation message |
32
- | `questionNumber` | `number?` | 1-indexed |
24
+ Each type is **standalone** open its file in exported SDK types for the complete field list.
25
+
26
+ > **Legacy:** `StarRatingQuestion` / `SliderQuestion` mapper types are not in the `SurveyQuestion` union. API RATING/SLIDER pages map into `NPS_SCALE`, matrix display styles, or `SLIDER_MATRIX`.
27
+
28
+ ## Shared field names (duplicated per type file)
29
+
30
+ | Property | Meaning |
31
+ |----------|---------|
32
+ | `id` | DOM `id` on wrapper |
33
+ | `questionText` | Main prompt (HTML) |
34
+ | `questionDescription?` | Supplementary HTML |
35
+ | `questionHint?` | Hint text |
36
+ | `required` | Mandatory flag |
37
+ | `requiredErrorMessage?` | Custom validation message |
38
+ | `questionNumber?` | 1-indexed position |
39
+ | `skipLogics?` | Forward skip rules evaluated on page leave |
40
+ | `displayLogic?` | Question-level show/hide (dynamic or page-level) |
41
+ | `displayVariants?` | Alternate `questionText` prompts selected by condition (SDK resolves on `currentQuestions`; see [`question-display-variants.md`](../../00-integration/question-display-variants.md)) |
42
+ | `answerLogic?` | On `McqOption`, `StatementRow`, or `ScaleColumn` — sub-entity show/hide (see [`answer-logic-and-navigation.md`](../../00-integration/answer-logic-and-navigation.md)) |
33
43
 
34
44
  ---
35
45
 
36
- ## radio {#radio}
46
+ ## MCQ {#mcq}
47
+
48
+ - **Type:** `McqQuestion` — `type: 'MCQ'`
49
+ - **Answer:** `string` or `string[]` (`option.id` values)
50
+ - **Options:** `McqOption[]` with `id`, `optionLabel`
51
+
52
+ ### SDK Integration Checklist (agent)
37
53
 
38
- - **Type:** `RadioQuestion` `type: 'radio'`
39
- - **Answer:** `string | number` (option id or value)
40
- - **UI:** Inline MCQ radio cards in `Question.tsx` see `01-components/02-question.md`
41
- - **No separate reference doc needed**
54
+ - [ ] Type literal: `QUESTION_TYPE.MCQ`
55
+ - [ ] Answer stored as: `option.id` (string/number) or array when multi-select
56
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: optionId | optionId[] }`
57
+ - [ ] Visibility helper: `getVisibleMcqOptionsForAnswers(question, answers, allQuestions, customFieldValues?)`
58
+ - [ ] Custom fields: 4th arg when logic references CRM fields
59
+ - [ ] Logic features: skip ✓ display ✓ answer ✓ (options) variants ✓ numbering ✓
60
+ - [ ] Performance: filter options via helper before render
61
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#mcq`](../../00-integration/question-type-sdk-matrix.md#mcq)
42
62
 
43
- ## text {#text}
63
+ ## TEXTFIELD {#textfield}
44
64
 
45
- - **Type:** `TextQuestion` — `type: 'text'`
65
+ - **Type:** `TextInputQuestion` — `type: 'TEXTFIELD'`
46
66
  - **Answer:** `string`
47
- - **UI:** Inline `<textarea>` or `<input>` in `Question.tsx`
48
- - **No separate reference doc needed**
49
67
 
50
- ## text_and_media {#text_and_media}
68
+ ### SDK Integration Checklist (agent)
51
69
 
52
- - **Type:** `TextAndMediaQuestion` `type: 'text_and_media'`
53
- - **Answer:** none display-only, skipped in validation and submission
54
- - **UI:** Inline `<video>` or `<img>` from `question.mediaUrl` no scale component
55
- - **No separate reference doc needed**
70
+ - [ ] Type literal: `QUESTION_TYPE.TEXTFIELD`
71
+ - [ ] Answer stored as: `string`
72
+ - [ ] onAction CHANGE payload: `{ questionId, answerValue: string }`
73
+ - [ ] Visibility helper: N/A
74
+ - [ ] Custom fields: skip/display only
75
+ - [ ] Logic features: skip ✓ display ✓ answer ✗ variants ✓ numbering ✓
76
+ - [ ] Performance: debounce long textarea onChange if partial save enabled
77
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#textfield`](../../00-integration/question-type-sdk-matrix.md#textfield)
78
+
79
+ ## TEXT_AND_MEDIA {#text_and_media}
80
+
81
+ - **Type:** `TextAndMediaQuestion` — `type: 'TEXT_AND_MEDIA'`
82
+ - **Answer:** none — display-only
83
+
84
+ ### SDK Integration Checklist (agent)
85
+
86
+ - [ ] Type literal: `QUESTION_TYPE.TEXT_AND_MEDIA`
87
+ - [ ] Answer stored as: none — no CHANGE action
88
+ - [ ] onAction: user advances with NEXT only
89
+ - [ ] Visibility helper: N/A
90
+ - [ ] Custom fields: skip/display only
91
+ - [ ] Logic features: skip ✓ display ✓ answer ✗ variants ✓ numbering ✓
92
+ - [ ] Performance: lazy-load media; respect `media.alignment`
93
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#text_and_media`](../../00-integration/question-type-sdk-matrix.md#text_and_media)
56
94
 
57
95
  ---
58
96
 
59
97
  ## Detailed Reference Docs
60
98
 
61
- | File | Type | When to read |
62
- |------|------|--------------|
63
- | `01-rating.md` | `rating` | NPS / numeric scales |
64
- | `04-csat.md` | `csat` | CSAT emoji/star (≤5 options) |
65
- | `05-rating-scale.md` | `rating_scale` | Star/emoji rating |
66
- | `06-slider.md` | `slider` | Single range slider |
67
- | `07-matrix-cfm.md` | `matrix` + `CFM_MATRIX` | Likert text grid |
68
- | `08-matrix-csat.md` | `matrix` + CSAT/RATING | Satisfaction grid |
69
- | `09-matrix-rating.md` | `rating_matrix` | NPS-style grid |
70
- | `10-slider-matrix.md` | `slider_matrix` | Slider grid |
71
- | `11-file-upload.md` | `file_upload` | File attachments |
99
+ | File | Type literal | When to read |
100
+ |------|--------------|--------------|
101
+ | `01-rating.md` | `NPS_SCALE` | NPS 0–10 scales |
102
+ | `04-csat.md` | `CSAT_MATRIX` | CSAT matrix grid |
103
+ | `07-matrix-cfm.md` | `CFM_MATRIX` | CFM matrix grid |
104
+ | `09-matrix-rating.md` | `RATING_MATRIX` | NPS-style rating matrix |
105
+ | `10-slider-matrix.md` | `SLIDER_MATRIX` | Slider grid |
106
+ | `11-file-upload.md` | `FILE_UPLOAD` | File attachments |
107
+ | `12-heatmap.md` | `HEATMAP` | Click-map heatmap |
108
+ | `13-rank-order.md` | `RANK_ORDER` | Rank order options |
109
+
110
+ Legacy docs (deprecated API mappings): `05-rating-scale.md`, `06-slider.md`