@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,128 @@
1
+ # Rank Order UI Spec (`RANK_ORDER`)
2
+
3
+ > **Reference:** `02-reference/question-types/13-rank-order.md`
4
+ > **Blueprint:** `01-components/18-rank-order-scale.md`
5
+ > **Portable template:** copy [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx)
6
+
7
+ ## Config gate
8
+
9
+ | Field | Values | UI branch |
10
+ |-------|--------|-----------|
11
+ | `interactionMode` | `'dropdown'` | Rank `<select>` per row |
12
+ | `interactionMode` | `'dragAndDrop'` | `@dnd-kit` sortable list |
13
+ | `optionDisplay` | `textOnly` / `imageOnly` / `textAndImage` | Option content layout |
14
+ | `requireRankAll` | boolean | Validation (SDK) |
15
+ | `shuffleOptions` | boolean | **SDK shuffles at fetch** — render `question.options` as-is; do not re-shuffle client-side |
16
+
17
+ ## Dependencies
18
+
19
+ ```bash
20
+ npm install @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities
21
+ ```
22
+
23
+ Next.js: template includes `'use client'`. Optional in `Question.tsx`:
24
+
25
+ ```tsx
26
+ const RankOrderScale = dynamic(() => import('./RankOrderScale').then(m => ({ default: m.RankOrderScale })), {
27
+ ssr: false,
28
+ loading: () => <p>Loading rank order…</p>,
29
+ });
30
+ ```
31
+
32
+ ## SDK wiring
33
+
34
+ ```typescript
35
+ import {
36
+ getVisibleRankOrderOptionsForAnswers,
37
+ normalizeRankOrderAnswers,
38
+ assignRankWithoutDuplicates,
39
+ buildRankOrderFromOrderedOptionIds,
40
+ getOrderedOptionIdsFromRanks,
41
+ } from '@explorer02/cfm-survey-sdk';
42
+
43
+ // Question.tsx — filter options + normalize answer
44
+ const rankOrderQuestion = {
45
+ ...question,
46
+ options: getVisibleRankOrderOptionsForAnswers(question, allAnswers, allQuestions, customFieldValues),
47
+ };
48
+ <RankOrderScale
49
+ question={rankOrderQuestion}
50
+ selectedValue={normalizeRankOrderAnswers(selectedValue)}
51
+ onSelect={onSelect}
52
+ />
53
+ ```
54
+
55
+ Answer shape: `RankOrderAnswers` = `Record<optionId, rank>` (1-based).
56
+
57
+ ## Interaction modes
58
+
59
+ ### Dropdown (`interactionMode: 'dropdown'`)
60
+
61
+ | Element | Behavior |
62
+ |---------|----------|
63
+ | Rank select | `-` (unassigned) or `1..N` per option row |
64
+ | Duplicate ranks | `assignRankWithoutDuplicates` clears rank R from other options |
65
+ | Layout | Rank select left, option content right |
66
+
67
+ ### Drag and drop (`interactionMode: 'dragAndDrop'`)
68
+
69
+ | Element | Behavior |
70
+ |---------|----------|
71
+ | Drag handle | Six-dot grip; `PointerSensor` + `KeyboardSensor` |
72
+ | Rank badge | Circular badge showing 1-based position |
73
+ | Reorder | List order → `buildRankOrderFromOrderedOptionIds(orderedIds)` |
74
+ | Up/Down | Keyboard fallback; disabled on first/last |
75
+
76
+ ## Implementation Recipe — dnd-kit
77
+
78
+ ```typescript
79
+ const sensors = useSensors(
80
+ useSensor(PointerSensor),
81
+ useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
82
+ );
83
+
84
+ const handleDragEnd = (event: DragEndEvent) => {
85
+ const { active, over } = event;
86
+ if (!over || active.id === over.id) return;
87
+ const oldIndex = orderedOptionIds.indexOf(String(active.id));
88
+ const newIndex = orderedOptionIds.indexOf(String(over.id));
89
+ if (oldIndex === -1 || newIndex === -1) return;
90
+ onSelect(buildRankOrderFromOrderedOptionIds(arrayMove(orderedOptionIds, oldIndex, newIndex)));
91
+ };
92
+ ```
93
+
94
+ Wrap list in `<DndContext collisionDetection={closestCenter}>` + `<SortableContext strategy={verticalListSortingStrategy}>`.
95
+
96
+ Copy full implementation from [`templates/RankOrderScale.tsx`](../templates/RankOrderScale.tsx).
97
+
98
+ ## Option display
99
+
100
+ | `optionDisplay` | Render |
101
+ |-----------------|--------|
102
+ | `textOnly` | Label via `dangerouslySetInnerHTML` |
103
+ | `imageOnly` | Square thumbnail; prefer `option.imageUrl` over `previewImageUrl` |
104
+ | `textAndImage` | Thumbnail + label side by side |
105
+
106
+ ## Validation UX
107
+
108
+ - Required + `requireRankAll`: every visible option unique rank 1..N
109
+ - Required + not `requireRankAll`: at least one visible option ranked
110
+ - Show `validationError` from question shell
111
+
112
+ ## Styling
113
+
114
+ - Border `#e5e5e5`, optional `#e20074` when ranked
115
+ - Rank badge: `#fdf2f8` bg, `#e20074` text
116
+
117
+ ## Logic
118
+
119
+ RANK_ORDER operators (ranked as/above/below) — see [`logic-fields-catalog.md`](../00-integration/logic-fields-catalog.md).
120
+
121
+ ## Agent checklist
122
+
123
+ - [ ] Copied `templates/RankOrderScale.tsx` (or equivalent dnd-kit + dropdown)
124
+ - [ ] `@dnd-kit/*` in package.json when survey has RANK_ORDER
125
+ - [ ] `getVisibleRankOrderOptionsForAnswers` + `normalizeRankOrderAnswers`
126
+ - [ ] `option.imageUrl` before `previewImageUrl`
127
+ - [ ] No client-side re-shuffle when `shuffleOptions` is true
128
+ - [ ] No stub placeholder text
@@ -1,7 +1,7 @@
1
1
  # UI Specifications — Reference Implementation Guide
