@explorer02/cfm-survey-sdk 0.2.1 → 0.2.3

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 (95) 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 +18 -8
  10. package/templates/docs/00-integration/analytics-events-catalog.md +54 -0
  11. package/templates/docs/00-integration/answer-logic-and-navigation.md +50 -0
  12. package/templates/docs/00-integration/aws-deploy.md +281 -0
  13. package/templates/docs/00-integration/client-integration-guide.md +351 -0
  14. package/templates/docs/00-integration/component-checklist.md +55 -22
  15. package/templates/docs/00-integration/constraints.md +49 -4
  16. package/templates/docs/00-integration/custom-field-logic-and-navigation.md +174 -0
  17. package/templates/docs/00-integration/display-logic-and-navigation.md +64 -0
  18. package/templates/docs/00-integration/end-page-logic.md +64 -0
  19. package/templates/docs/00-integration/file-upload-aws.md +116 -0
  20. package/templates/docs/00-integration/logic-fields-catalog.md +105 -0
  21. package/templates/docs/00-integration/partial-save-and-recovery.md +98 -0
  22. package/templates/docs/00-integration/placeholders-and-tokens.md +116 -0
  23. package/templates/docs/00-integration/progress.md +61 -0
  24. package/templates/docs/00-integration/question-display-variants.md +65 -0
  25. package/templates/docs/00-integration/question-numbering.md +51 -0
  26. package/templates/docs/00-integration/question-type-sdk-matrix.md +244 -0
  27. package/templates/docs/00-integration/setup.md +84 -0
  28. package/templates/docs/00-integration/skip-logic-and-navigation.md +80 -0
  29. package/templates/docs/00-integration/survey-lifecycle-analytics.md +94 -0
  30. package/templates/docs/00-integration/useSurveySDK.md +151 -23
  31. package/templates/docs/01-components/01-survey-page.md +76 -54
  32. package/templates/docs/01-components/02-question.md +61 -58
  33. package/templates/docs/01-components/03-rating-scale.md +11 -1
  34. package/templates/docs/01-components/04-star-rating-scale.md +45 -0
  35. package/templates/docs/01-components/05-csat-matrix-scale.md +20 -11
  36. package/templates/docs/01-components/06-likert-matrix-scale.md +14 -4
  37. package/templates/docs/01-components/07-slider-matrix-scale.md +11 -2
  38. package/templates/docs/01-components/08-file-upload-scale.md +23 -51
  39. package/templates/docs/01-components/09-custom-slider-track.md +2 -2
  40. package/templates/docs/01-components/11-progress-bar.md +10 -4
  41. package/templates/docs/01-components/13-matrix-dropdown.md +29 -32
  42. package/templates/docs/01-components/14-intro-page.md +34 -0
  43. package/templates/docs/01-components/15-end-page.md +31 -0
  44. package/templates/docs/01-components/16-paused-page.md +27 -0
  45. package/templates/docs/01-components/17-heatmap-scale.md +75 -0
  46. package/templates/docs/01-components/18-rank-order-scale.md +93 -0
  47. package/templates/docs/01-components/README.md +42 -36
  48. package/templates/docs/02-reference/config-field-index.md +141 -139
  49. package/templates/docs/02-reference/exports.md +149 -0
  50. package/templates/docs/02-reference/question-types/01-rating.md +31 -32
  51. package/templates/docs/02-reference/question-types/04-csat.md +51 -42
  52. package/templates/docs/02-reference/question-types/05-rating-scale.md +16 -11
  53. package/templates/docs/02-reference/question-types/06-slider.md +2 -2
  54. package/templates/docs/02-reference/question-types/07-matrix-cfm.md +44 -30
  55. package/templates/docs/02-reference/question-types/08-matrix-csat.md +4 -26
  56. package/templates/docs/02-reference/question-types/09-matrix-rating.md +29 -13
  57. package/templates/docs/02-reference/question-types/10-slider-matrix.md +15 -4
  58. package/templates/docs/02-reference/question-types/11-file-upload.md +43 -17
  59. package/templates/docs/02-reference/question-types/12-heatmap.md +59 -0
  60. package/templates/docs/02-reference/question-types/13-rank-order.md +101 -0
  61. package/templates/docs/02-reference/question-types/README.md +96 -47
  62. package/templates/docs/02-reference/routing-table.md +33 -18
  63. package/templates/docs/02-reference/value-derivation.md +63 -0
  64. package/templates/docs/03-ui-specs/00-question-shell.md +19 -88
  65. package/templates/docs/03-ui-specs/01-rating.md +18 -52
  66. package/templates/docs/03-ui-specs/02-radio.md +80 -37
  67. package/templates/docs/03-ui-specs/03-text.md +2 -2
  68. package/templates/docs/03-ui-specs/04-csat.md +68 -33
  69. package/templates/docs/03-ui-specs/05-rating-scale.md +21 -18
  70. package/templates/docs/03-ui-specs/06-slider.md +3 -1
  71. package/templates/docs/03-ui-specs/07-matrix-cfm.md +44 -25
  72. package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +19 -43
  73. package/templates/docs/03-ui-specs/09-slider-matrix.md +18 -1
  74. package/templates/docs/03-ui-specs/10-file-upload.md +42 -21
  75. package/templates/docs/03-ui-specs/11-text-and-media.md +29 -29
  76. package/templates/docs/03-ui-specs/12-survey-chrome.md +58 -14
  77. package/templates/docs/03-ui-specs/13-heatmap.md +80 -0
  78. package/templates/docs/03-ui-specs/14-rank-order.md +128 -0
  79. package/templates/docs/03-ui-specs/README.md +16 -14
  80. package/templates/docs/03-ui-specs/shared/custom-slider-track.md +28 -35
  81. package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +5 -0
  82. package/templates/docs/MANIFEST.json +476 -69
  83. package/templates/docs/index.md +82 -30
  84. package/templates/docs/templates/CustomSliderTrack.tsx +144 -0
  85. package/templates/docs/templates/MatrixDropdown.tsx +216 -0
  86. package/templates/docs/templates/Question.tsx +221 -154
  87. package/templates/docs/templates/RankOrderScale.tsx +353 -0
  88. package/templates/docs/templates/deploy-to-aws.sh +114 -0
  89. package/templates/docs/templates/heatmapCoords.ts +58 -0
  90. package/templates/docs/templates/implementation_plan.md +126 -67
  91. package/templates/docs/templates/survey-inventory.schema.json +77 -0
  92. package/templates/docs/templates/surveyUiIcons.tsx +52 -0
  93. package/templates/docs/templates/verify-agent-build.sh +85 -0
  94. package/templates/docs/01-components/04-csat-scale.md +0 -40
  95. package/templates/docs/02-question-types/01-rating.md +0 -44
