@explorer02/cfm-survey-sdk 0.3.8 → 0.4.0
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 +35 -35
- package/dist/cli/index.mjs +35 -35
- package/package.json +1 -1
- package/templates/docs/templates/CsatMatrixScale.tsx +60 -45
- package/templates/docs/templates/CustomSliderTrack.tsx +2 -2
- package/templates/docs/templates/Header.tsx +14 -13
- package/templates/docs/templates/LikertMatrixScale.tsx +2 -2
- package/templates/docs/templates/Question.tsx +31 -13
- package/templates/docs/templates/RankOrderScale.tsx +10 -2
- package/templates/docs/templates/SliderMatrixScale.tsx +3 -4
- package/templates/docs/templates/uiConfig.ts +89 -2
- package/templates/preview-harness/preview-bridge.inline.js +55 -15
- package/templates/preview-harness/previewPages.js +2 -2
- package/templates/preview-harness/previewPages.ts +1 -1
- package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +8 -1
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +17 -96
- package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +32 -8
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +72 -47
- package/templates/preview-harness/vite-app/src/globals.css +6 -0
- package/templates/preview-harness/vite-app/src/mergePreviewQuestion.ts +173 -0
- package/templates/preview-harness/vite-app/src/preview-live-overrides.css +22 -0
- package/templates/previewBridge.ts +61 -14
- package/templates/survey-theme.css +4 -1
- package/templates/wizard-dist/assets/{PreviewMock-CS4WqhDB.js → PreviewMock-BlOAvUCN.js} +1 -1
- package/templates/wizard-dist/assets/TypePanel-DcbMaw1b.js +1 -0
- package/templates/wizard-dist/assets/index-2Bi_7Fdh.js +34 -0
- package/templates/wizard-dist/index.html +1 -1
- package/templates/wizard-dist/assets/TypePanel-BgTW2c74.js +0 -1
- package/templates/wizard-dist/assets/index-hjm-fxWO.js +0 -34
|
@@ -17,10 +17,12 @@
|
|
|
17
17
|
delete pending[k];
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
applyThemeSideEffects();
|
|
21
|
+
syncCompanyNameVisibility();
|
|
22
|
+
syncQuestionChromeVisibility();
|
|
23
|
+
}
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
function queue(vars) {
|
|
24
26
|
for (var k in vars) {
|
|
25
27
|
if (Object.prototype.hasOwnProperty.call(vars, k)) pending[k] = vars[k];
|
|
26
28
|
}
|
|
@@ -34,10 +36,12 @@
|
|
|
34
36
|
root.style.setProperty(k, vars[k]);
|
|
35
37
|
}
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
applyThemeSideEffects();
|
|
40
|
+
syncCompanyNameVisibility();
|
|
41
|
+
syncQuestionChromeVisibility();
|
|
42
|
+
}
|
|
39
43
|
|
|
40
|
-
|
|
44
|
+
function setDisplay(selector, visible) {
|
|
41
45
|
document.querySelectorAll(selector).forEach(function (el) {
|
|
42
46
|
el.style.display = visible ? '' : 'none';
|
|
43
47
|
});
|
|
@@ -81,6 +85,46 @@
|
|
|
81
85
|
applyDropzoneStyle();
|
|
82
86
|
}
|
|
83
87
|
|
|
88
|
+
function isHeaderLogoVisible() {
|
|
89
|
+
var logoImg = document.querySelector('header [data-cfm-logo], .cfm-header [data-cfm-logo]');
|
|
90
|
+
return Boolean(
|
|
91
|
+
logoImg &&
|
|
92
|
+
logoImg.style.display !== 'none' &&
|
|
93
|
+
logoImg.getAttribute('src'),
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function syncCompanyNameVisibility(layoutShowCompany) {
|
|
98
|
+
var showFromCss = readVar('--cfm-header-show-company', '1') !== '0';
|
|
99
|
+
var showToggle =
|
|
100
|
+
layoutShowCompany !== undefined ? !!layoutShowCompany : showFromCss;
|
|
101
|
+
|
|
102
|
+
document.querySelectorAll('[data-cfm-company]').forEach(function (el) {
|
|
103
|
+
var hasName = Boolean((el.textContent || '').trim());
|
|
104
|
+
var show = showToggle && hasName && isHeaderLogoVisible();
|
|
105
|
+
el.style.display = show ? '' : 'none';
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function syncQuestionChromeVisibility(layoutShowNumbers, layoutShowRequired) {
|
|
110
|
+
var showNumbers =
|
|
111
|
+
layoutShowNumbers !== undefined
|
|
112
|
+
? !!layoutShowNumbers
|
|
113
|
+
: readVar('--cfm-show-question-numbers', '1') !== '0';
|
|
114
|
+
var showRequired =
|
|
115
|
+
layoutShowRequired !== undefined
|
|
116
|
+
? !!layoutShowRequired
|
|
117
|
+
: readVar('--cfm-show-required-asterisk', '1') !== '0';
|
|
118
|
+
|
|
119
|
+
document.querySelectorAll('[data-cfm-question-number]').forEach(function (el) {
|
|
120
|
+
var hasNumber = Boolean((el.textContent || '').trim());
|
|
121
|
+
el.style.display = showNumbers && hasNumber ? '' : 'none';
|
|
122
|
+
});
|
|
123
|
+
document.querySelectorAll('[data-cfm-required]').forEach(function (el) {
|
|
124
|
+
el.style.display = showRequired ? '' : 'none';
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
|
|
84
128
|
function applyContent(patch) {
|
|
85
129
|
if (!patch) return;
|
|
86
130
|
if (patch.logoUrl !== undefined) {
|
|
@@ -103,17 +147,11 @@
|
|
|
103
147
|
el.classList.remove('hidden');
|
|
104
148
|
}
|
|
105
149
|
});
|
|
106
|
-
document.querySelectorAll('[data-cfm-company]').forEach(function (el) {
|
|
107
|
-
if (patch.logoUrl) {
|
|
108
|
-
el.style.display = el.textContent ? '' : 'none';
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
150
|
}
|
|
112
151
|
if (patch.companyName !== undefined) {
|
|
113
152
|
var name = patch.companyName || '';
|
|
114
153
|
document.querySelectorAll('[data-cfm-company]').forEach(function (el) {
|
|
115
154
|
el.textContent = name;
|
|
116
|
-
el.style.display = name ? '' : 'none';
|
|
117
155
|
});
|
|
118
156
|
document.querySelectorAll('[data-cfm-logo-text]').forEach(function (el) {
|
|
119
157
|
var logoImg = document.querySelector('[data-cfm-logo]');
|
|
@@ -174,7 +212,7 @@
|
|
|
174
212
|
if (patch.layoutFlags) {
|
|
175
213
|
var flags = patch.layoutFlags;
|
|
176
214
|
if (flags.showCompanyName !== undefined) {
|
|
177
|
-
|
|
215
|
+
syncCompanyNameVisibility(flags.showCompanyName);
|
|
178
216
|
}
|
|
179
217
|
if (flags.showHeader !== undefined) {
|
|
180
218
|
setDisplay('.cfm-header, header.cfm-header', flags.showHeader);
|
|
@@ -195,10 +233,10 @@
|
|
|
195
233
|
setDisplay('[data-cfm-btn-back]', flags.showBackButton);
|
|
196
234
|
}
|
|
197
235
|
if (flags.showQuestionNumbers !== undefined) {
|
|
198
|
-
|
|
236
|
+
syncQuestionChromeVisibility(flags.showQuestionNumbers, undefined);
|
|
199
237
|
}
|
|
200
238
|
if (flags.showRequiredAsterisk !== undefined) {
|
|
201
|
-
|
|
239
|
+
syncQuestionChromeVisibility(undefined, flags.showRequiredAsterisk);
|
|
202
240
|
}
|
|
203
241
|
if (flags.showFooterLogo !== undefined) {
|
|
204
242
|
setDisplay('[data-cfm-footer-logo]', flags.showFooterLogo);
|
|
@@ -232,6 +270,8 @@
|
|
|
232
270
|
applyMultiStatement(!!patch.previewState.multiStatement);
|
|
233
271
|
}
|
|
234
272
|
}
|
|
273
|
+
syncCompanyNameVisibility();
|
|
274
|
+
syncQuestionChromeVisibility();
|
|
235
275
|
applyThemeSideEffects();
|
|
236
276
|
}
|
|
237
277
|
|
|
@@ -97,8 +97,8 @@ const PREVIEW_PAGE_DEFS = [
|
|
|
97
97
|
{ key: 'TEXTFIELD_short', title: 'Text Short', body: `<p style="font-weight:600;margin-bottom:8px">Your name</p><input class="cfm-input" data-cfm-textfield placeholder="Type here..." />` },
|
|
98
98
|
{ key: 'TEXTFIELD_long', title: 'Text Long', body: `<p style="font-weight:600;margin-bottom:8px">Comments</p><textarea class="cfm-input" data-cfm-textfield style="height:120px;padding:12px" placeholder="Type your response..."></textarea>` },
|
|
99
99
|
{ key: 'NPS_SCALE', title: 'NPS', body: npsPreview() },
|
|
100
|
-
{ key: 'CFM_likert', title: 'CFM Likert', body: `${matrixPreview('Statement item 1', 'radio')}<div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label">Statement item 2</div><div class="cfm-matrix-cells">${cells(5)}</div></div>` },
|
|
101
|
-
{ key: 'CFM_bipolar', title: 'CFM Bipolar', body: `<div class="cfm-matrix-row"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%)">
|
|
100
|
+
{ key: 'CFM_likert', title: 'CFM Likert', body: `${matrixPreview('Statement item 1', 'radio')}<div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label">Statement item 2</div><div class="cfm-matrix-cells">${cells(5)}</div></div><div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label">Statement item 3</div><div class="cfm-matrix-cells">${cells(5)}</div></div>` },
|
|
101
|
+
{ key: 'CFM_bipolar', title: 'CFM Bipolar', body: `<div class="cfm-matrix-row"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%)">Statement 1</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%);text-align:right">Opposite 1</div></div><div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%)">Statement 2</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%);text-align:right">Opposite 2</div></div><div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%)">Statement 3</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width,25%);text-align:right">Opposite 3</div></div>` },
|
|
102
102
|
{ key: 'CFM_transpose', title: 'CFM Transpose', body: matrixPreview('Scale item (transposed row)', 'radio') },
|
|
103
103
|
{ key: 'CFM_carousel', title: 'CFM Carousel', body: `${matrixPreview('Row 1 of 3', 'radio')}<div style="text-align:center;margin-top:12px"><span style="color:var(--cfm-matrix-selected)">●</span> ○ ○</div>` },
|
|
104
104
|
{ key: 'CFM_dropdown', title: 'CFM Dropdown', body: `<div class="cfm-matrix-label" style="width:100%;margin-bottom:8px">Statement 1</div><select class="cfm-input"><option>Select...</option><option>Col 1</option><option>Col 2</option></select>` },
|
|
@@ -141,7 +141,7 @@ export const PREVIEW_PAGE_DEFS: PreviewPageDef[] = [
|
|
|
141
141
|
{
|
|
142
142
|
key: 'CFM_bipolar',
|
|
143
143
|
title: 'CFM Bipolar',
|
|
144
|
-
body: `<div class="cfm-matrix-row"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width)">
|
|
144
|
+
body: `<div class="cfm-matrix-row"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width)">Statement 1</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width);text-align:right">Opposite 1</div></div><div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width)">Statement 2</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width);text-align:right">Opposite 2</div></div><div class="cfm-matrix-row" data-cfm-matrix-row-extra style="display:none"><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width)">Statement 3</div><div class="cfm-matrix-cells">${cells(5)}</div><div class="cfm-matrix-label" style="width:var(--cfm-matrix-bipolar-width);text-align:right">Opposite 3</div></div>`,
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
key: 'CFM_transpose',
|
|
@@ -70,14 +70,19 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
70
70
|
const data = event.data;
|
|
71
71
|
if (!data?.type) return;
|
|
72
72
|
if (data.type !== PREVIEW_BRIDGE_SNAPSHOT && data.type !== PREVIEW_BRIDGE_DELTA) return;
|
|
73
|
+
|
|
74
|
+
let shouldBumpRevision = false;
|
|
75
|
+
|
|
73
76
|
if (data.contentPatch?.previewState) {
|
|
74
77
|
setPreviewState((prev) => ({ ...prev, ...data.contentPatch.previewState }));
|
|
78
|
+
shouldBumpRevision = true;
|
|
75
79
|
}
|
|
76
80
|
if (data.contentPatch?.domAttributes) {
|
|
77
81
|
const root = document.documentElement;
|
|
78
82
|
for (const [key, value] of Object.entries(data.contentPatch.domAttributes)) {
|
|
79
83
|
root.setAttribute(key, value as string);
|
|
80
84
|
}
|
|
85
|
+
shouldBumpRevision = true;
|
|
81
86
|
}
|
|
82
87
|
if (data.cssVars) {
|
|
83
88
|
const root = document.documentElement;
|
|
@@ -85,7 +90,9 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
85
90
|
root.style.setProperty(key, value as string);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
88
|
-
|
|
93
|
+
if (shouldBumpRevision) {
|
|
94
|
+
setConfigRevision((r) => r + 1);
|
|
95
|
+
}
|
|
89
96
|
applyThemeSideEffects();
|
|
90
97
|
};
|
|
91
98
|
|
|
@@ -2,6 +2,7 @@ import { useMemo, useState } from 'react';
|
|
|
2
2
|
import type { AnswerValue, SurveyQuestion } from '@explorer02/cfm-survey-sdk';
|
|
3
3
|
import Question from '@/components/Question';
|
|
4
4
|
import { PreviewConfigProvider, usePreviewConfig } from './PreviewConfigContext';
|
|
5
|
+
import { mergePreviewQuestion } from './mergePreviewQuestion';
|
|
5
6
|
|
|
6
7
|
type QuestionPreviewProps = {
|
|
7
8
|
question: SurveyQuestion;
|
|
@@ -27,103 +28,14 @@ function resolveNumberLabelColor(index: number): string {
|
|
|
27
28
|
return '';
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
function applyMatrixRowCount<T extends SurveyQuestion & { statementRows?: { id: string; statementText: string }[] }>(
|
|
31
|
-
q: T,
|
|
32
|
-
multiStatement: boolean | undefined,
|
|
33
|
-
): T {
|
|
34
|
-
if (!('statementRows' in q) || !Array.isArray(q.statementRows)) return q;
|
|
35
|
-
const rows = q.statementRows;
|
|
36
|
-
if (multiStatement) {
|
|
37
|
-
if (rows.length >= 2) return q;
|
|
38
|
-
return {
|
|
39
|
-
...q,
|
|
40
|
-
statementRows: [
|
|
41
|
-
...rows,
|
|
42
|
-
{ id: 'r2', statementText: 'Statement Item 2' },
|
|
43
|
-
...(rows.length === 1 ? [{ id: 'r3', statementText: 'Statement Item 3' }] : []),
|
|
44
|
-
],
|
|
45
|
-
} as T;
|
|
46
|
-
}
|
|
47
|
-
return { ...q, statementRows: rows.slice(0, 1) } as T;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
31
|
function QuestionPreviewInner({ question, initialValue }: QuestionPreviewProps) {
|
|
51
32
|
const { previewState, configRevision } = usePreviewConfig();
|
|
52
33
|
const [value, setValue] = useState<AnswerValue | undefined>(initialValue);
|
|
53
34
|
|
|
54
|
-
const mergedQuestion = useMemo(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (previewState.textfieldPlaceholder && q.type === 'TEXTFIELD') {
|
|
59
|
-
q = { ...q, placeholder: previewState.textfieldPlaceholder };
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
if (previewState.npsButtonStyle && q.type === 'NPS_SCALE') {
|
|
63
|
-
const style = previewState.npsButtonStyle;
|
|
64
|
-
const buttonStyle =
|
|
65
|
-
style === 'numbered'
|
|
66
|
-
? 'numbered'
|
|
67
|
-
: style === 'pill'
|
|
68
|
-
? 'pill'
|
|
69
|
-
: style === 'emoji'
|
|
70
|
-
? 'emoji'
|
|
71
|
-
: 'standard';
|
|
72
|
-
q = { ...q, buttonStyle };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (previewState.hintMinText !== undefined || previewState.hintMaxText !== undefined) {
|
|
76
|
-
if (q.type === 'NPS_SCALE') {
|
|
77
|
-
q = {
|
|
78
|
-
...q,
|
|
79
|
-
minLabel: previewState.hintMinText ?? q.minLabel,
|
|
80
|
-
maxLabel: previewState.hintMaxText ?? q.maxLabel,
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
if (q.type === 'SLIDER_MATRIX') {
|
|
84
|
-
q = {
|
|
85
|
-
...q,
|
|
86
|
-
scaleAnchorLabels: [
|
|
87
|
-
previewState.hintMinText ?? q.scaleAnchorLabels?.[0] ?? '',
|
|
88
|
-
previewState.hintMaxText ?? q.scaleAnchorLabels?.[1] ?? '',
|
|
89
|
-
],
|
|
90
|
-
};
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
if (q.type === 'CFM_MATRIX') {
|
|
95
|
-
if (previewKey === 'CFM_bipolar') {
|
|
96
|
-
q = {
|
|
97
|
-
...q,
|
|
98
|
-
statementLayout: 'bipolar',
|
|
99
|
-
showColumnHeaders: false,
|
|
100
|
-
gridLayout: 'standard',
|
|
101
|
-
transposeTable: false,
|
|
102
|
-
};
|
|
103
|
-
} else if (previewKey === 'CFM_transpose') {
|
|
104
|
-
q = { ...q, statementLayout: 'likert', transposeTable: true, gridLayout: 'standard' };
|
|
105
|
-
} else if (previewKey === 'CFM_carousel') {
|
|
106
|
-
q = { ...q, statementLayout: 'likert', gridLayout: 'carousel', transposeTable: false };
|
|
107
|
-
} else if (previewKey === 'CFM_dropdown') {
|
|
108
|
-
q = { ...q, statementLayout: 'likert', gridLayout: 'dropdown', transposeTable: false };
|
|
109
|
-
} else {
|
|
110
|
-
q = { ...q, statementLayout: 'likert', gridLayout: 'standard', transposeTable: false };
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
if (q.type === 'RANK_ORDER') {
|
|
115
|
-
if (previewState.rankVariant === 'drag' || previewKey === 'RANK_drag') {
|
|
116
|
-
q = { ...q, interactionMode: 'dragAndDrop', optionDisplay: 'textAndImage' };
|
|
117
|
-
}
|
|
118
|
-
if (previewState.rankVariant === 'dropdown' || previewKey === 'RANK_dropdown') {
|
|
119
|
-
q = { ...q, interactionMode: 'dropdown', optionDisplay: 'textAndImage' };
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
q = applyMatrixRowCount(q, previewState.multiStatement);
|
|
124
|
-
|
|
125
|
-
return q;
|
|
126
|
-
}, [question, previewState]);
|
|
35
|
+
const mergedQuestion = useMemo(
|
|
36
|
+
() => mergePreviewQuestion(question, previewState),
|
|
37
|
+
[question, previewState],
|
|
38
|
+
);
|
|
127
39
|
|
|
128
40
|
const heatmapInitial =
|
|
129
41
|
previewState.heatmapPreviewPin && mergedQuestion.type === 'HEATMAP'
|
|
@@ -136,16 +48,25 @@ function QuestionPreviewInner({ question, initialValue }: QuestionPreviewProps)
|
|
|
136
48
|
]
|
|
137
49
|
: initialValue;
|
|
138
50
|
|
|
51
|
+
const rankDropdownInitial =
|
|
52
|
+
mergedQuestion.type === 'RANK_ORDER' &&
|
|
53
|
+
(mergedQuestion as { interactionMode?: string }).interactionMode === 'dropdown' &&
|
|
54
|
+
value === undefined
|
|
55
|
+
? { o1: 1 }
|
|
56
|
+
: undefined;
|
|
57
|
+
|
|
58
|
+
const resolvedValue = heatmapInitial ?? rankDropdownInitial ?? value;
|
|
59
|
+
|
|
139
60
|
return (
|
|
140
61
|
<div
|
|
141
|
-
className="mx-auto max-w-
|
|
142
|
-
style={{ fontFamily: 'var(--cfm-font-family)' }}
|
|
62
|
+
className="mx-auto w-full min-w-0 max-w-full overflow-x-auto px-4 py-6 box-border"
|
|
63
|
+
style={{ fontFamily: 'var(--cfm-font-family)', maxWidth: 'min(100%, var(--cfm-max-width, 48rem))' }}
|
|
143
64
|
data-cfm-question-area
|
|
144
65
|
>
|
|
145
66
|
<Question
|
|
146
67
|
key={configRevision}
|
|
147
68
|
question={mergedQuestion}
|
|
148
|
-
selectedValue={
|
|
69
|
+
selectedValue={resolvedValue}
|
|
149
70
|
allAnswers={{}}
|
|
150
71
|
allQuestions={[mergedQuestion]}
|
|
151
72
|
onSelect={setValue}
|
|
@@ -1,26 +1,43 @@
|
|
|
1
|
-
import { useState } from 'react';
|
|
2
|
-
import type { AnswerValue } from '@explorer02/cfm-survey-sdk';
|
|
1
|
+
import { useMemo, useState } from 'react';
|
|
2
|
+
import type { AnswerValue, MatrixRowAnswers } from '@explorer02/cfm-survey-sdk';
|
|
3
3
|
import SurveyStickyChrome from '@/components/SurveyStickyChrome';
|
|
4
4
|
import LanguageSelector from '@/components/LanguageSelector';
|
|
5
5
|
import Question from '@/components/Question';
|
|
6
6
|
import Footer from '@/components/Footer';
|
|
7
7
|
import { PreviewConfigProvider, usePreviewConfig } from './PreviewConfigContext';
|
|
8
|
+
import { mergeSurveyPageQuestion } from './mergePreviewQuestion';
|
|
8
9
|
import {
|
|
9
10
|
FIXTURE_SURVEY_PAGE_MCQ,
|
|
11
|
+
FIXTURE_SURVEY_PAGE_CFM_LIKERT,
|
|
10
12
|
FIXTURE_SURVEY_PAGE_NPS,
|
|
11
13
|
PREVIEW_LANGUAGES,
|
|
12
14
|
} from './fixtures/questions';
|
|
13
15
|
|
|
14
16
|
function SurveyPagePreviewInner() {
|
|
15
|
-
const { configRevision } = usePreviewConfig();
|
|
17
|
+
const { previewState, configRevision } = usePreviewConfig();
|
|
16
18
|
const [lang, setLang] = useState('en');
|
|
17
19
|
const [mcqAnswer, setMcqAnswer] = useState<AnswerValue>('a');
|
|
20
|
+
const [matrixAnswer, setMatrixAnswer] = useState<MatrixRowAnswers>({});
|
|
18
21
|
const [npsAnswer, setNpsAnswer] = useState<AnswerValue>(8);
|
|
19
22
|
|
|
20
|
-
const
|
|
23
|
+
const mcqQuestion = useMemo(
|
|
24
|
+
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_MCQ, previewState),
|
|
25
|
+
[previewState],
|
|
26
|
+
);
|
|
27
|
+
const matrixQuestion = useMemo(
|
|
28
|
+
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_CFM_LIKERT, previewState),
|
|
29
|
+
[previewState],
|
|
30
|
+
);
|
|
31
|
+
const npsQuestion = useMemo(
|
|
32
|
+
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_NPS, previewState),
|
|
33
|
+
[previewState],
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const allQuestions = [mcqQuestion, matrixQuestion, npsQuestion];
|
|
21
37
|
const allAnswers = {
|
|
22
|
-
[
|
|
23
|
-
[
|
|
38
|
+
[mcqQuestion.id]: mcqAnswer,
|
|
39
|
+
[matrixQuestion.id]: matrixAnswer,
|
|
40
|
+
[npsQuestion.id]: npsAnswer,
|
|
24
41
|
};
|
|
25
42
|
|
|
26
43
|
return (
|
|
@@ -45,14 +62,21 @@ function SurveyPagePreviewInner() {
|
|
|
45
62
|
|
|
46
63
|
<div className="space-y-8" key={configRevision}>
|
|
47
64
|
<Question
|
|
48
|
-
question={
|
|
65
|
+
question={mcqQuestion}
|
|
49
66
|
selectedValue={mcqAnswer}
|
|
50
67
|
allAnswers={allAnswers}
|
|
51
68
|
allQuestions={allQuestions}
|
|
52
69
|
onSelect={setMcqAnswer}
|
|
53
70
|
/>
|
|
54
71
|
<Question
|
|
55
|
-
question={
|
|
72
|
+
question={matrixQuestion}
|
|
73
|
+
selectedValue={matrixAnswer}
|
|
74
|
+
allAnswers={allAnswers}
|
|
75
|
+
allQuestions={allQuestions}
|
|
76
|
+
onSelect={setMatrixAnswer}
|
|
77
|
+
/>
|
|
78
|
+
<Question
|
|
79
|
+
question={npsQuestion}
|
|
56
80
|
selectedValue={npsAnswer}
|
|
57
81
|
allAnswers={allAnswers}
|
|
58
82
|
allQuestions={allQuestions}
|
|
@@ -19,27 +19,37 @@ const LIKERT_COLUMNS = [
|
|
|
19
19
|
{ id: 'c5', label: 'Strongly Agree' },
|
|
20
20
|
];
|
|
21
21
|
|
|
22
|
-
const
|
|
23
|
-
'Strongly Disagree',
|
|
24
|
-
'Disagree',
|
|
25
|
-
'Neutral',
|
|
26
|
-
'Agree',
|
|
27
|
-
'Strongly Agree',
|
|
28
|
-
];
|
|
29
|
-
|
|
30
|
-
const SCALE_COLUMNS_10 = Array.from({ length: 10 }, (_, i) => ({
|
|
31
|
-
id: `c${i}`,
|
|
32
|
-
label: String(i + 1),
|
|
33
|
-
}));
|
|
22
|
+
export const MATRIX_ROW_SINGLE = [{ id: 'r1', statementText: 'Statement Item 1' }];
|
|
34
23
|
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
const MATRIX_ROWS_MULTI = [
|
|
24
|
+
export const MATRIX_ROWS_MULTI = [
|
|
38
25
|
{ id: 'r1', statementText: 'Statement Item 1' },
|
|
39
26
|
{ id: 'r2', statementText: 'Statement Item 2' },
|
|
40
27
|
{ id: 'r3', statementText: 'Statement Item 3' },
|
|
41
28
|
];
|
|
42
29
|
|
|
30
|
+
/** Bipolar matrix preview rows — left statement + matching right opposite per row. */
|
|
31
|
+
export const BIPOLAR_ROWS_SINGLE = [
|
|
32
|
+
{ id: 'r1', statementText: 'Statement 1', oppositeStatementText: 'Opposite 1' },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
export const BIPOLAR_ROWS_MULTI = [
|
|
36
|
+
{ id: 'r1', statementText: 'Statement 1', oppositeStatementText: 'Opposite 1' },
|
|
37
|
+
{ id: 'r2', statementText: 'Statement 2', oppositeStatementText: 'Opposite 2' },
|
|
38
|
+
{ id: 'r3', statementText: 'Statement 3', oppositeStatementText: 'Opposite 3' },
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
const SLIDER_ROW_DEFAULTS = { min: 0, max: 10, step: 1 };
|
|
42
|
+
|
|
43
|
+
export const SLIDER_ROWS_SINGLE = [
|
|
44
|
+
{ id: 'r1', statementText: 'Statement Item 1', ...SLIDER_ROW_DEFAULTS },
|
|
45
|
+
];
|
|
46
|
+
|
|
47
|
+
export const SLIDER_ROWS_MULTI = [
|
|
48
|
+
{ id: 'r1', statementText: 'Statement Item 1', ...SLIDER_ROW_DEFAULTS },
|
|
49
|
+
{ id: 'r2', statementText: 'Statement Item 2', ...SLIDER_ROW_DEFAULTS },
|
|
50
|
+
{ id: 'r3', statementText: 'Statement Item 3', ...SLIDER_ROW_DEFAULTS },
|
|
51
|
+
];
|
|
52
|
+
|
|
43
53
|
const SLIDER_TICKS = Array.from({ length: 11 }, (_, i) => ({
|
|
44
54
|
tickPosition: i,
|
|
45
55
|
tickLabel: String(i),
|
|
@@ -92,7 +102,7 @@ export const FIXTURE_NPS = base({
|
|
|
92
102
|
type: 'NPS_SCALE',
|
|
93
103
|
questionText:
|
|
94
104
|
'Based on your experience, how likely are you to recommend [Company/Product/Service] to your friends and family?',
|
|
95
|
-
buttonStyle: '
|
|
105
|
+
buttonStyle: 'numbered',
|
|
96
106
|
minLabel: 'Not Likely At All',
|
|
97
107
|
maxLabel: 'Extremely Likely',
|
|
98
108
|
options: Array.from({ length: 11 }, (_, i) => ({
|
|
@@ -117,8 +127,8 @@ export const FIXTURE_SURVEY_PAGE_MCQ = base({
|
|
|
117
127
|
export const FIXTURE_SURVEY_PAGE_NPS = base({
|
|
118
128
|
id: 'preview-survey-nps',
|
|
119
129
|
type: 'NPS_SCALE',
|
|
120
|
-
questionNumber:
|
|
121
|
-
buttonStyle: '
|
|
130
|
+
questionNumber: 3,
|
|
131
|
+
buttonStyle: 'numbered',
|
|
122
132
|
questionText:
|
|
123
133
|
'Based on your experience, how likely are you to recommend [Company/Product/Service] to your friends and family?',
|
|
124
134
|
minLabel: 'Not Likely At All',
|
|
@@ -129,6 +139,23 @@ export const FIXTURE_SURVEY_PAGE_NPS = base({
|
|
|
129
139
|
})),
|
|
130
140
|
});
|
|
131
141
|
|
|
142
|
+
/** Likert matrix with 3 statements — used on survey_page preview for zebra row styling. */
|
|
143
|
+
export const FIXTURE_SURVEY_PAGE_CFM_LIKERT = base({
|
|
144
|
+
id: 'preview-survey-cfm-likert',
|
|
145
|
+
type: 'CFM_MATRIX',
|
|
146
|
+
questionNumber: 2,
|
|
147
|
+
questionText: 'Please rate each statement below.',
|
|
148
|
+
statementLayout: 'likert',
|
|
149
|
+
gridLayout: 'standard',
|
|
150
|
+
transposeTable: false,
|
|
151
|
+
selectionMode: 'single',
|
|
152
|
+
showColumnHeaders: true,
|
|
153
|
+
repeatColumnHeaders: false,
|
|
154
|
+
hasNotApplicableOption: false,
|
|
155
|
+
statementRows: MATRIX_ROWS_MULTI,
|
|
156
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
157
|
+
});
|
|
158
|
+
|
|
132
159
|
export const FIXTURE_TEXT_SHORT = base({
|
|
133
160
|
type: 'TEXTFIELD',
|
|
134
161
|
questionText: 'Question',
|
|
@@ -167,13 +194,7 @@ export const FIXTURE_CFM_BIPOLAR = base({
|
|
|
167
194
|
showColumnHeaders: false,
|
|
168
195
|
repeatColumnHeaders: false,
|
|
169
196
|
hasNotApplicableOption: false,
|
|
170
|
-
statementRows:
|
|
171
|
-
{
|
|
172
|
-
id: 'r1',
|
|
173
|
-
statementText: 'Difficult',
|
|
174
|
-
oppositeStatementText: 'Easy',
|
|
175
|
-
},
|
|
176
|
-
],
|
|
197
|
+
statementRows: BIPOLAR_ROWS_SINGLE,
|
|
177
198
|
scaleColumns: Array.from({ length: 5 }, (_, i) => ({ id: `c${i}`, label: '' })),
|
|
178
199
|
scaleAnchorLabels: ['Hard', '', '', '', 'Easy'],
|
|
179
200
|
});
|
|
@@ -217,13 +238,20 @@ export const FIXTURE_CFM_DROPDOWN = base({
|
|
|
217
238
|
scaleColumns: LIKERT_COLUMNS,
|
|
218
239
|
});
|
|
219
240
|
|
|
241
|
+
const LIKERT_ANCHOR_LABELS = LIKERT_COLUMNS.map((c) => c.label);
|
|
242
|
+
|
|
243
|
+
const RATING_TEN_COLUMNS = Array.from({ length: 10 }, (_, i) => ({
|
|
244
|
+
id: `c${i}`,
|
|
245
|
+
label: String(i + 1),
|
|
246
|
+
}));
|
|
247
|
+
|
|
220
248
|
export const FIXTURE_CSAT_EMOJI = base({
|
|
221
249
|
type: 'CSAT_MATRIX',
|
|
222
250
|
displayStyle: 'emoji',
|
|
223
251
|
gridLayout: 'standard',
|
|
224
252
|
statementRows: MATRIX_ROW_SINGLE,
|
|
225
|
-
scaleColumns:
|
|
226
|
-
scaleAnchorLabels:
|
|
253
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
254
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
227
255
|
});
|
|
228
256
|
|
|
229
257
|
export const FIXTURE_CSAT_STAR = base({
|
|
@@ -231,8 +259,8 @@ export const FIXTURE_CSAT_STAR = base({
|
|
|
231
259
|
displayStyle: 'star',
|
|
232
260
|
gridLayout: 'standard',
|
|
233
261
|
statementRows: MATRIX_ROW_SINGLE,
|
|
234
|
-
scaleColumns:
|
|
235
|
-
scaleAnchorLabels:
|
|
262
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
263
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
236
264
|
});
|
|
237
265
|
|
|
238
266
|
export const FIXTURE_CSAT_NUMBERED = base({
|
|
@@ -240,8 +268,8 @@ export const FIXTURE_CSAT_NUMBERED = base({
|
|
|
240
268
|
displayStyle: 'numbered',
|
|
241
269
|
gridLayout: 'standard',
|
|
242
270
|
statementRows: MATRIX_ROWS_MULTI,
|
|
243
|
-
scaleColumns:
|
|
244
|
-
scaleAnchorLabels:
|
|
271
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
272
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
245
273
|
});
|
|
246
274
|
|
|
247
275
|
export const FIXTURE_CSAT_GRAPHICS = base({
|
|
@@ -249,8 +277,8 @@ export const FIXTURE_CSAT_GRAPHICS = base({
|
|
|
249
277
|
displayStyle: 'graphics',
|
|
250
278
|
gridLayout: 'standard',
|
|
251
279
|
statementRows: MATRIX_ROW_SINGLE,
|
|
252
|
-
scaleColumns:
|
|
253
|
-
scaleAnchorLabels:
|
|
280
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
281
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
254
282
|
});
|
|
255
283
|
|
|
256
284
|
export const FIXTURE_CSAT_CAROUSEL = base({
|
|
@@ -280,8 +308,8 @@ export const FIXTURE_RATING_STAR = base({
|
|
|
280
308
|
gridLayout: 'standard',
|
|
281
309
|
showColumnHeaders: true,
|
|
282
310
|
statementRows: MATRIX_ROWS_MULTI,
|
|
283
|
-
scaleColumns:
|
|
284
|
-
scaleAnchorLabels:
|
|
311
|
+
scaleColumns: RATING_TEN_COLUMNS,
|
|
312
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
285
313
|
});
|
|
286
314
|
|
|
287
315
|
export const FIXTURE_RATING_NUMBERED = base({
|
|
@@ -289,8 +317,8 @@ export const FIXTURE_RATING_NUMBERED = base({
|
|
|
289
317
|
displayStyle: 'numbered',
|
|
290
318
|
gridLayout: 'standard',
|
|
291
319
|
statementRows: MATRIX_ROWS_MULTI,
|
|
292
|
-
scaleColumns:
|
|
293
|
-
scaleAnchorLabels:
|
|
320
|
+
scaleColumns: RATING_TEN_COLUMNS,
|
|
321
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
294
322
|
});
|
|
295
323
|
|
|
296
324
|
export const FIXTURE_RATING_RADIO = base({
|
|
@@ -298,8 +326,8 @@ export const FIXTURE_RATING_RADIO = base({
|
|
|
298
326
|
displayStyle: 'standard',
|
|
299
327
|
gridLayout: 'standard',
|
|
300
328
|
statementRows: MATRIX_ROW_SINGLE,
|
|
301
|
-
scaleColumns:
|
|
302
|
-
scaleAnchorLabels:
|
|
329
|
+
scaleColumns: RATING_TEN_COLUMNS,
|
|
330
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
303
331
|
});
|
|
304
332
|
|
|
305
333
|
export const FIXTURE_RATING_EMOJI = base({
|
|
@@ -307,8 +335,8 @@ export const FIXTURE_RATING_EMOJI = base({
|
|
|
307
335
|
displayStyle: 'emoji',
|
|
308
336
|
gridLayout: 'standard',
|
|
309
337
|
statementRows: MATRIX_ROW_SINGLE,
|
|
310
|
-
scaleColumns:
|
|
311
|
-
scaleAnchorLabels:
|
|
338
|
+
scaleColumns: RATING_TEN_COLUMNS,
|
|
339
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
312
340
|
});
|
|
313
341
|
|
|
314
342
|
export const FIXTURE_RATING_GRAPHICS = base({
|
|
@@ -316,8 +344,8 @@ export const FIXTURE_RATING_GRAPHICS = base({
|
|
|
316
344
|
displayStyle: 'graphics',
|
|
317
345
|
gridLayout: 'standard',
|
|
318
346
|
statementRows: MATRIX_ROW_SINGLE,
|
|
319
|
-
scaleColumns:
|
|
320
|
-
scaleAnchorLabels:
|
|
347
|
+
scaleColumns: RATING_TEN_COLUMNS,
|
|
348
|
+
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
321
349
|
});
|
|
322
350
|
|
|
323
351
|
export const FIXTURE_RATING_SLIDER = base({
|
|
@@ -339,10 +367,7 @@ export const FIXTURE_RATING_SLIDER = base({
|
|
|
339
367
|
|
|
340
368
|
export const FIXTURE_SLIDER = base({
|
|
341
369
|
type: 'SLIDER_MATRIX',
|
|
342
|
-
statementRows:
|
|
343
|
-
{ id: 'r1', statementText: 'Statement Item 1', min: 0, max: 10, step: 1 },
|
|
344
|
-
{ id: 'r2', statementText: 'Statement Item 2', min: 0, max: 10, step: 1 },
|
|
345
|
-
],
|
|
370
|
+
statementRows: SLIDER_ROWS_MULTI.slice(0, 2),
|
|
346
371
|
scaleAnchorLabels: ['Label 1', 'Label 2'],
|
|
347
372
|
ticks: {
|
|
348
373
|
count: 11,
|
|
@@ -9,8 +9,14 @@ body {
|
|
|
9
9
|
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
10
10
|
color: #262626;
|
|
11
11
|
background-color: #ffffff;
|
|
12
|
+
max-width: 100%;
|
|
13
|
+
overflow-x: hidden;
|
|
14
|
+
box-sizing: border-box;
|
|
12
15
|
}
|
|
13
16
|
|
|
14
17
|
#root {
|
|
15
18
|
min-height: 100vh;
|
|
19
|
+
max-width: 100%;
|
|
20
|
+
overflow-x: hidden;
|
|
21
|
+
box-sizing: border-box;
|
|
16
22
|
}
|