2
2
 
3
- > **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx). The monorepo path `apps/client/src/components/` is **not** available in client projects.
4
- > **For monorepo devs:** cross-check against [`apps/client/src/components/`](../../../../../../apps/client/src/components/).
3
+ > **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx).
4
+ > **For monorepo devs:** Reference client at `apps/client/src/components/` aligns with SDK types — trust `03-ui-specs/`, `templates/Question.tsx`, and exported types.
5
5
  > Read the spec for **each question type present** in the fetched survey before writing React code.
6
6
 
7
7
  ## How to Read a UI Spec
@@ -38,24 +38,26 @@ Each file in this folder follows the same structure:
38
38
  | Spec file | Reference component | `question.type` |
39
39
  |-----------|---------------------|-----------------|
40
40
  | [00-question-shell.md](00-question-shell.md) | `Question.tsx` | All (wrapper) |
41
- | [01-rating.md](01-rating.md) | `RatingScale.tsx` | `rating` |
42
- | [02-radio.md](02-radio.md) | `Question.tsx` inline | `radio` |
43
- | [03-text.md](03-text.md) | `Question.tsx` inline | `text` |
44
- | [04-csat.md](04-csat.md) | `CsatScale.tsx` | `csat` |
45
- | [05-rating-scale.md](05-rating-scale.md) | *(gap — reuse CsatScale patterns)* | `rating_scale` |
46
- | [06-slider.md](06-slider.md) | *(gap — reuse CustomSliderTrack)* | `slider` |
47
- | [07-matrix-cfm.md](07-matrix-cfm.md) | `LikertMatrixScale.tsx` | `matrix` + CFM |
48
- | [08-matrix-csat-rating.md](08-matrix-csat-rating.md) | `CsatMatrixScale.tsx` | CSAT/RATING matrix |
41
+ | [01-rating.md](01-rating.md) | `RatingScale.tsx` | `NPS_SCALE` |
42
+ | [02-radio.md](02-radio.md) | `Question.tsx` inline | `MCQ` |
43
+ | [03-text.md](03-text.md) | `Question.tsx` inline | `TEXTFIELD` |
44
+ | [04-csat.md](04-csat.md) | `CsatMatrixScale.tsx` | `CSAT_MATRIX` |
45
+ | [05-rating-scale.md](05-rating-scale.md) | `RatingScale.tsx` | `star_rating` |
46
+ | [06-slider.md](06-slider.md) | `CustomSliderTrack.tsx` | `slider` |
47
+ | [07-matrix-cfm.md](07-matrix-cfm.md) | `LikertMatrixScale.tsx` | `cfm_matrix` |
48
+ | [08-matrix-csat-rating.md](08-matrix-csat-rating.md) | `CsatMatrixScale.tsx` | `rating_matrix` |
49
49
  | [09-slider-matrix.md](09-slider-matrix.md) | `SliderMatrixScale.tsx` | `slider_matrix` |
