@explorer02/cfm-survey-sdk 0.2.3 → 0.2.5
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.
- package/dist/cli/index.js +141 -33
- package/dist/cli/index.mjs +141 -33
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +3 -1
- package/postinstall.js +9 -5
- package/templates/AGENT.md +60 -19
- package/templates/deploy-wizard-to-s3.sh +52 -0
- package/templates/docs/00-integration/agent-execution-flow.md +293 -0
- package/templates/docs/00-integration/agent-operating-contract.md +268 -0
- package/templates/docs/00-integration/apply-ui-config.md +390 -0
- package/templates/docs/00-integration/aws-deploy.md +117 -3
- package/templates/docs/00-integration/canonical-survey-fixtures.md +94 -0
- package/templates/docs/00-integration/client-integration-guide.md +9 -7
- package/templates/docs/00-integration/client-lib-folder.md +115 -0
- package/templates/docs/00-integration/component-checklist.md +90 -62
- package/templates/docs/00-integration/constraints.md +14 -5
- package/templates/docs/00-integration/custom-field-logic-and-navigation.md +56 -0
- package/templates/docs/00-integration/mockup-ui-extraction.md +113 -0
- package/templates/docs/00-integration/placeholders-and-custom-fields-wiring.md +192 -0
- package/templates/docs/00-integration/placeholders-and-tokens.md +2 -1
- package/templates/docs/00-integration/progress.md +4 -2
- package/templates/docs/00-integration/setup.md +12 -0
- package/templates/docs/00-integration/ui-customization-wizard.md +123 -0
- package/templates/docs/00-integration/useSurveySDK.md +35 -1
- package/templates/docs/00-integration/wizard-api.md +126 -0
- package/templates/docs/00-integration/wizard-config-handoff.md +292 -0
- package/templates/docs/00-integration/wizard-preview-build-guide.md +405 -0
- package/templates/docs/00-integration/wizard-question-type-styling.md +197 -0
- package/templates/docs/00-integration/wizard-troubleshooting.md +80 -0
- package/templates/docs/01-components/01-survey-page.md +18 -8
- package/templates/docs/01-components/02-question.md +2 -2
- package/templates/docs/01-components/03-rating-scale.md +12 -18
- package/templates/docs/01-components/05-csat-matrix-scale.md +18 -26
- package/templates/docs/01-components/06-likert-matrix-scale.md +19 -39
- package/templates/docs/01-components/07-slider-matrix-scale.md +48 -33
- package/templates/docs/01-components/09-custom-slider-track.md +15 -25
- package/templates/docs/01-components/10-header-footer.md +23 -4
- package/templates/docs/01-components/11-progress-bar.md +14 -6
- package/templates/docs/01-components/19-survey-sticky-chrome.md +79 -0
- package/templates/docs/01-components/README.md +2 -2
- package/templates/docs/02-reference/question-types/10-slider-matrix.md +38 -26
- package/templates/docs/02-reference/routing-table.md +1 -0
- package/templates/docs/02-reference/value-derivation.md +1 -1
- package/templates/docs/03-ui-specs/00-question-shell.md +10 -0
- package/templates/docs/03-ui-specs/01-rating.md +18 -0
- package/templates/docs/03-ui-specs/02-radio.md +16 -1
- package/templates/docs/03-ui-specs/03-text.md +12 -1
- package/templates/docs/03-ui-specs/04-csat.md +84 -50
- package/templates/docs/03-ui-specs/06-slider.md +3 -1
- package/templates/docs/03-ui-specs/07-matrix-cfm.md +71 -48
- package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +48 -18
- package/templates/docs/03-ui-specs/09-slider-matrix.md +59 -32
- package/templates/docs/03-ui-specs/10-file-upload.md +11 -0
- package/templates/docs/03-ui-specs/11-text-and-media.md +4 -0
- package/templates/docs/03-ui-specs/12-survey-chrome.md +54 -5
- package/templates/docs/03-ui-specs/13-heatmap.md +12 -1
- package/templates/docs/03-ui-specs/14-rank-order.md +11 -0
- package/templates/docs/03-ui-specs/README.md +4 -2
- package/templates/docs/03-ui-specs/shared/matrix-dropdown.md +1 -1
- package/templates/docs/MANIFEST.json +180 -7
- package/templates/docs/index.md +114 -117
- package/templates/docs/templates/CsatMatrixScale.tsx +637 -0
- package/templates/docs/templates/FileUploadScale.tsx +262 -0
- package/templates/docs/templates/HeatmapScale.tsx +114 -0
- package/templates/docs/templates/LikertMatrixScale.tsx +414 -0
- package/templates/docs/templates/Question.tsx +3 -0
- package/templates/docs/templates/RatingScale.tsx +129 -0
- package/templates/docs/templates/SliderMatrixScale.tsx +248 -0
- package/templates/docs/templates/SurveyStickyChrome.tsx +24 -0
- package/templates/docs/templates/customFieldValues.ts +36 -0
- package/templates/docs/templates/deploy-to-aws.sh +74 -0
- package/templates/docs/templates/implementation_plan.md +64 -10
- package/templates/docs/templates/labelStyles.ts +33 -0
- package/templates/docs/templates/selectionStyles.ts +100 -0
- package/templates/docs/templates/surveyUiIcons.tsx +11 -0
- package/templates/docs/templates/surveyUiScaleUtils.ts +51 -0
- package/templates/docs/templates/verify-agent-build.sh +119 -0
- package/templates/preview-harness/preview-bridge.inline.js +201 -0
- package/templates/preview-harness/previewPages.js +108 -0
- package/templates/preview-harness/previewPages.ts +298 -0
- package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +67 -0
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +122 -0
- package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +75 -0
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +311 -0
- package/templates/preview-harness/vite-app/src/globals.css +16 -0
- package/templates/preview-harness/vite-app/src/mount.tsx +9 -0
- package/templates/preview-harness/vite-app/src/preview-live-overrides.css +101 -0
- package/templates/preview-harness/vite-app/stubs/next-dynamic.tsx +25 -0
- package/templates/preview-harness/vite-app/stubs/next-image.tsx +29 -0
- package/templates/previewBridge.ts +153 -0
- package/templates/survey-theme.css +295 -0
- package/templates/survey-ui-config.schema.json +213 -0
- package/templates/wizard-dist/assets/PreviewMock-AoZdAEPZ.js +1 -0
- package/templates/wizard-dist/assets/TypePanel-39FnbtvG.js +1 -0
- package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
- package/templates/wizard-dist/assets/index-CWKdsJOp.js +34 -0
- package/templates/wizard-dist/assets/vendor-BwkXDkd3.js +17 -0
- package/templates/wizard-dist/index.html +20 -0
- package/templates/wizard.html +13 -1129
|
@@ -1,78 +1,105 @@
|
|
|
1
1
|
# UI Spec: Slider Matrix (`type: 'SLIDER_MATRIX'`)
|
|
2
2
|
|
|
3
|
-
> **
|
|
3
|
+
> **COPY TEMPLATE FIRST:** [`templates/SliderMatrixScale.tsx`](../templates/SliderMatrixScale.tsx) + [`CustomSliderTrack.tsx`](../templates/CustomSliderTrack.tsx) + [`surveyUiScaleUtils.ts`](../templates/surveyUiScaleUtils.ts)
|
|
4
|
+
>
|
|
5
|
+
> **Anti-pattern:** Do NOT build custom range overlay sliders. Lone pink circle with no track = broken implementation.
|
|
6
|
+
>
|
|
4
7
|
> **SDK type:** `SliderMatrixQuestion` — `fetchSurvey/types/sliderMatrix.ts`
|
|
5
8
|
> **Component blueprint:** `01-components/07-slider-matrix-scale.md`
|
|
6
|
-
> **Shared:** [`shared/custom-slider-track.md`](shared/custom-slider-track.md)
|
|
7
9
|
|
|
8
10
|
## Config Inventory
|
|
9
11
|
|
|
10
12
|
| Field | Implemented | UI impact |
|
|
11
13
|
|-------|-------------|-----------|
|
|
12
|
-
| `
|
|
13
|
-
| `
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `sliderType: 'graphics'` | ✅ | Plain text tick labels; emoji thumb |
|
|
14
|
+
| `statementRows[]` (min/max/step) | ✅ | Per-row slider + **25% statement column** |
|
|
15
|
+
| `scaleAnchorLabels?` | ✅ | Text labels above tick badge row |
|
|
16
|
+
| `ticks.count` + `ticks.marks[]` | ✅ | Colored header badges (`tickPosition`, `tickLabel`) |
|
|
17
|
+
| `sliderStyle: 'graphics'` | ✅ | Plain text tick labels; emoji thumb |
|
|
17
18
|
| `enableInputBox` | ✅ | 80px input + stepper buttons |
|
|
18
19
|
| `displayValues` | ✅ | Passed to CustomSliderTrack |
|
|
19
|
-
| `
|
|
20
|
+
| `hasNotApplicableOption` | ✅ | Checkbox; answer value **`'N/A'`** string |
|
|
20
21
|
|
|
21
22
|
## Layout Anatomy
|
|
22
23
|
|
|
23
24
|
```
|
|
24
|
-
[header:
|
|
25
|
+
[header: scaleAnchorLabels? + colored tick badges from ticks.marks]
|
|
25
26
|
┌─ row band (#f3f4f6, rounded-xl) ─────────────────────────────┐
|
|
26
|
-
│ 25%
|
|
27
|
+
│ 25% statementText │ CustomSliderTrack │ 80px input? │ N/A? │
|
|
27
28
|
└───────────────────────────────────────────────────────────────┘
|
|
28
29
|
```
|
|
29
30
|
|
|
30
|
-
##
|
|
31
|
+
## Statement text (CRITICAL)
|
|
32
|
+
|
|
33
|
+
Every row MUST show `statementRows[].statementText` in the left 25% column:
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
<div style={{ flex: '0 0 25%', paddingRight: '16px' }}>
|
|
37
|
+
{row.statementText && row.statementText !== 'Question' && (
|
|
38
|
+
<span dangerouslySetInnerHTML={{ __html: row.statementText }} />
|
|
39
|
+
)}
|
|
40
|
+
</div>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Agents that hide statement text or merge it into the question title break multi-row sliders.
|
|
44
|
+
|
|
45
|
+
## Header tick badges
|
|
31
46
|
|
|
32
47
|
```typescript
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
48
|
+
tickValues = ticks.marks.map((mark, i) => ({
|
|
49
|
+
value: mark.tickPosition,
|
|
50
|
+
label: mark.tickLabel,
|
|
51
|
+
color: tickColorFromIndex(i, ticks.count),
|
|
52
|
+
}));
|
|
53
|
+
percentage = ((tv.value - min) / (max - min)) * 100;
|
|
54
|
+
htmlStep = ticks.count > 1 ? (max - min) / (ticks.count - 1) : row.step;
|
|
37
55
|
```
|
|
38
56
|
|
|
39
|
-
## CustomSliderTrack per row
|
|
57
|
+
## CustomSliderTrack per row
|
|
40
58
|
|
|
41
59
|
```typescript
|
|
42
60
|
<CustomSliderTrack
|
|
43
61
|
min={row.min}
|
|
44
62
|
max={row.max}
|
|
45
|
-
htmlStep={
|
|
63
|
+
htmlStep={htmlStep}
|
|
46
64
|
value={rowVal as number}
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
disabled={rowVal === 'N/A'}
|
|
66
|
+
hasSelectedValue={typeof rowVal === 'number'}
|
|
67
|
+
displayValues={displayValues}
|
|
49
68
|
sliderType={question.sliderStyle === 'graphics' ? 'graphics' : undefined}
|
|
69
|
+
ticks={ticks.count}
|
|
50
70
|
onChange={v => updateRow(row.id, v)}
|
|
51
71
|
/>
|
|
52
72
|
```
|
|
53
73
|
|
|
54
|
-
Pass **`scaleColumns[].label`** (or row tick labels) as `tickLabels` — required for correct tooltip text (Day 19 fix).
|
|
55
|
-
|
|
56
74
|
## N/A Behavior
|
|
57
75
|
|
|
58
|
-
- Checked → `rowVal === 'N/A'`; slider disabled
|
|
76
|
+
- Checked → `rowVal === 'N/A'`; slider disabled
|
|
59
77
|
- Unchecked → reset to `defaultValue ?? min`
|
|
60
78
|
|
|
61
|
-
## Input Box
|
|
62
|
-
|
|
63
|
-
- Clamp to row.min / row.max on change
|
|
64
|
-
- Steppers use `htmlStep` increment/decrement
|
|
65
|
-
|
|
66
79
|
## Answer Mutation
|
|
67
80
|
|
|
68
81
|
```typescript
|
|
69
|
-
onSelect(Record<string, number |
|
|
82
|
+
onSelect(Record<string, number | 'N/A'>)
|
|
83
|
+
onAction({ type: 'CHANGE', payload: { questionId, answerValue: MatrixRowAnswers } })
|
|
70
84
|
```
|
|
71
85
|
|
|
72
86
|
## Agent Checklist
|
|
73
87
|
|
|
74
|
-
- [ ]
|
|
75
|
-
- [ ]
|
|
88
|
+
- [ ] Copied portable templates — did not build slider from scratch
|
|
89
|
+
- [ ] Shared header with colored 0–10 badges (even single-row questions)
|
|
90
|
+
- [ ] Gray row bands with **visible** statement text in 25% column
|
|
76
91
|
- [ ] CustomSliderTrack per row with correct htmlStep
|
|
77
|
-
- [ ]
|
|
78
|
-
|
|
92
|
+
- [ ] N/A uses `'N/A'` string, not null
|
|
93
|
+
|
|
94
|
+
## Wizard customization (Phase 5 — required)
|
|
95
|
+
|
|
96
|
+
| Control | CSS vars | Apply in |
|
|
97
|
+
|---------|----------|----------|
|
|
98
|
+
| Tick label items | `--cfm-slider-tick-label-color`, `--cfm-slider-tick-label-bg` | Header badge row — `sliderTickLabelStyle()` |
|
|
99
|
+
| Row band | `--cfm-slider-row-bg` | Gray statement band |
|
|
100
|
+
| Thumb selection | `--cfm-matrix-selected`, `--cfm-input-focus-ring` | `CustomSliderTrack` thumb ring + annulus + dot |
|
|
101
|
+
|
|
102
|
+
### Wizard checklist
|
|
103
|
+
|
|
104
|
+
- [ ] Colored tick badges use `--cfm-number-*` when traffic-light mode applies
|
|
105
|
+
- [ ] `labelStyles.ts` imported for tick label row
|
|
@@ -73,3 +73,14 @@ onAction({ type: 'CHANGE', payload: { questionId, answerValue: UploadedFileAnswe
|
|
|
73
73
|
- [ ] Final answer shape: `UploadedFileAnswer[]` with `id` + `mediaUrl`
|
|
74
74
|
- [ ] Remove clears answer or passes updated array
|
|
75
75
|
- [ ] Matrix row: [`question-type-sdk-matrix.md#file_upload`](../00-integration/question-type-sdk-matrix.md#file_upload)
|
|
76
|
+
|
|
77
|
+
## Wizard customization (Phase 5 — required)
|
|
78
|
+
|
|
79
|
+
| Control | CSS vars | Apply in |
|
|
80
|
+
|---------|----------|----------|
|
|
81
|
+
| Dropzone border | `--cfm-upload-border-color` | Dashed border on upload area |
|
|
82
|
+
| Focus / drag-over | `--cfm-input-focus-ring` | Active dropzone outline |
|
|
83
|
+
|
|
84
|
+
### Wizard checklist
|
|
85
|
+
|
|
86
|
+
- [ ] Dropzone border uses `var(--cfm-upload-border-color)` not hardcoded hex
|
|
@@ -47,3 +47,7 @@ Container-level media (survey chrome) is separate — see `03-ui-specs/12-survey
|
|
|
47
47
|
|
|
48
48
|
- [ ] No CHANGE action — display-only
|
|
49
49
|
- [ ] Matrix row: [`question-type-sdk-matrix.md#text_and_media`](../00-integration/question-type-sdk-matrix.md#text_and_media)
|
|
50
|
+
|
|
51
|
+
## Wizard customization (Phase 5 — required)
|
|
52
|
+
|
|
53
|
+
Display-only — no selection tokens. Media caption may use `--cfm-question-title-color` for consistency.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# UI Spec: Survey Chrome
|
|
2
2
|
|
|
3
|
-
> **Reference:** `SurveyPage.tsx`, `Header.tsx`, `Footer.tsx`, `ProgressBar.tsx`, `LanguageSelector.tsx`, `IntroPage.tsx`, `EndPage.tsx`, `PausedPage.tsx`
|
|
4
|
-
> **Component blueprints:** `01-components/01-survey-page.md`, `10-header-footer.md`, `11-progress-bar.md`, `12-language-selector.md`, `14-intro-page.md`, `15-end-page.md`, `16-paused-page.md`
|
|
3
|
+
> **Reference:** `SurveyPage.tsx`, `SurveyStickyChrome.tsx`, `Header.tsx`, `Footer.tsx`, `ProgressBar.tsx`, `LanguageSelector.tsx`, `IntroPage.tsx`, `EndPage.tsx`, `PausedPage.tsx`
|
|
4
|
+
> **Component blueprints:** `01-components/01-survey-page.md`, `10-header-footer.md`, `11-progress-bar.md`, `19-survey-sticky-chrome.md`, `12-language-selector.md`, `14-intro-page.md`, `15-end-page.md`, `16-paused-page.md`
|
|
5
5
|
|
|
6
6
|
## SurveyPage — Phase Router
|
|
7
7
|
|
|
@@ -21,9 +21,8 @@
|
|
|
21
21
|
## Active Layout
|
|
22
22
|
|
|
23
23
|
```
|
|
24
|
-
Header
|
|
24
|
+
SurveyStickyChrome (sticky top-0 — Header + ProgressBar)
|
|
25
25
|
main (max-w-4xl)
|
|
26
|
-
ProgressBar(progressPercentage)
|
|
27
26
|
LanguageSelector (hidden if ≤1 language)
|
|
28
27
|
Questions (space-y-12)
|
|
29
28
|
Submit error (if any)
|
|
@@ -31,6 +30,25 @@ main (max-w-4xl)
|
|
|
31
30
|
Footer
|
|
32
31
|
```
|
|
33
32
|
|
|
33
|
+
### Sticky chrome (required on content phase)
|
|
34
|
+
|
|
35
|
+
Long pages push the last question below the fold. Wrap **Header + ProgressBar** in one sticky container so progress stays visible while answering.
|
|
36
|
+
|
|
37
|
+
```tsx
|
|
38
|
+
<div className="sticky top-0 z-30 bg-white shadow-[0_2px_8px_rgba(0,0,0,0.06)]">
|
|
39
|
+
<Header embedded />
|
|
40
|
+
<div className="mx-auto w-full max-w-4xl px-4 pb-5 pt-4 sm:px-6 lg:px-8">
|
|
41
|
+
<ProgressBar progressPercentage={state.progressPercentage} />
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
**Spacing:** `pt-4` (16px) between logo block and progress track; `pb-5` (20px) below the track before scrollable content. Do not flush the bar against the logo square.
|
|
47
|
+
|
|
48
|
+
See [`01-components/19-survey-sticky-chrome.md`](../01-components/19-survey-sticky-chrome.md). Copy [`templates/SurveyStickyChrome.tsx`](../templates/SurveyStickyChrome.tsx).
|
|
49
|
+
|
|
50
|
+
Use standalone `Header` (no sticky wrapper) on intro, end, paused, loading, and terminal phases.
|
|
51
|
+
|
|
34
52
|
## Navigation Labels
|
|
35
53
|
|
|
36
54
|
German when `survey.language.startsWith('de')`:
|
|
@@ -51,6 +69,14 @@ German when `survey.language.startsWith('de')`:
|
|
|
51
69
|
|
|
52
70
|
Pink fill bar. Bound to `state.progressPercentage` (path-scoped — see `00-integration/progress.md`).
|
|
53
71
|
|
|
72
|
+
Render inside **`SurveyStickyChrome`** (sticky header + progress) on the content phase — not inside scrollable `<main>`. Clamp width to `0–100`.
|
|
73
|
+
|
|
74
|
+
| Token | Value | Role |
|
|
75
|
+
|-------|-------|------|
|
|
76
|
+
| Gap above track | `pt-4` (16px) | Space between logo block and progress bar |
|
|
77
|
+
| Gap below track | `pb-5` (20px) | Breathing room before question content |
|
|
78
|
+
| Track height | `h-3` (12px) | Full-width rounded pill |
|
|
79
|
+
|
|
54
80
|
## LanguageSelector
|
|
55
81
|
|
|
56
82
|
- Hidden when `languages.length <= 1`
|
|
@@ -97,8 +123,31 @@ Disable primary Next/Submit when `submitSurveyResults.isLoading`; label "Submitt
|
|
|
97
123
|
- [ ] `onAction({ type: 'START' })` on intro
|
|
98
124
|
- [ ] `onAction({ type: 'CHANGE' })` wired per question with `allAnswers` / `allQuestions`
|
|
99
125
|
- [ ] Back uses `state.canGoBack`; primary uses `state.primaryButtonType`
|
|
100
|
-
- [ ] ProgressBar receives `state.progressPercentage`
|
|
126
|
+
- [ ] ProgressBar receives `state.progressPercentage` inside sticky chrome (`SurveyStickyChrome`)
|
|
127
|
+
- [ ] Sticky `top-0 z-30` wrapper keeps progress visible on long pages
|
|
128
|
+
- [ ] `pt-4` / `pb-5` spacing between logo, progress track, and question content
|
|
101
129
|
- [ ] Header/Footer on every state branch
|
|
102
130
|
- [ ] `questionNumber` prefix when present on content questions
|
|
103
131
|
- [ ] Intro / Paused / End / terminal phase branches
|
|
104
132
|
- [ ] Submit button disabled while `submitSurveyResults.isLoading`
|
|
133
|
+
|
|
134
|
+
## Wizard customization (Phase 5 — required)
|
|
135
|
+
|
|
136
|
+
> Full chrome contract: [`wizard-preview-build-guide.md`](../00-integration/wizard-preview-build-guide.md).
|
|
137
|
+
|
|
138
|
+
| Element | `data-cfm-*` / CSS vars |
|
|
139
|
+
|---------|-------------------------|
|
|
140
|
+
| Logo | `data-cfm-logo` or `data-cfm-logo-text` |
|
|
141
|
+
| Company | `data-cfm-company` |
|
|
142
|
+
| Survey title | `data-cfm-survey-title` |
|
|
143
|
+
| Thank you | `data-cfm-thank-you` |
|
|
144
|
+
| Next / Back | `data-cfm-btn-next`, `data-cfm-btn-back` |
|
|
145
|
+
| Footer | `data-cfm-copyright`, `data-cfm-footer-links` |
|
|
146
|
+
| Progress | `--cfm-progress-track`, `--cfm-progress-fill` |
|
|
147
|
+
| Header bg | `--cfm-header-bg`, `--cfm-header-text` |
|
|
148
|
+
|
|
149
|
+
### Wizard checklist
|
|
150
|
+
|
|
151
|
+
- [ ] All editable chrome strings use `data-cfm-*` attributes
|
|
152
|
+
- [ ] Buttons and progress use `var(--cfm-*)` — not hardcoded Telekom hex
|
|
153
|
+
- [ ] Logo: text/CSS **or** local `public/` image — never external URL (see `constraints.md` §4)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UI Spec: Heatmap (`type: 'HEATMAP'`)
|
|
2
2
|
|
|
3
|
-
> **Implement from this spec
|
|
3
|
+
> **Implement from this spec.** Portable template: `docs/templates/HeatmapScale.tsx`
|
|
4
4
|
> **SDK type:** `HeatmapQuestion` — `fetchSurvey/types/heatmap.ts`
|
|
5
5
|
> **Component blueprint:** `01-components/17-heatmap-scale.md`
|
|
6
6
|
|
|
@@ -78,3 +78,14 @@ Copy coord helpers from [`templates/heatmapCoords.ts`](../templates/heatmapCoord
|
|
|
78
78
|
- [ ] Wait for `onLoad` before accepting clicks
|
|
79
79
|
- [ ] Percentage-positioned spots (survives resize)
|
|
80
80
|
- [ ] Do NOT render region overlays on respondent UI
|
|
81
|
+
|
|
82
|
+
## Wizard customization (Phase 5 — required)
|
|
83
|
+
|
|
84
|
+
| Control | CSS vars | Apply in |
|
|
85
|
+
|---------|----------|----------|
|
|
86
|
+
| Spot color | `--cfm-heatmap-spot-color` | Click markers |
|
|
87
|
+
| Spot border | `--cfm-heatmap-spot-border` | Marker outline |
|
|
88
|
+
|
|
89
|
+
### Wizard checklist
|
|
90
|
+
|
|
91
|
+
- [ ] Spot markers use `--cfm-heatmap-spot-*` vars
|
|
@@ -126,3 +126,14 @@ RANK_ORDER operators (ranked as/above/below) — see [`logic-fields-catalog.md`]
|
|
|
126
126
|
- [ ] `option.imageUrl` before `previewImageUrl`
|
|
127
127
|
- [ ] No client-side re-shuffle when `shuffleOptions` is true
|
|
128
128
|
- [ ] No stub placeholder text
|
|
129
|
+
|
|
130
|
+
## Wizard customization (Phase 5 — required)
|
|
131
|
+
|
|
132
|
+
| Control | CSS vars | Apply in |
|
|
133
|
+
|---------|----------|----------|
|
|
134
|
+
| Rank badge | `--cfm-rank-badge-bg`, `--cfm-rank-badge-color` | Drag handle / rank number |
|
|
135
|
+
| Option border | `--cfm-rank-option-border` | List item cards |
|
|
136
|
+
|
|
137
|
+
### Wizard checklist
|
|
138
|
+
|
|
139
|
+
- [ ] Rank badges and option borders use `--cfm-rank-*` vars
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
# UI Specifications — Reference Implementation Guide
|
|
2
2
|
|
|
3
3
|
> **For npm installs:** implement from these specs + [`templates/Question.tsx`](../templates/Question.tsx).
|
|
4
|
-
> **
|
|
4
|
+
> **Shared lib utilities** (NPS colors, custom fields, heatmap coords) live in [`templates/`](../templates/) — see [`client-lib-folder.md`](../00-integration/client-lib-folder.md), not in this ui-specs folder.
|
|
5
5
|
> Read the spec for **each question type present** in the fetched survey before writing React code.
|
|
6
6
|
|
|
7
|
+
> **Wizard customization:** When the client may use the web wizard, hardcoded hex in § Design Tokens below are **defaults only**. Wire `var(--cfm-*)` per [`wizard-question-type-styling.md`](../00-integration/wizard-question-type-styling.md) — especially `--cfm-matrix-selected` (cell annulus) and `--cfm-input-focus-ring` (outer border + inner dot). Portable scale templates in `docs/templates/` are layout/logic baselines; extend with `selectionStyles.ts` + `labelStyles.ts` for live preview.
|
|
8
|
+
|
|
7
9
|
## How to Read a UI Spec
|
|
8
10
|
|
|
9
11
|
Each file in this folder follows the same structure:
|
|
@@ -75,7 +77,7 @@ Use accent colors from SDK options — never invent colors for NPS:
|
|
|
75
77
|
|
|
76
78
|
## When to Read
|
|
77
79
|
|
|
78
|
-
After Phase 3 in [`index.md`](../index.md), for each question in the fetched survey:
|
|
80
|
+
After Phase 3 in [`index.md`](../index.md) and [`agent-execution-flow.md`](../00-integration/agent-execution-flow.md), for each question in the fetched survey:
|
|
79
81
|
|
|
80
82
|
1. Read [`02-reference/question-types/`](../02-reference/question-types/) for data shape
|
|
81
83
|
2. Read matching spec from this folder (see [`MANIFEST.json`](../MANIFEST.json) `questionTypes.{type}.uiSpec`)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# UI Spec: Matrix Dropdown (shared primitive)
|
|
2
2
|
|
|
3
|
-
> **Implement from this spec
|
|
3
|
+
> **Implement from this spec.** Portable template: `docs/templates/MatrixDropdown.tsx`
|
|
4
4
|
> **Used by:** `LikertMatrixScale`, `CsatMatrixScale` vertical list
|
|
5
5
|
|
|
6
6
|
## Modes
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"docsSchemaVersion": "2.
|
|
2
|
+
"docsSchemaVersion": "2.6.0",
|
|
3
3
|
"sdkTypesVersion": "0.2.1",
|
|
4
4
|
"packageNames": {
|
|
5
5
|
"npm": "@explorer02/cfm-survey-sdk",
|
|
@@ -13,8 +13,28 @@
|
|
|
13
13
|
"clientInputs": [
|
|
14
14
|
"initialPrompt",
|
|
15
15
|
"instanceIdJwt",
|
|
16
|
+
"customizationWizardOptional",
|
|
16
17
|
"deployConfirmation"
|
|
17
18
|
],
|
|
19
|
+
"surveyUiConfig": {
|
|
20
|
+
"artifact": "survey-ui-config.json",
|
|
21
|
+
"schema": "templates/survey-ui-config.schema.json",
|
|
22
|
+
"cliCommand": "npx cfm-sdk customize",
|
|
23
|
+
"cliCommands": {
|
|
24
|
+
"default": "npx cfm-sdk customize",
|
|
25
|
+
"remoteClient": "npx cfm-sdk customize-ui",
|
|
26
|
+
"exportPreviews": "npx cfm-sdk export-previews"
|
|
27
|
+
},
|
|
28
|
+
"wizardApiDoc": "00-integration/wizard-api.md",
|
|
29
|
+
"applyDoc": "00-integration/apply-ui-config.md",
|
|
30
|
+
"wizardDoc": "00-integration/ui-customization-wizard.md",
|
|
31
|
+
"previewBuildDoc": "00-integration/wizard-preview-build-guide.md",
|
|
32
|
+
"questionTypeStylingDoc": "00-integration/wizard-question-type-styling.md",
|
|
33
|
+
"agentExecutionFlowDoc": "00-integration/agent-execution-flow.md",
|
|
34
|
+
"agentOperatingContractDoc": "00-integration/agent-operating-contract.md",
|
|
35
|
+
"wizardConfigHandoffDoc": "00-integration/wizard-config-handoff.md",
|
|
36
|
+
"previewBridgeTemplate": "templates/previewBridge.ts"
|
|
37
|
+
},
|
|
18
38
|
"hookContract": {
|
|
19
39
|
"answersField": "state.answers",
|
|
20
40
|
"customFieldValuesField": "options.customFieldValues",
|
|
@@ -44,6 +64,14 @@
|
|
|
44
64
|
]
|
|
45
65
|
},
|
|
46
66
|
"integrationDocs": [
|
|
67
|
+
{
|
|
68
|
+
"path": "00-integration/agent-operating-contract.md",
|
|
69
|
+
"purpose": "Anti-hallucination rules — read-before-write gates, doc routing, forbidden inventions (read FIRST)"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"path": "00-integration/agent-execution-flow.md",
|
|
73
|
+
"purpose": "Authoritative agent pipeline — client questions, phase order, wizard-ready build (read with index.md)"
|
|
74
|
+
},
|
|
47
75
|
{
|
|
48
76
|
"path": "00-integration/client-integration-guide.md",
|
|
49
77
|
"purpose": "Master wiring map — start here for full client integration"
|
|
@@ -119,6 +147,50 @@
|
|
|
119
147
|
{
|
|
120
148
|
"path": "00-integration/file-upload-aws.md",
|
|
121
149
|
"purpose": "Presigned S3 upload flow for FILE_UPLOAD submit contract"
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"path": "00-integration/canonical-survey-fixtures.md",
|
|
153
|
+
"purpose": "Page-by-page UI expectations — matrix labels, slider header, template copy list"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"path": "00-integration/client-lib-folder.md",
|
|
157
|
+
"purpose": "src/lib layout — customFieldValues + surveyUi portable templates"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"path": "00-integration/wizard-preview-build-guide.md",
|
|
161
|
+
"purpose": "Build client components for wizard live preview — --cfm-* vars and data-cfm-* hooks (Phase 5)"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"path": "00-integration/wizard-question-type-styling.md",
|
|
165
|
+
"purpose": "Per-type wizard styling — selection colors, label items, all 11 question types (Phase 5)"
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
"path": "00-integration/wizard-config-handoff.md",
|
|
169
|
+
"purpose": "Wait for client submit, review artifacts (.final.json, .diff.md), confirm-ui-config order (Phase 6b→6c)"
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
"path": "00-integration/ui-customization-wizard.md",
|
|
173
|
+
"purpose": "Optional web wizard flow, CLI commands, wizard steps"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"path": "00-integration/apply-ui-config.md",
|
|
177
|
+
"purpose": "Apply survey-ui-config.json tokens after wizard (Phase 6c)"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"path": "00-integration/wizard-api.md",
|
|
181
|
+
"purpose": "EC2 /wizard/* API — customize-ui remote-client fallback only"
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
"path": "00-integration/wizard-troubleshooting.md",
|
|
185
|
+
"purpose": "Fix mock preview, local vs EC2, layout toggles, all-11-types wizard export (Phase 6b)"
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
"path": "00-integration/mockup-ui-extraction.md",
|
|
189
|
+
"purpose": "UI-only extraction from client mockup — no logic/language/types from images (Phase 0–4)"
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"path": "00-integration/placeholders-and-custom-fields-wiring.md",
|
|
193
|
+
"purpose": "Discover placeholder + _c_ keys from fetch; precise useSurveySDK wiring (Phase 4–5)"
|
|
122
194
|
}
|
|
123
195
|
],
|
|
124
196
|
"templateScaleFiles": [
|
|
@@ -126,7 +198,15 @@
|
|
|
126
198
|
"templates/MatrixDropdown.tsx",
|
|
127
199
|
"templates/CustomSliderTrack.tsx",
|
|
128
200
|
"templates/surveyUiIcons.tsx",
|
|
129
|
-
"templates/
|
|
201
|
+
"templates/surveyUiScaleUtils.ts",
|
|
202
|
+
"templates/SliderMatrixScale.tsx",
|
|
203
|
+
"templates/RatingScale.tsx",
|
|
204
|
+
"templates/LikertMatrixScale.tsx",
|
|
205
|
+
"templates/CsatMatrixScale.tsx",
|
|
206
|
+
"templates/HeatmapScale.tsx",
|
|
207
|
+
"templates/FileUploadScale.tsx",
|
|
208
|
+
"templates/heatmapCoords.ts",
|
|
209
|
+
"templates/customFieldValues.ts"
|
|
130
210
|
],
|
|
131
211
|
"deployTargets": {
|
|
132
212
|
"aws": {
|
|
@@ -134,6 +214,8 @@
|
|
|
134
214
|
"script": "templates/deploy-to-aws.sh",
|
|
135
215
|
"apiBaseEnv": "CFM_DEPLOY_API_BASE",
|
|
136
216
|
"apiBaseDefault": "http://43.204.26.213:3000",
|
|
217
|
+
"wizardClientUrlPattern": "{CFM_DEPLOY_API_BASE}/wizard-app/index.html?session={sessionId}&secret={sessionSecret}",
|
|
218
|
+
"wizardClientUrlNote": "customize-ui only (remote client): EC2 link after preview upload — default is npx cfm-sdk customize on localhost",
|
|
137
219
|
"instanceIdEnv": "CFM_INSTANCE_ID",
|
|
138
220
|
"outDirEnv": "OUT_DIR",
|
|
139
221
|
"healthPath": "/health",
|
|
@@ -190,11 +272,15 @@
|
|
|
190
272
|
"name": "orient",
|
|
191
273
|
"read": [
|
|
192
274
|
"index.md",
|
|
193
|
-
"../AGENT.md"
|
|
275
|
+
"../AGENT.md",
|
|
276
|
+
"00-integration/agent-operating-contract.md",
|
|
277
|
+
"00-integration/agent-execution-flow.md",
|
|
278
|
+
"00-integration/mockup-ui-extraction.md",
|
|
279
|
+
"MANIFEST.json"
|
|
194
280
|
],
|
|
195
281
|
"actions": [
|
|
196
282
|
"detectFramework",
|
|
197
|
-
"
|
|
283
|
+
"extractUiOnlyFromMockup"
|
|
198
284
|
]
|
|
199
285
|
},
|
|
200
286
|
{
|
|
@@ -229,6 +315,7 @@
|
|
|
229
315
|
"00-integration/display-logic-and-navigation.md",
|
|
230
316
|
"00-integration/answer-logic-and-navigation.md",
|
|
231
317
|
"00-integration/custom-field-logic-and-navigation.md",
|
|
318
|
+
"00-integration/client-lib-folder.md",
|
|
232
319
|
"00-integration/question-display-variants.md",
|
|
233
320
|
"00-integration/question-numbering.md",
|
|
234
321
|
"00-integration/placeholders-and-tokens.md",
|
|
@@ -244,7 +331,14 @@
|
|
|
244
331
|
"id": 4,
|
|
245
332
|
"name": "planAndIngest",
|
|
246
333
|
"readAlways": [
|
|
334
|
+
"00-integration/agent-operating-contract.md",
|
|
335
|
+
"00-integration/agent-execution-flow.md",
|
|
336
|
+
"00-integration/mockup-ui-extraction.md",
|
|
337
|
+
"00-integration/placeholders-and-custom-fields-wiring.md",
|
|
247
338
|
"00-integration/component-checklist.md",
|
|
339
|
+
"00-integration/canonical-survey-fixtures.md",
|
|
340
|
+
"00-integration/client-lib-folder.md",
|
|
341
|
+
"00-integration/custom-field-logic-and-navigation.md",
|
|
248
342
|
"00-integration/question-type-sdk-matrix.md",
|
|
249
343
|
"00-integration/logic-fields-catalog.md",
|
|
250
344
|
"03-ui-specs/00-question-shell.md",
|
|
@@ -266,7 +360,12 @@
|
|
|
266
360
|
"id": 5,
|
|
267
361
|
"name": "build",
|
|
268
362
|
"read": [
|
|
363
|
+
"00-integration/agent-operating-contract.md",
|
|
364
|
+
"00-integration/agent-execution-flow.md",
|
|
269
365
|
"00-integration/constraints.md",
|
|
366
|
+
"00-integration/component-checklist.md",
|
|
367
|
+
"00-integration/wizard-preview-build-guide.md",
|
|
368
|
+
"00-integration/wizard-question-type-styling.md",
|
|
270
369
|
"02-reference/routing-table.md"
|
|
271
370
|
],
|
|
272
371
|
"onDemand": "02-reference/question-types"
|
|
@@ -275,7 +374,10 @@
|
|
|
275
374
|
"id": 6,
|
|
276
375
|
"name": "verify",
|
|
277
376
|
"read": [
|
|
278
|
-
"00-integration/
|
|
377
|
+
"00-integration/agent-operating-contract.md",
|
|
378
|
+
"00-integration/agent-execution-flow.md",
|
|
379
|
+
"00-integration/constraints.md",
|
|
380
|
+
"00-integration/component-checklist.md"
|
|
279
381
|
],
|
|
280
382
|
"script": "templates/verify-agent-build.sh",
|
|
281
383
|
"checklist": [
|
|
@@ -295,8 +397,78 @@
|
|
|
295
397
|
"outIndexHtmlExists",
|
|
296
398
|
"outFileCountUnder500",
|
|
297
399
|
"rankOrderScaleTemplateCopied",
|
|
400
|
+
"sliderMatrixScaleTemplateCopied",
|
|
401
|
+
"ratingScaleTemplateCopied",
|
|
402
|
+
"matrixScaleTemplatesCopied",
|
|
403
|
+
"heatmapScaleTemplateCopied",
|
|
298
404
|
"dndKitWhenRankOrder",
|
|
299
|
-
"fileUploadPresignedFlowWhenFileUpload"
|
|
405
|
+
"fileUploadPresignedFlowWhenFileUpload",
|
|
406
|
+
"surveyThemeCssPresent",
|
|
407
|
+
"selectionStylesCopied",
|
|
408
|
+
"labelStylesCopied",
|
|
409
|
+
"chromeDataCfmHooksPresent",
|
|
410
|
+
"draftSurveyUiConfigPresent"
|
|
411
|
+
],
|
|
412
|
+
"postVerify": [
|
|
413
|
+
"startDevServer",
|
|
414
|
+
"askCustomizationWizard"
|
|
415
|
+
]
|
|
416
|
+
},
|
|
417
|
+
{
|
|
418
|
+
"id": "6b",
|
|
419
|
+
"name": "optionalUiCustomization",
|
|
420
|
+
"optional": true,
|
|
421
|
+
"requiresClientConfirmation": true,
|
|
422
|
+
"read": [
|
|
423
|
+
"00-integration/wizard-config-handoff.md",
|
|
424
|
+
"00-integration/ui-customization-wizard.md",
|
|
425
|
+
"00-integration/wizard-preview-build-guide.md",
|
|
426
|
+
"00-integration/wizard-question-type-styling.md",
|
|
427
|
+
"00-integration/wizard-api.md",
|
|
428
|
+
"00-integration/wizard-troubleshooting.md"
|
|
429
|
+
],
|
|
430
|
+
"cliCommand": "npx cfm-sdk customize",
|
|
431
|
+
"cliCommandRemote": "npx cfm-sdk customize-ui",
|
|
432
|
+
"cliConfirmCommand": "npx cfm-sdk confirm-ui-config",
|
|
433
|
+
"output": "survey-ui-config.json",
|
|
434
|
+
"outputArtifactsRemote": [
|
|
435
|
+
"survey-ui-config.seed.json",
|
|
436
|
+
"survey-ui-config.final.json",
|
|
437
|
+
"survey-ui-config.diff.json",
|
|
438
|
+
"survey-ui-config.diff.md"
|
|
439
|
+
],
|
|
440
|
+
"agentMustWait": true,
|
|
441
|
+
"waitUntil": "cliExit0UiConfigurationSaved",
|
|
442
|
+
"clientHandoff": "openLocalhostWizardSameMachine",
|
|
443
|
+
"clientHandoffRemote": "shareDeployedWizardUrlAfterPreviewUpload",
|
|
444
|
+
"prerequisites": [
|
|
445
|
+
"phase6VerifyPassed",
|
|
446
|
+
"devServerRunning"
|
|
447
|
+
]
|
|
448
|
+
},
|
|
449
|
+
{
|
|
450
|
+
"id": "6c",
|
|
451
|
+
"name": "applyUiConfig",
|
|
452
|
+
"optional": true,
|
|
453
|
+
"when": "wizardUsedOrSurveyUiConfigExists",
|
|
454
|
+
"read": [
|
|
455
|
+
"00-integration/wizard-config-handoff.md",
|
|
456
|
+
"00-integration/apply-ui-config.md",
|
|
457
|
+
"00-integration/wizard-preview-build-guide.md",
|
|
458
|
+
"00-integration/wizard-question-type-styling.md"
|
|
459
|
+
],
|
|
460
|
+
"inputFile": "survey-ui-config.final.json",
|
|
461
|
+
"inputFileLocal": "survey-ui-config.json",
|
|
462
|
+
"actions": [
|
|
463
|
+
"readDiffMdCompletely",
|
|
464
|
+
"validateAgainstSchema",
|
|
465
|
+
"regenerateSurveyThemeCssFromFinal",
|
|
466
|
+
"applyDataCfmContentHooks",
|
|
467
|
+
"applyLayoutToggles",
|
|
468
|
+
"applyQuestionTypesTokens",
|
|
469
|
+
"runConfirmUiConfigAws",
|
|
470
|
+
"crossCheckEveryDiffPath",
|
|
471
|
+
"reRunVerify"
|
|
300
472
|
]
|
|
301
473
|
},
|
|
302
474
|
{
|
|
@@ -305,7 +477,8 @@
|
|
|
305
477
|
"requiresClientConfirmation": true,
|
|
306
478
|
"selectTargetFromPrompt": {
|
|
307
479
|
"awsKeywords": ["aws", "cloudfront", "s3", "ec2", "sprinklr"],
|
|
308
|
-
"default": "vercel"
|
|
480
|
+
"default": "vercel",
|
|
481
|
+
"fallbackFromConfig": "survey-ui-config.json deploy.target"
|
|
309
482
|
},
|
|
310
483
|
"targets": {
|
|
311
484
|
"aws": {
|