@@ -0,0 +1,27 @@
1
+ # Paused Page
2
+
3
+ > **UI spec:** `03-ui-specs/12-survey-chrome.md`
4
+ > **Reference:** `apps/client/src/components/PausedPage.tsx`
5
+
6
+ ## When to render
7
+
8
+ `state.phase.kind === 'paused'` when survey `phaseFlags.paused` is true.
9
+
10
+ ## Props
11
+
12
+ ```typescript
13
+ type PausedPageProps = {
14
+ page: SpecialPage;
15
+ };
16
+ ```
17
+
18
+ ## Wiring
19
+
20
+ ```tsx
21
+ <PausedPage page={state.specialPage} />
22
+ ```
23
+
24
+ ## Content
25
+
26
+ - Read-only message from `page.header` / `page.description`
27
+ - No start or navigation actions
@@ -0,0 +1,75 @@
1
+ # Heatmap Architectural Blueprint
2
+
3
+ > **UI spec (authoritative):** `03-ui-specs/13-heatmap.md`
4
+ > **Reference implementation:** `apps/client/src/components/HeatmapScale.tsx`
5
+ > **Portable coord helper:** copy [`templates/heatmapCoords.ts`](../templates/heatmapCoords.ts)
6
+ > **Target Component**: `HeatmapScale`
7
+ > **Handles**: `type: 'HEATMAP'`
8
+
9
+ ## Core Responsibility
10
+
11
+ Render the heatmap image, capture click spots in normalized 0–1 coordinates, toggle spots on repeat click, enforce `maxClicksAllowed` client-side, and bubble answers via `onSelect`.
12
+
13
+ ## Props Contract
14
+
15
+ ```typescript
16
+ type HeatmapScaleProps = {
17
+ question: HeatmapQuestion;
18
+ selectedValue?: HeatmapClickPoint[];
19
+ onSelect: (answer: HeatmapClickPoint[] | undefined) => void;
20
+ };
21
+ ```
22
+
23
+ ## State Management
24
+
25
+ - `selectedValue` from SDK is source of truth — do not duplicate answer state
26
+ - Local UI state: `isImageReady` only
27
+
28
+ ## Click Interaction
29
+
30
+ 1. User clicks image → compute normalized `{ x, y }` from `getBoundingClientRect()`
31
+ 2. If click within 14px of existing spot → remove that spot
32
+ 3. Else if under `maxClicksAllowed` → append `{ id: crypto.randomUUID(), x, y }`
33
+ 4. Else → no-op
34
+
35
+ ## Coordinate Helpers
36
+
37
+ Copy [`templates/heatmapCoords.ts`](../templates/heatmapCoords.ts):
38
+
39
+ - `getNormalizedClickFromImage(event, imageElement)`
40
+ - `findSpotNearClick(clickX, clickY, spots, imageRect)`
41
+ - `createNewSpot(x, y)`
42
+
43
+ ## DOM Structure
44
+
45
+ ```tsx
46
+ <div className="relative inline-block max-w-full">
47
+ <img onClick={handleImageClick} ... />
48
+ <div className="absolute inset-0 pointer-events-none">
49
+ {spots.map(spot => <Spot />)}
50
+ </div>
51
+ </div>
52
+ ```
53
+
54
+ ## Wiring in Question.tsx
55
+
56
+ ```typescript
57
+ {question.type === QUESTION_TYPE.HEATMAP && (
58
+ <HeatmapScale
59
+ question={question as HeatmapQuestion}
60
+ selectedValue={Array.isArray(selectedValue) ? selectedValue : undefined}
61
+ onSelect={onSelect}
62
+ />
63
+ )}
64
+ ```
65
+
66
+ Question shell (title, description, validation) stays in `Question.tsx`.
67
+
68
+ ## SDK Integration Checklist (agent)
69
+
70
+ - [ ] Type literal: `QUESTION_TYPE.HEATMAP`
71
+ - [ ] Answer stored as: `HeatmapClickPoint[]`
72
+ - [ ] onAction CHANGE: `{ questionId, answerValue: HeatmapClickPoint[] }`
73
+ - [ ] Copy coord helper from [`templates/heatmapCoords.ts`](../templates/heatmapCoords.ts)
74
+ - [ ] Respect `maxClicksAllowed`; normalize coords 0–1
75
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#heatmap`](../00-integration/question-type-sdk-matrix.md#heatmap)
@@ -0,0 +1,93 @@
1
+ # Rank Order Architectural Blueprint
2
+
3
+ > **UI spec (authoritative):** `03-ui-specs/14-rank-order.md`
4
+ > **Portable template:** copy [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx)
5
+ > **Target Component:** `RankOrderScale`
6
+ > **Handles:** `type: 'RANK_ORDER'`
7
+
8
+ ## Core Responsibility
9
+
10
+ Render rankable options in **dropdown** or **drag-and-drop** mode, three option display variants, bubble ranks via `onSelect`.
11
+
12
+ ## Props Contract
13
+
14
+ ```typescript
15
+ type RankOrderScaleProps = {
16
+ question: RankOrderQuestion;
17
+ selectedValue?: RankOrderAnswers;
18
+ onSelect: (value: RankOrderAnswers) => void;
19
+ };
20
+ ```
21
+
22
+ ## State Management
23
+
24
+ - `selectedValue` from SDK is source of truth — no duplicate local answer state
25
+ - Dropdown: `assignRankWithoutDuplicates` on rank change
26
+ - Drag-and-drop: `buildRankOrderFromOrderedOptionIds` after reorder; `getOrderedOptionIdsFromRanks` for display order
27
+
28
+ ## Layout Orchestrator
29
+
30
+ ```tsx
31
+ export function RankOrderScale({ question, selectedValue, onSelect }: RankOrderScaleProps) {
32
+ if (question.interactionMode === 'dragAndDrop') {
33
+ return <DragDropRankLayout ... />;
34
+ }
35
+ return <DropdownRankLayout ... />;
36
+ }
37
+ ```
38
+
39
+ ## shuffleOptions
40
+
41
+ When API `SHUFFLE_ORDER` is true, SDK shuffles options at map time. **Do not re-shuffle in the client** — logic and option ids must stay aligned with fetched order.
42
+
43
+ ## Wiring in Question.tsx
44
+
45
+ ```typescript
46
+ import {
47
+ QUESTION_TYPE,
48
+ getVisibleRankOrderOptionsForAnswers,
49
+ normalizeRankOrderAnswers,
50
+ } from '@explorer02/cfm-survey-sdk';
51
+
52
+ const rankOrderQuestion = useMemo(() => {
53
+ if (question.type !== QUESTION_TYPE.RANK_ORDER) return null;
54
+ return {
55
+ ...question,
56
+ options: getVisibleRankOrderOptionsForAnswers(
57
+ question, allAnswers, allQuestions, customFieldValues
58
+ ),
59
+ };
60
+ }, [question, allAnswers, allQuestions, customFieldValues]);
61
+
62
+ {question.type === QUESTION_TYPE.RANK_ORDER && rankOrderQuestion && (
63
+ <RankOrderScale
64
+ question={rankOrderQuestion}
65
+ selectedValue={normalizeRankOrderAnswers(
66
+ typeof selectedValue === 'object' && selectedValue !== null && !Array.isArray(selectedValue)
67
+ ? selectedValue
68
+ : undefined
69
+ )}
70
+ onSelect={onSelect}
71
+ />
72
+ )}
73
+ ```
74
+
75
+ ## Dependencies
76
+
77
+ ```bash
78
+ npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
79
+ ```
80
+
81
+ ## Next.js SSR
82
+
83
+ Template uses `'use client'`. For drag-and-drop, optional `dynamic(..., { ssr: false })` in Question.tsx if hydration warnings occur.
84
+
85
+ ## SDK Integration Checklist (agent)
86
+
87
+ - [ ] Copy [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx)
88
+ - [ ] Type literal: `QUESTION_TYPE.RANK_ORDER`
89
+ - [ ] Answer: `RankOrderAnswers`
90
+ - [ ] Visibility: `getVisibleRankOrderOptionsForAnswers(..., customFieldValues?)`
91
+ - [ ] Utils: `assignRankWithoutDuplicates`, `buildRankOrderFromOrderedOptionIds`, `normalizeRankOrderAnswers`
92
+ - [ ] Prefer `option.imageUrl` over `previewImageUrl`
93
+ - [ ] Matrix row: [`question-type-sdk-matrix.md#rank_order`](../00-integration/question-type-sdk-matrix.md#rank_order)
@@ -1,50 +1,51 @@
1
1
  # Client Components Overview
2
2
 
3
- > Wiring blueprints for React components. **Authoritative UI details** are in [`03-ui-specs/`](../03-ui-specs/README.md) (reference-client driven).
3
+ > Wiring blueprints for React components. **Authoritative UI details** are in [`03-ui-specs/`](../03-ui-specs/README.md).
4
4
  > **Required files gate:** [`component-checklist.md`](../00-integration/component-checklist.md)
5
5
  > **Dispatcher template:** [`templates/Question.tsx`](../templates/Question.tsx)
6
- > This folder documents props, `onSelect` wiring, and dispatcher architecture.
6
+ > Read blueprints **per type** from `MANIFEST.json` after survey inventory — not all files are needed for every survey.
7
7
 
8
8
  ## Component Architecture
9
9
 
10
- The UI is driven by a single top-level `SurveyPage` component which iterates over the `currentQuestions` array and passes each `SurveyQuestion` object to the `Question` dispatcher component.
10
+ The UI is driven by `SurveyPage`, which routes by `state.phase` and renders `Question` for each item in `currentQuestions`.
11
11
 
12
12
  ```
13
- SurveyPage (Top-level orchestrator)
13
+ SurveyPage (phase router)
14
14
 
15
- ├── Header (Branding/Logo)
16
- ├── ProgressBar
17
- ├── LanguageSelector
18
- ├── Footer
15
+ ├── IntroPage / PausedPage / EndPage (special phases)
19
16
 
20
- └── Question (Dispatcher, mapped over `currentQuestions`)
21
-
22
- ├── RatingScale (handles 'rating' and 'rating_scale')
23
- ├── CsatScale (handles 'csat')
24
- ├── LikertMatrixScale (handles 'matrix' CFM_MATRIX)
25
- ├── CsatMatrixScale (handles 'matrix' CSAT_MATRIX / 'rating_matrix')
26
- ├── SliderMatrixScale (handles 'slider_matrix')
27
- ├── FileUploadScale (handles 'file_upload')
28
-
29
- ├── (Inline UI for 'radio', 'text', 'text_and_media')
30
-
31
- └── Shared Sub-Components:
32
- ├── CustomSliderTrack (used by csat/matrix sliders)
33
- └── MatrixDropdown (used by matrix dropdowns)
17
+ └── SurveyContent (phase.kind === 'content')
18
+ ├── Header
19
+ ├── ProgressBar
20
+ ├── LanguageSelector
21
+ ├── Question × N (dispatcher)
22
+ ├── Back / Next|Submit nav
23
+ └── Footer
34
24
  ```
35
25
 
36
- ## Styling Approach
26
+ ## Question dispatcher (11 types)
37
27
 
38
- - Built entirely with **Tailwind CSS**.
39
- - **No external UI libraries** (no Material UI, Chakra, etc.).
40
- - The default brand colour is Telekom Magenta: `#e20074`.
41
- - The UI follows a strict, clean, modern corporate aesthetic (card-based layout, subtle borders, pink accents on selection).
28
+ `Question` switches on `question.type` / `QUESTION_TYPE` (no `subType`):
29
+
30
+ | Type | Component |
31
+ |------|-----------|
32
+ | `NPS_SCALE` | `RatingScale` |
33
+ | `MCQ`, `TEXTFIELD`, `TEXT_AND_MEDIA` | Inline in `Question` |
34
+ | `CFM_MATRIX` | `LikertMatrixScale` |
35
+ | `CSAT_MATRIX`, `RATING_MATRIX` | `CsatMatrixScale` |
36
+ | `SLIDER_MATRIX` | `SliderMatrixScale` |
37
+ | `FILE_UPLOAD` | `FileUploadScale` |
38
+ | `HEATMAP` | `HeatmapScale` |
39
+ | `RANK_ORDER` | `RankOrderScale` |
42
40
 
43
- ## The `Question` Dispatcher
41
+ Shared: `CustomSliderTrack`, `MatrixDropdown`
44
42
 
45
- The `Question` component is the heart of the rendering engine. It receives a `SurveyQuestion` union type and switches on `question.type` (and `question.subType` for matrices) to render the correct specialized scale component.
43
+ ## Styling Approach
46
44
 
47
- See `02-question.md` for details on the dispatcher logic.
45
+ - Built entirely with **Tailwind CSS**.
46
+ - **No external UI libraries** (no Material UI, Chakra, etc.).
47
+ - Default brand colour: Telekom Magenta `#e20074`.
48
+ - Card-based layout, subtle borders, pink accents on selection.
48
49
 
49
50
  ## Files in This Folder
50
51
 
@@ -52,14 +53,19 @@ See `02-question.md` for details on the dispatcher logic.
52
53
  |------|-----------|
53
54
  | `01-survey-page.md` | `SurveyPage` orchestrator |
54
55
  | `02-question.md` | `Question` dispatcher & inline types |
55
- | `03-rating-scale.md` | `RatingScale` (NPS/Stars) |
56
- | `04-csat-scale.md` | `CsatScale` (Emoji/Star CSAT) |
57
- | `05-csat-matrix-scale.md` | `CsatMatrixScale` (Satisfaction Grid) |
58
- | `06-likert-matrix-scale.md` | `LikertMatrixScale` (Text Grid) |
59
- | `07-slider-matrix-scale.md` | `SliderMatrixScale` (Sliders Grid) |
56
+ | `03-rating-scale.md` | `RatingScale` (NPS) |
57
+ | `04-star-rating-scale.md` | Legacy star patterns (deprecated) |
58
+ | `05-csat-matrix-scale.md` | `CsatMatrixScale` |
59
+ | `06-likert-matrix-scale.md` | `LikertMatrixScale` |
60
+ | `07-slider-matrix-scale.md` | `SliderMatrixScale` |
60
61
  | `08-file-upload-scale.md` | `FileUploadScale` |
61
- | `09-custom-slider-track.md` | `CustomSliderTrack` (Emoji thumbs) |
62
+ | `09-custom-slider-track.md` | `CustomSliderTrack` |
62
63
  | `10-header-footer.md` | `Header` & `Footer` |
63
64
  | `11-progress-bar.md` | `ProgressBar` |
64
65
  | `12-language-selector.md` | `LanguageSelector` |
65
66
  | `13-matrix-dropdown.md` | `MatrixDropdown` |
67
+ | `14-intro-page.md` | `IntroPage` |
68
+ | `15-end-page.md` | `EndPage` |
69
+ | `16-paused-page.md` | `PausedPage` |
70
+ | `17-heatmap-scale.md` | `HeatmapScale` |
71
+ | `18-rank-order-scale.md` | `RankOrderScale` |
@@ -1,158 +1,160 @@
1
1
  # Config Field Index
2
2
 
3
- > Master map: every SDK config field → reference client file → implemented? → UI spec doc.
3
+ > Master map: every SDK config field → UI spec doc.
4
4
  > Cross-check this when building any question with non-default config.
5
5
 
6
- ## QuestionBase (all types)
7
-
8
- | Field | Types | Client file | Implemented? | Spec doc |
9
- |-------|-------|-------------|--------------|----------|
10
- | `id` | all | Question.tsx | ✅ | 00-question-shell |
11
- | `text` | all | Question.tsx | ✅ | 00-question-shell |
12
- | `description` | all | Question.tsx | ✅ | 00-question-shell |
13
- | `required` | all | Question.tsx | ✅ | 00-question-shell |
14
- | `requiredErrorMessage` | all | Question.tsx | ✅ | 00-question-shell |
15
- | `questionNumber` | all | — | ❌ | 00-question-shell |
16
- | `containerMediaUrl` | all | — | ❌ | 00-question-shell |
17
- | `containerMediaMimeType` | all | — | ❌ | 00-question-shell |
18
- | `containerMediaAlignment` | all | — | ❌ | 00-question-shell |
19
- | `containerMediaSize` | all | — | ❌ | 00-question-shell |
20
-
21
- ## rating
22
-
23
- | Field | Values | Client file | Implemented? | Spec doc |
24
- |-------|--------|-------------|--------------|----------|
25
- | `options[]` | SurveyOption[] | RatingScale.tsx | | 01-rating |
26
- | `options[].color` | hex | RatingScale.tsx | ✅ | 01-rating |
27
- | `minLabel` | string | Question.tsx | ✅ | 01-rating |
28
- | `midLabel` | string | Question.tsx | | 01-rating |
29
- | `maxLabel` | string | Question.tsx | ✅ | 01-rating |
30
- | `midLabelIndex` | number | Question.tsx | ✅ | 01-rating |
31
- | `reverseScaleOrder` | boolean | — | ❌ | 01-rating |
32
- | `buttonVariant` | radio/numbered/emoji | — | ❌ | 01-rating |
33
-
34
- ## radio
35
-
36
- | Field | Values | Client file | Implemented? | Spec doc |
37
- |-------|--------|-------------|--------------|----------|
38
- | `options[]` | SurveyOption[] | Question.tsx | ✅ | 02-radio |
39
- | `isMultiSelect` | boolean | — | ❌ | 02-radio |
40
-
41
- ## text
42
-
43
- | Field | Values | Client file | Implemented? | Spec doc |
44
- |-------|--------|-------------|--------------|----------|
45
- | `placeholder` | string | Question.tsx | | 03-text |
46
- | `maxCharacterCount` | number | Question.tsx | ✅ | 03-text |
47
- | `inputVariant` | long/short | Question.tsx | partial | 03-text |
48
-
49
- ## csat
50
-
51
- | Field | Values | Client file | Implemented? | Spec doc |
52
- |-------|--------|-------------|--------------|----------|
53
- | `options[]` | SurveyOption[] | CsatScale.tsx | | 04-csat |
54
- | `buttonType` | emoji/star/numbered/... | CsatScale.tsx | ✅ | 04-csat |
55
- | `labelPosition` | top/bottom/hidden | CsatScale.tsx | ✅ | 04-csat |
56
- | `minLabel` / `maxLabel` | string | Question.tsx | ✅ | 04-csat |
57
- | `hasNotApplicable` | boolean | — | ❌ | 04-csat |
58
- | `reverseScaleOrder` | boolean | — | ❌ | 04-csat |
59
-
60
- ## rating_scale
61
-
62
- | Field | Values | Client file | Implemented? | Spec doc |
63
- |-------|--------|-------------|--------------|----------|
64
- | `options[]` | SurveyOption[] | — | ❌ | 05-rating-scale |
65
- | `scaleStyle` | star/emoji | | | 05-rating-scale |
66
- | `minLabel` / `midLabel` / `maxLabel` | string | — | ❌ | 05-rating-scale |
67
- | `midLabelIndex` | number | — | ❌ | 05-rating-scale |
68
- | `reverseScaleOrder` | boolean | — | ❌ | 05-rating-scale |
6
+ ## Question shell (all types)
7
+
8
+ | Field | Types | Spec doc |
9
+ |-------|-------|----------|
10
+ | `id` | all | 00-question-shell |
11
+ | `questionText` | all | 00-question-shell |
12
+ | `questionDescription` | all | 00-question-shell |
13
+ | `questionHint` | all | 00-question-shell |
14
+ | `required` | all | 00-question-shell |
15
+ | `requiredErrorMessage` | all | 00-question-shell |
16
+ | `questionNumber` | all | 00-question-shell |
17
+ | `containerMedia` | ContainerMedia? | 00-question-shell |
18
+ | `containerMedia.url` | string | 00-question-shell |
19
+ | `containerMedia.mimeType` | string | 00-question-shell |
20
+ | `containerMedia.alignment` | string | 00-question-shell |
21
+ | `containerMedia.size` | number | 00-question-shell |
22
+
23
+ ## nps
24
+
25
+ | Field | Values | Spec doc |
26
+ |-------|--------|----------|
27
+ | `options[]` | NpsScalePoint[] | 01-rating |
28
+ | `minLabel` / `midLabel` / `maxLabel` | string | 01-rating |
29
+ | `midLabelIndex` | number | 01-rating |
30
+ | `reverseScaleOrder` | boolean | 01-rating |
31
+ | `buttonStyle` | standard/numbered/emoji | 01-rating |
32
+
33
+ ## mcq
34
+
35
+ | Field | Values | Spec doc |
36
+ |-------|--------|----------|
37
+ | `options[]` | McqOption[] | 02-radio |
38
+ | `selectionMode` | single/multiple | 02-radio |
39
+ | `displayFormat` | list/grid | 02-radio |
40
+ | `shuffleOptions` | boolean | 02-radio |
41
+ | `columnCount` | number | 02-radio |
42
+
43
+ ## text_input
44
+
45
+ | Field | Values | Spec doc |
46
+ |-------|--------|----------|
47
+ | `placeholder` | string | 03-text |
48
+ | `maxCharacterCount` | number | 03-text |
49
+ | `inputVariant` | long/short | 03-text |
50
+
51
+ ## csat (matrix grid)
52
+
53
+ | Field | Values | Spec doc |
54
+ |-------|--------|----------|
55
+ | `statementRows[]` | CsatStatementRow[] | 04-csat |
56
+ | `scaleColumns[]` | CsatScaleColumn[] | 04-csat |
57
+ | `displayStyle` | emoji/star/standard/numbered/dropdown/selectbox/graphics | 04-csat |
58
+ | `gridLayout` | standard/carousel/dropdown | 04-csat |
59
+ | `hasNotApplicableOption` | boolean | 04-csat |
60
+ | `reverseScaleOrder` | boolean | 04-csat |
61
+ | `scaleAnchorLabels[]` | string[] | 04-csat |
62
+
63
+ ## star_rating
64
+
65
+ | Field | Values | Spec doc |
66
+ |-------|--------|----------|
67
+ | `options[]` | StarRatingPoint[] | 05-rating-scale |
68
+ | `scaleStyle` | star/emoji | 05-rating-scale |
69
+ | `minLabel` / `midLabel` / `maxLabel` | string | 05-rating-scale |
70
+ | `midLabelIndex` | number | 05-rating-scale |
71
+ | `reverseScaleOrder` | boolean | 05-rating-scale |
69
72
 
70
73
  ## slider
71
74
 
72
- | Field | Values | Client file | Implemented? | Spec doc |
73
- |-------|--------|-------------|--------------|----------|
74
- | `min` / `max` / `step` | number | — | ❌ | 06-slider |
75
- | `defaultValue` | number | — | ❌ | 06-slider |
76
- | `minLabel` / `maxLabel` | string | — | ❌ | 06-slider |
77
- | `enableInputBox` | boolean | SliderMatrixScale.tsx | partial | 06-slider |
78
- | `displayValues` | boolean | CustomSliderTrack.tsx | partial | 06-slider, shared/custom-slider-track |
79
-
80
- ## matrix (shared)
81
-
82
- | Field | Values | Client file | Implemented? | Spec doc |
83
- |-------|--------|-------------|--------------|----------|
84
- | `subType` | CFM/CSAT/RATING | Question.tsx | ✅ | 07, 08 |
85
- | `rows[]` | MatrixRow[] | Likert/CsatMatrix | ✅ | 07, 08 |
86
- | `columns[]` | MatrixColumn[] | Likert/CsatMatrix | ✅ | 07, 08 |
87
- | `matrixFormat` | standard/carousel/dropdown | Likert/CsatMatrix | ✅ | 07, 08 |
88
- | `hasNotApplicable` | boolean | Likert/CsatMatrix | ✅ | 07, 08 |
89
- | `reverseScaleOrder` | boolean | CsatMatrixScale | ✅ | 08 |
90
- | `labels[]` | string[] | Likert/CsatMatrix | ✅ | 07, 08 |
91
- | `buttonType` | SurveyButtonType | CsatMatrixScale | ✅ | 08 |
92
-
93
- ## matrix CFM only
94
-
95
- | Field | Values | Client file | Implemented? | Spec doc |
96
- |-------|--------|-------------|--------------|----------|
97
- | `matrixType` | likert/bipolar | LikertMatrixScale | | 07-matrix-cfm |
98
- | `answerType` | single/multiple | LikertMatrixScale | ✅ | 07-matrix-cfm |
99
- | `transposeTable` | boolean | LikertMatrixScale | | 07-matrix-cfm |
100
- | `repeatScale` | boolean | LikertMatrixScale | ✅ | 07-matrix-cfm |
101
- | `enableScale` | boolean | LikertMatrixScale | ✅ | 07-matrix-cfm |
75
+ | Field | Values | Spec doc |
76
+ |-------|--------|----------|
77
+ | `min` / `max` / `step` | number | 06-slider |
78
+ | `defaultValue` | number | 06-slider |
79
+ | `minLabel` / `maxLabel` | string | 06-slider |
80
+ | `enableInputBox` | boolean | 06-slider |
81
+ | `displayValues` | boolean | 06-slider, shared/custom-slider-track |
82
+
83
+ ## cfm_matrix
84
+
85
+ | Field | Values | Spec doc |
86
+ |-------|--------|----------|
87
+ | `statementRows[]` | CfmMatrixStatementRow[] | 07-matrix-cfm |
88
+ | `scaleColumns[]` | CfmMatrixScaleColumn[] | 07-matrix-cfm |
89
+ | `statementLayout` | likert/bipolar | 07-matrix-cfm |
90
+ | `selectionMode` | single/multiple | 07-matrix-cfm |
91
+ | `gridLayout` | standard/carousel/dropdown | 07-matrix-cfm |
92
+ | `transposeTable` | boolean | 07-matrix-cfm |
93
+ | `repeatColumnHeaders` | boolean | 07-matrix-cfm |
94
+ | `showColumnHeaders` | boolean | 07-matrix-cfm |
95
+ | `hasNotApplicableOption` | boolean | 07-matrix-cfm |
96
+ | `scaleAnchorLabels[]` | string[] | 07-matrix-cfm |
97
+
98
+ ## rating_matrix
99
+
100
+ | Field | Values | Spec doc |
101
+ |-------|--------|----------|
102
+ | Same matrix fields as `csat` | | 08-matrix-csat-rating |
103
+ | `minLabel` / `maxLabel` | string | 08-matrix-csat-rating |
102
104
 
103
105
  ## slider_matrix
104
106
 
105
- | Field | Values | Client file | Implemented? | Spec doc |
106
- |-------|--------|-------------|--------------|----------|
107
- | `rows[].min/max/step` | number | SliderMatrixScale | ✅ | 09-slider-matrix |
108
- | `labels[]` | string[] | SliderMatrixScale | ✅ | 09-slider-matrix |
109
- | `ticks` | number | SliderMatrixScale | ✅ | 09-slider-matrix |
110
- | `tickValues[]` | TickValue[] | SliderMatrixScale | ✅ | 09-slider-matrix |
111
- | `enableInputBox` | boolean | SliderMatrixScale | ✅ | 09-slider-matrix |
112
- | `displayValues` | boolean | CustomSliderTrack | ✅ | 09-slider-matrix |
113
- | `enableNotApplicable` | boolean | SliderMatrixScale | ✅ | 09-slider-matrix |
114
- | `sliderType` | graphics | SliderMatrixScale | ✅ | 09-slider-matrix |
107
+ | Field | Values | Spec doc |
108
+ |-------|--------|----------|
109
+ | `statementRows[].min/max/step` | number | 09-slider-matrix |
110
+ | `scaleAnchorLabels[]` | string[] | 09-slider-matrix |
111
+ | `tickMarks` | number | 09-slider-matrix |
112
+ | `enableInputBox` | boolean | 09-slider-matrix |
113
+ | `displayValues` | boolean | 09-slider-matrix |
114
+ | `hasNotApplicableOption` | boolean | 09-slider-matrix |
115
+ | `sliderStyle` | graphics | 09-slider-matrix |
115
116
 
116
117
  ## file_upload
117
118
 
118
- | Field | Values | Client file | Implemented? | Spec doc |
119
- |-------|--------|-------------|--------------|----------|
120
- | `uploadMessage` | HTML string | FileUploadScale | ✅ | 10-file-upload |
121
- | `supportedFileFormats` | string[] | FileUploadScale | ✅ | 10-file-upload |
122
- | `maxFileCount` | number | FileUploadScale | ✅ | 10-file-upload |
123
- | `fileSizeLimit` | number (MB) | FileUploadScale | ✅ | 10-file-upload |
124
- | `fileSizeLimitType` | PER_FILE/IN_TOTAL | FileUploadScale | ✅ | 10-file-upload |
119
+ | Field | Values | Spec doc |
120
+ |-------|--------|----------|
121
+ | `uploadMessage` | HTML string | 10-file-upload |
122
+ | `supportedFileFormats` | string[] | 10-file-upload |
123
+ | `maxFileCount` | number | 10-file-upload |
124
+ | `fileSizeLimit` | number (MB) | 10-file-upload |
125
+ | `fileSizeLimitType` | PER_FILE/IN_TOTAL | 10-file-upload |
125
126
 
126
127
  ## text_and_media
127
128
 
128
- | Field | Values | Client file | Implemented? | Spec doc |
129
- |-------|--------|-------------|--------------|----------|
130
- | `mediaUrl` | string | Question.tsx | ✅ | 11-text-and-media |
131
- | `mediaMimeType` | string | Question.tsx | ✅ | 11-text-and-media |
132
- | `mediaTitle` | string | Question.tsx | ✅ | 11-text-and-media |
133
- | `mediaAlignment` | string | Question.tsx | ✅ | 11-text-and-media |
134
- | `mediaSize` | number (%) | Question.tsx | ✅ | 11-text-and-media |
135
-
136
- ## Implementation Gaps (no client branch yet)
137
-
138
- | Gap | SDK type/field | Extend from |
139
- |-----|----------------|-------------|
140
- | `rating_scale` dispatcher | `type: 'rating_scale'` | CsatScale star/emoji patterns |
141
- | `slider` dispatcher | `type: 'slider'` | CustomSliderTrack + SliderMatrixScale row |
142
- | `radio.isMultiSelect` | checkbox cards | 02-radio card styling |
143
- | `text.inputVariant: 'short'` | single-line input | 03-text focus tokens |
144
- | `rating.reverseScaleOrder` | reverse options array | 01-rating |
145
- | `rating.buttonVariant` | numbered clickable badges | 01-rating |
146
- | `csat.hasNotApplicable` / `reverseScaleOrder` | standalone CSAT | 04-csat, 08-matrix N/A |
147
- | `containerMedia*` on any type | container asset | 11-text-and-media media block |
148
-
149
- ## buttonType × matrixFormat Quick Reference
150
-
151
- | buttonType | matrixFormat | Layout component | Spec |
152
- |------------|--------------|------------------|------|
129
+ | Field | Values | Spec doc |
130
+ |-------|--------|----------|
131
+ | `media` | QuestionMedia? | 11-text-and-media |
132
+ | `media.url` | string | 11-text-and-media |
133
+ | `media.mimeType` | string | 11-text-and-media |
134
+ | `media.title` | string | 11-text-and-media |
135
+ | `media.alignment` | string | 11-text-and-media |
136
+ | `media.size` | number | 11-text-and-media |
137
+ | `mediaTitle` | string | 11-text-and-media |
138
+ | `mediaAlignment` | string | 11-text-and-media |
139
+ | `mediaSize` | number (%) | 11-text-and-media |
140
+
141
+ ## displayStyle × gridLayout Quick Reference
142
+
143
+ | displayStyle | gridLayout | Layout component | Spec |
144
+ |--------------|------------|------------------|------|
153
145
  | (CFM default) | standard | LikertMatrixGrid | 07 |
154
146
  | (CFM default) | carousel | LikertMatrixCarousel | 07 |
155
147
  | (CFM default) | dropdown | LikertMatrixDropdown | 07 |
156
- | emoji/star/numbered | standard | CsatMatrixGrid | 08 |
157
- | emoji/star/numbered/graphics | carousel | CsatMatrixCarousel | 08 |
158
- | dropdown/selectbox/radio | any | CsatMatrixVerticalList | 08 |
148
+ | emoji/star/numbered | standard | CsatMatrixGrid | 04 |
149
+ | emoji/star/numbered/graphics | carousel | CsatMatrixCarousel | 04 |
150
+ | dropdown/selectbox | any | CsatMatrixVerticalList | 04 |
151
+
152
+ ## Shared spec triggers
153
+
154
+ When these config values appear, also read `03-ui-specs/shared/`:
155
+
156
+ | Config | Read |
157
+ |--------|------|
158
+ | `gridLayout: dropdown` | `matrix-dropdown.md` |
159
+ | `displayStyle: dropdown` or `selectbox` | `matrix-dropdown.md` |
160
+ | `displayStyle: graphics` or `sliderStyle: graphics` | `custom-slider-track.md` |