50
50
  | [10-file-upload.md](10-file-upload.md) | `FileUploadScale.tsx` | `file_upload` |
51
- | [11-text-and-media.md](11-text-and-media.md) | `Question.tsx` inline | `text_and_media` |
51
+ | [11-text-and-media.md](11-text-and-media.md) | `Question.tsx` inline | `TEXT_AND_MEDIA` |
52
+ | [13-heatmap.md](13-heatmap.md) | `HeatmapScale.tsx` | `HEATMAP` |
53
+ | [14-rank-order.md](14-rank-order.md) | `RankOrderScale.tsx` | `RANK_ORDER` |
52
54
  | [12-survey-chrome.md](12-survey-chrome.md) | `SurveyPage.tsx` + chrome | Shell |
53
55
  | [shared/custom-slider-track.md](shared/custom-slider-track.md) | `CustomSliderTrack.tsx` | Primitive |
54
56
  | [shared/matrix-dropdown.md](shared/matrix-dropdown.md) | `MatrixDropdown.tsx` | Primitive |
55
57
 
56
58
  ## NPS Traffic-Light Colors
57
59
 
58
- Use `option.color` from SDK — never invent colors:
60
+ Use accent colors from SDK options — never invent colors for NPS:
59
61
 
60
62
  | Value | Hex |
61
63
  |-------|-----|
@@ -73,8 +75,8 @@ Use `option.color` from SDK — never invent colors:
73
75
 
74
76
  ## When to Read
75
77
 
76
- After Phase 3 in [`index.md`](../index.md), for each question in `state.currentQuestions`:
78
+ After Phase 3 in [`index.md`](../index.md), for each question in the fetched survey:
77
79
 
78
80
  1. Read [`02-reference/question-types/`](../02-reference/question-types/) for data shape
79
- 2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `uiSpecs`)
81
+ 2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `questionTypes.{type}.uiSpec`)
80
82
  3. Cross-check [`config-field-index.md`](../02-reference/config-field-index.md)
@@ -1,52 +1,45 @@
1
1
  # UI Spec: Custom Slider Track (shared primitive)
2
2
 
3
- > **Implement from this spec** (npm installs). Monorepo reference: `apps/client/src/components/CustomSliderTrack.tsx`
4
- > **Used by:** `SliderMatrixScale.tsx`, `CsatMatrixScale` (graphics), standalone `slider` (gap)
3
+ > **Portable template:** copy [`templates/CustomSliderTrack.tsx`](../templates/CustomSliderTrack.tsx) + [`templates/surveyUiIcons.tsx`](../templates/surveyUiIcons.tsx)
4
+ > **Used by:** `SliderMatrixScale`, `CsatMatrixScale` (graphics), matrix `displayStyle: graphics`
5
+
6
+ ## Scale column labels (Day 19 — CRITICAL)
7
+
8
+ Matrix rows must pass **`tickLabels` from `scaleColumns[].label`** (filtered to visible columns):
9
+
10
+ ```typescript
11
+ const tickLabels = visibleScaleColumns.map(col => col.label);
12
+ <CustomSliderTrack tickLabels={tickLabels} ticks={tickLabels.length} ... />
13
+ ```
14
+
15
+ Tooltip shows stripped HTML from `tickLabels[tickIndex]`; without labels, tooltips fall back to numeric value only.
5
16
 
6
17
  ## Layer Architecture
7
18
 
8
19
  ```
9
- 1. Gray inactive track (#e5e7eb, 4px height)
10
- 2. Magenta fill bar (width = percentage%, #e20074 or #9ca3af if disabled)
11
- 3. Tick marks (1px × 8px at ticks positions)
12
- 4. Invisible <input type="range"> overlay (opacity 0, full hit area)
13
- 5. Visual thumb: circle OR emoji (sliderType === 'graphics')
14
- 6. Tooltip bubble on hover/drag (#1f2937 bg, rounded value)
20
+ 1. Gray inactive track (#e5e7eb, 4px)
21
+ 2. Magenta fill bar (percentage%, #e20074 or #9ca3af if disabled)
22
+ 3. Tick marks at column positions
23
+ 4. Invisible <input type="range"> overlay
24
+ 5. Thumb: circle OR emoji (sliderType === 'graphics')
25
+ 6. Tooltip on hover/drag (#1f2937)
15
26
  ```
16
27
 
17
28
  ## Props
18
29
 
19
30
  | Prop | Role |
20
31
  |------|------|
21
- | `min`, `max`, `htmlStep` | Range input bounds |
32
+ | `min`, `max`, `htmlStep` | Range bounds |
22
33
  | `value` | Current position |
23
- | `disabled` | Gray theme, opacity 0.5, no interaction |
24
- | `displayValues` | Reserved tooltip always shows on hover/drag in client |
25
- | `hasSelectedValue` | Reserved |
26
- | `sliderType: 'graphics'` | Emoji thumb via `getEmojiForIndex` |
27
- | `ticks` | Discrete tick count + emoji index scale |
28
- | `reverseScaleOrder` | Flip emoji index calculation |
29
-
30
- ## Interactive States
31
-
32
- | State | Thumb | Tooltip |
33
- |-------|-------|---------|
34
- | Default | White circle, 2.5px magenta border | Hidden |
35
- | Hover/drag | Pink glow ring `rgba(226,0,116,0.2)` | Dark bubble with `Math.round(value)` |
36
- | Disabled | Gray border, opacity 0.5 | Hidden |
37
- | Graphics | Emoji at percentage position | Same tooltip |
38
-
39
- ## Emoji Index Formula
40
-
41
- ```typescript
42
- const idx = Math.round(((value - min) / (max - min)) * ((ticks || 10) - 1));
43
- const displayIdx = reverseScaleOrder ? (ticks || 10) - 1 - idx : idx;
44
- getEmojiForIndex(displayIdx, ticks || 10)
45
- ```
34
+ | `disabled` | Gray theme, opacity 0.5 |
35
+ | `sliderType: 'graphics'` | Emoji thumb via `surveyUiIcons.getEmojiForIndex` |
36
+ | `ticks` | Discrete tick count |
37
+ | **`tickLabels`** | **Column labels for tooltip + graphics index** |
38
+ | `reverseScaleOrder` | Flip emoji index |
46
39
 
47
40
  ## Agent Checklist
48
41
 
49
- - [ ] 4-layer overlay with invisible range input
42
+ - [ ] Copy portable template or match layer stack
43
+ - [ ] Always pass `tickLabels` from matrix `scaleColumns` when available
50
44
  - [ ] Tooltip on hover AND drag
51
- - [ ] Graphics mode emoji thumb
52
- - [ ] Transition disabled while dragging
45
+ - [ ] Graphics emoji thumb with `reverseScaleOrder` support
@@ -30,6 +30,11 @@ if (val === null) {
30
30
  // When null selected, non-null options disabled
31
31
  ```
32
32
 
33
+ ## Props
34
+
35
+ - `options: ScaleColumn[]` — matrix scale columns (`id`, `label`)
36
+ - `value` / `onChange` — stored values use `matrixColumnStoredValue(col)` → column **`id`**
37
+
33
38
  ## Agent Checklist
34
39
 
35
40
  - [ ] Click-outside closes panel