@explorer02/cfm-survey-sdk 0.4.0 → 0.4.1
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 +64 -64
- package/dist/cli/index.mjs +63 -63
- package/package.json +1 -1
- package/templates/docs/templates/CsatMatrixScale.tsx +79 -23
- package/templates/docs/templates/Footer.tsx +3 -2
- package/templates/docs/templates/labelStyles.ts +27 -0
- package/templates/docs/templates/uiConfig.ts +23 -8
- package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +54 -8
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +1 -1
- package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +3 -3
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +6 -9
- package/templates/preview-harness/vite-app/src/mergePreviewQuestion.ts +67 -7
- package/templates/preview-harness/vite-app/src/preview-live-overrides.css +8 -0
- package/templates/survey-theme.css +13 -0
- package/templates/wizard-dist/assets/{PreviewMock-BlOAvUCN.js → PreviewMock-MsONyaq9.js} +1 -1
- package/templates/wizard-dist/assets/TypePanel-D24BxbHk.js +1 -0
- package/templates/wizard-dist/assets/index-C7RSJr09.js +34 -0
- package/templates/wizard-dist/index.html +1 -1
- package/templates/wizard-dist/assets/TypePanel-DcbMaw1b.js +0 -1
- package/templates/wizard-dist/assets/index-2Bi_7Fdh.js +0 -34
package/package.json
CHANGED
|
@@ -16,14 +16,64 @@ import {
|
|
|
16
16
|
mcqSelectedAccentVar,
|
|
17
17
|
mcqSelectedBgVar,
|
|
18
18
|
} from '@/lib/surveyUi/selectionStyles';
|
|
19
|
-
import { csatColumnLabelStyle, ratingColumnLabelStyle } from '@/lib/surveyUi/labelStyles';
|
|
19
|
+
import { csatColumnLabelStyle, ratingColumnLabelStyle, stackAnchorLabelLines, ratingAnchorLabelPillStyle } from '@/lib/surveyUi/labelStyles';
|
|
20
20
|
|
|
21
21
|
const MATRIX_ROW_LABEL_WIDTH = 'var(--cfm-matrix-row-width, 180px)';
|
|
22
22
|
|
|
23
23
|
type CsatMatrixQuestion = CsatQuestion | RatingMatrixQuestion;
|
|
24
24
|
|
|
25
25
|
function anchorLabelStyle(question: CsatMatrixQuestion) {
|
|
26
|
-
return question.type === 'RATING_MATRIX' ?
|
|
26
|
+
return question.type === 'RATING_MATRIX' ? ratingAnchorLabelPillStyle() : csatColumnLabelStyle();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function anchorLabelPositionPercent(
|
|
30
|
+
index: number,
|
|
31
|
+
labelCount: number,
|
|
32
|
+
columnCount: number,
|
|
33
|
+
isGraphics: boolean,
|
|
34
|
+
question: CsatMatrixQuestion,
|
|
35
|
+
): number {
|
|
36
|
+
if (labelCount === 1) return 50;
|
|
37
|
+
const useFullSpan = isGraphics || question.type === 'RATING_MATRIX';
|
|
38
|
+
const startPercent = useFullSpan ? 0 : 0.5 / columnCount;
|
|
39
|
+
const rangePercent = useFullSpan ? 1 : (columnCount - 1) / columnCount;
|
|
40
|
+
return (startPercent + (index / (labelCount - 1)) * rangePercent) * 100;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function anchorLabelRowMinHeight(question: CsatMatrixQuestion, hasLabels: boolean): string {
|
|
44
|
+
if (question.type === 'RATING_MATRIX' && hasLabels) return '44px';
|
|
45
|
+
return '24px';
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function renderAnchorLabelContent(label: string, question: CsatMatrixQuestion): React.ReactNode {
|
|
49
|
+
if (question.type !== 'RATING_MATRIX') return label;
|
|
50
|
+
const lines = stackAnchorLabelLines(label);
|
|
51
|
+
if (lines.length === 1) return label;
|
|
52
|
+
return lines.map((line, idx) => (
|
|
53
|
+
<span key={idx} style={{ display: 'block' }}>
|
|
54
|
+
{line}
|
|
55
|
+
</span>
|
|
56
|
+
));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function anchorLabelBoxStyle(question: CsatMatrixQuestion, isGraphics: boolean): React.CSSProperties {
|
|
60
|
+
if (question.type === 'RATING_MATRIX') {
|
|
61
|
+
return {
|
|
62
|
+
textAlign: 'center',
|
|
63
|
+
fontSize: '12px',
|
|
64
|
+
fontWeight: 600,
|
|
65
|
+
...ratingAnchorLabelPillStyle(),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
textAlign: 'center',
|
|
70
|
+
fontSize: isGraphics ? '12px' : '13px',
|
|
71
|
+
fontWeight: 600,
|
|
72
|
+
lineHeight: 1.3,
|
|
73
|
+
whiteSpace: isGraphics ? 'normal' : 'nowrap',
|
|
74
|
+
maxWidth: isGraphics ? '72px' : undefined,
|
|
75
|
+
...anchorLabelStyle(question),
|
|
76
|
+
};
|
|
27
77
|
}
|
|
28
78
|
|
|
29
79
|
function columnHeaderLabelStyle(question: CsatMatrixQuestion) {
|
|
@@ -227,24 +277,25 @@ function CsatMatrixGrid({
|
|
|
227
277
|
<div style={{ display: 'flex', alignItems: 'flex-end', marginBottom: '12px', minWidth: 0 }}>
|
|
228
278
|
<div style={{ width: MATRIX_ROW_LABEL_WIDTH, flexShrink: 0, minWidth: 0 }} />
|
|
229
279
|
<div style={{ flex: 1, display: 'flex', minWidth: 0 }}>
|
|
230
|
-
<div style={{
|
|
280
|
+
<div style={{
|
|
281
|
+
flex: 1,
|
|
282
|
+
position: 'relative',
|
|
283
|
+
minHeight: anchorLabelRowMinHeight(question, Boolean(showLabels)),
|
|
284
|
+
minWidth: 0,
|
|
285
|
+
...(isGraphics || question.type === 'RATING_MATRIX' ? { margin: '0 8px' } : {}),
|
|
286
|
+
}}>
|
|
231
287
|
{labels!.map((label, i) => {
|
|
232
|
-
const
|
|
233
|
-
const rangePercent = isGraphics ? 1 : (m - 1) / m;
|
|
234
|
-
const percent = n === 1 ? 50 : (startPercent + (i / (n - 1)) * rangePercent) * 100;
|
|
288
|
+
const percent = anchorLabelPositionPercent(i, n, m, isGraphics, question);
|
|
235
289
|
|
|
236
290
|
return (
|
|
237
291
|
<div key={i} style={{
|
|
238
292
|
position: 'absolute',
|
|
239
293
|
left: `${percent}%`,
|
|
294
|
+
bottom: 0,
|
|
240
295
|
transform: 'translateX(-50%)',
|
|
241
|
-
|
|
242
|
-
lineHeight: 1.3,
|
|
243
|
-
whiteSpace: isGraphics ? 'normal' : 'nowrap',
|
|
244
|
-
maxWidth: isGraphics ? '72px' : undefined,
|
|
245
|
-
...anchorLabelStyle(question),
|
|
296
|
+
...anchorLabelBoxStyle(question, isGraphics),
|
|
246
297
|
}}>
|
|
247
|
-
{label}
|
|
298
|
+
{renderAnchorLabelContent(label, question)}
|
|
248
299
|
</div>
|
|
249
300
|
);
|
|
250
301
|
})}
|
|
@@ -465,24 +516,29 @@ function CsatMatrixCarousel({
|
|
|
465
516
|
<h3 style={{ fontSize: '18px', fontWeight: 500, color: '#111827', marginBottom: '32px', textAlign: 'center' }} dangerouslySetInnerHTML={{ __html: row.statementText }} />
|
|
466
517
|
|
|
467
518
|
{showLabels && scaleColumns.length > 0 && (
|
|
468
|
-
<div style={{
|
|
519
|
+
<div style={{
|
|
520
|
+
width: '100%',
|
|
521
|
+
maxWidth: '100%',
|
|
522
|
+
minWidth: 0,
|
|
523
|
+
position: 'relative',
|
|
524
|
+
minHeight: anchorLabelRowMinHeight(question, Boolean(showLabels)),
|
|
525
|
+
marginBottom: '16px',
|
|
526
|
+
...(isGraphics || question.type === 'RATING_MATRIX' ? { padding: '0 8px' } : {}),
|
|
527
|
+
}}>
|
|
469
528
|
{labels!.map((label, i) => {
|
|
470
529
|
const m = scaleColumns.length;
|
|
471
530
|
const n = labels!.length;
|
|
472
|
-
const
|
|
473
|
-
const rangePercent = isGraphics ? 1 : (m - 1) / m;
|
|
474
|
-
const percent = n === 1 ? 50 : (startPercent + (i / (n - 1)) * rangePercent) * 100;
|
|
531
|
+
const percent = anchorLabelPositionPercent(i, n, m, isGraphics, question);
|
|
475
532
|
|
|
476
533
|
return (
|
|
477
534
|
<div key={i} style={{
|
|
478
|
-
position: 'absolute',
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
...anchorLabelStyle(question),
|
|
535
|
+
position: 'absolute',
|
|
536
|
+
left: `${percent}%`,
|
|
537
|
+
bottom: 0,
|
|
538
|
+
transform: 'translateX(-50%)',
|
|
539
|
+
...anchorLabelBoxStyle(question, isGraphics),
|
|
484
540
|
}}>
|
|
485
|
-
{label}
|
|
541
|
+
{renderAnchorLabelContent(label, question)}
|
|
486
542
|
</div>
|
|
487
543
|
);
|
|
488
544
|
})}
|
|
@@ -39,10 +39,11 @@ export default function Footer() {
|
|
|
39
39
|
data-cfm-logo
|
|
40
40
|
src={seedLogoSrc!}
|
|
41
41
|
alt=""
|
|
42
|
-
className="object-contain"
|
|
42
|
+
className="object-contain object-left"
|
|
43
43
|
style={{
|
|
44
|
-
width: 'var(--cfm-footer-logo-width, 120px)',
|
|
45
44
|
height: 'var(--cfm-footer-logo-height, 32px)',
|
|
45
|
+
maxWidth: 'var(--cfm-footer-logo-width, 120px)',
|
|
46
|
+
width: 'auto',
|
|
46
47
|
}}
|
|
47
48
|
/>
|
|
48
49
|
</div>
|
|
@@ -64,3 +64,30 @@ export function ratingColumnLabelStyle(): CSSProperties {
|
|
|
64
64
|
export function sliderTickLabelStyle(): CSSProperties {
|
|
65
65
|
return columnLabelPillStyle('sliderTick');
|
|
66
66
|
}
|
|
67
|
+
|
|
68
|
+
/** Split multi-word anchor labels into stacked lines for equal-width matrix headers. */
|
|
69
|
+
export function stackAnchorLabelLines(label: string): string[] {
|
|
70
|
+
const trimmed = label.trim();
|
|
71
|
+
if (!trimmed) return [''];
|
|
72
|
+
const words = trimmed.split(/\s+/);
|
|
73
|
+
if (words.length <= 1) return [trimmed];
|
|
74
|
+
const mid = Math.ceil(words.length / 2);
|
|
75
|
+
return [words.slice(0, mid).join(' '), words.slice(mid).join(' ')].filter(Boolean);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** Rating matrix anchor pills — stacked text, fixed width, same look on every format. */
|
|
79
|
+
export function ratingAnchorLabelPillStyle(): CSSProperties {
|
|
80
|
+
return {
|
|
81
|
+
...columnLabelPillStyle('rating'),
|
|
82
|
+
display: 'inline-flex',
|
|
83
|
+
flexDirection: 'column',
|
|
84
|
+
alignItems: 'center',
|
|
85
|
+
justifyContent: 'center',
|
|
86
|
+
whiteSpace: 'normal',
|
|
87
|
+
maxWidth: '72px',
|
|
88
|
+
minWidth: '52px',
|
|
89
|
+
padding: '3px 6px',
|
|
90
|
+
wordBreak: 'break-word',
|
|
91
|
+
lineHeight: 1.15,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
@@ -136,6 +136,15 @@ export function resolveNpsButtonStyle(questionStyle?: string): NpsButtonStyle {
|
|
|
136
136
|
const live = readLiveNpsButtonStyle();
|
|
137
137
|
if (live) return live;
|
|
138
138
|
|
|
139
|
+
if (
|
|
140
|
+
questionStyle === 'standard' ||
|
|
141
|
+
questionStyle === 'numbered' ||
|
|
142
|
+
questionStyle === 'emoji' ||
|
|
143
|
+
questionStyle === 'pill'
|
|
144
|
+
) {
|
|
145
|
+
return questionStyle;
|
|
146
|
+
}
|
|
147
|
+
|
|
139
148
|
const fromJson = (
|
|
140
149
|
surveyUiConfig.questionTypes as { NPS_SCALE?: { buttonStyle?: string } } | undefined
|
|
141
150
|
)?.NPS_SCALE?.buttonStyle;
|
|
@@ -147,18 +156,24 @@ export function resolveNpsButtonStyle(questionStyle?: string): NpsButtonStyle {
|
|
|
147
156
|
) {
|
|
148
157
|
return fromJson;
|
|
149
158
|
}
|
|
150
|
-
if (
|
|
151
|
-
questionStyle === 'standard' ||
|
|
152
|
-
questionStyle === 'numbered' ||
|
|
153
|
-
questionStyle === 'emoji' ||
|
|
154
|
-
questionStyle === 'pill'
|
|
155
|
-
) {
|
|
156
|
-
return questionStyle;
|
|
157
|
-
}
|
|
158
159
|
return 'numbered';
|
|
159
160
|
}
|
|
160
161
|
|
|
162
|
+
function readLiveNpsHintText(kind: 'min' | 'max'): string | null {
|
|
163
|
+
if (typeof window === 'undefined') return null;
|
|
164
|
+
const root = document.documentElement;
|
|
165
|
+
const cssVar = kind === 'min' ? '--cfm-hint-min-text' : '--cfm-hint-max-text';
|
|
166
|
+
const fromCss =
|
|
167
|
+
root.style.getPropertyValue(cssVar).trim() ||
|
|
168
|
+
getComputedStyle(root).getPropertyValue(cssVar).trim();
|
|
169
|
+
return fromCss || null;
|
|
170
|
+
}
|
|
171
|
+
|
|
161
172
|
function resolveNpsHintText(kind: 'min' | 'max', questionFallback: string): string {
|
|
173
|
+
const fromCss = readLiveNpsHintText(kind);
|
|
174
|
+
if (fromCss) return fromCss;
|
|
175
|
+
if (questionFallback.trim()) return questionFallback;
|
|
176
|
+
|
|
162
177
|
const nps = (
|
|
163
178
|
surveyUiConfig.questionTypes as { NPS_SCALE?: { hintMinText?: string; hintMaxText?: string } } | undefined
|
|
164
179
|
)?.NPS_SCALE;
|
|
@@ -15,6 +15,7 @@ export type PreviewStatePatch = {
|
|
|
15
15
|
|
|
16
16
|
export const PREVIEW_BRIDGE_SNAPSHOT = 'CFM_UI_CONFIG_SNAPSHOT';
|
|
17
17
|
export const PREVIEW_BRIDGE_DELTA = 'CFM_UI_CONFIG_DELTA';
|
|
18
|
+
export const PREVIEW_BRIDGE_READY = 'CFM_PREVIEW_READY';
|
|
18
19
|
|
|
19
20
|
const TRAFFIC = [
|
|
20
21
|
'#ef4444', '#f97316', '#eab308', '#84cc16', '#22c55e', '#14b8a6',
|
|
@@ -51,6 +52,26 @@ function applyThemeSideEffects(): void {
|
|
|
51
52
|
applyDropzoneStyle();
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
function previewStateFromCssVars(
|
|
56
|
+
cssVars: Record<string, string>,
|
|
57
|
+
prev: PreviewStatePatch,
|
|
58
|
+
): PreviewStatePatch {
|
|
59
|
+
const next: PreviewStatePatch = { ...prev };
|
|
60
|
+
if (cssVars['--cfm-matrix-multi-statement'] !== undefined) {
|
|
61
|
+
next.multiStatement = cssVars['--cfm-matrix-multi-statement'] === '1';
|
|
62
|
+
}
|
|
63
|
+
if (cssVars['--cfm-nps-button-style']) {
|
|
64
|
+
next.npsButtonStyle = cssVars['--cfm-nps-button-style'];
|
|
65
|
+
}
|
|
66
|
+
if (cssVars['--cfm-hint-min-text']) {
|
|
67
|
+
next.hintMinText = cssVars['--cfm-hint-min-text'];
|
|
68
|
+
}
|
|
69
|
+
if (cssVars['--cfm-hint-max-text']) {
|
|
70
|
+
next.hintMaxText = cssVars['--cfm-hint-max-text'];
|
|
71
|
+
}
|
|
72
|
+
return next;
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
type PreviewConfigContextValue = {
|
|
55
76
|
previewState: PreviewStatePatch;
|
|
56
77
|
configRevision: number;
|
|
@@ -66,17 +87,47 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
66
87
|
const [configRevision, setConfigRevision] = useState(0);
|
|
67
88
|
|
|
68
89
|
useEffect(() => {
|
|
90
|
+
const requestSnapshot = () => {
|
|
91
|
+
try {
|
|
92
|
+
window.parent.postMessage({ type: PREVIEW_BRIDGE_READY }, '*');
|
|
93
|
+
} catch {
|
|
94
|
+
/* ignore */
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
requestSnapshot();
|
|
99
|
+
|
|
69
100
|
const handler = (event: MessageEvent) => {
|
|
70
101
|
const data = event.data;
|
|
71
102
|
if (!data?.type) return;
|
|
72
103
|
if (data.type !== PREVIEW_BRIDGE_SNAPSHOT && data.type !== PREVIEW_BRIDGE_DELTA) return;
|
|
73
104
|
|
|
74
|
-
|
|
105
|
+
const isSnapshot = data.type === PREVIEW_BRIDGE_SNAPSHOT;
|
|
106
|
+
let shouldBumpRevision = isSnapshot;
|
|
107
|
+
|
|
108
|
+
if (data.cssVars) {
|
|
109
|
+
const root = document.documentElement;
|
|
110
|
+
for (const [key, value] of Object.entries(data.cssVars)) {
|
|
111
|
+
root.style.setProperty(key, value as string);
|
|
112
|
+
}
|
|
113
|
+
shouldBumpRevision = true;
|
|
114
|
+
}
|
|
75
115
|
|
|
76
|
-
if (
|
|
116
|
+
if (isSnapshot) {
|
|
117
|
+
const patchState = (data.contentPatch?.previewState ?? {}) as PreviewStatePatch;
|
|
118
|
+
const nextState = data.cssVars
|
|
119
|
+
? previewStateFromCssVars(data.cssVars, patchState)
|
|
120
|
+
: patchState;
|
|
121
|
+
setPreviewState(nextState);
|
|
122
|
+
shouldBumpRevision = true;
|
|
123
|
+
} else if (data.contentPatch?.previewState) {
|
|
77
124
|
setPreviewState((prev) => ({ ...prev, ...data.contentPatch.previewState }));
|
|
78
125
|
shouldBumpRevision = true;
|
|
126
|
+
} else if (data.cssVars) {
|
|
127
|
+
setPreviewState((prev) => previewStateFromCssVars(data.cssVars, prev));
|
|
128
|
+
shouldBumpRevision = true;
|
|
79
129
|
}
|
|
130
|
+
|
|
80
131
|
if (data.contentPatch?.domAttributes) {
|
|
81
132
|
const root = document.documentElement;
|
|
82
133
|
for (const [key, value] of Object.entries(data.contentPatch.domAttributes)) {
|
|
@@ -84,12 +135,7 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
84
135
|
}
|
|
85
136
|
shouldBumpRevision = true;
|
|
86
137
|
}
|
|
87
|
-
|
|
88
|
-
const root = document.documentElement;
|
|
89
|
-
for (const [key, value] of Object.entries(data.cssVars)) {
|
|
90
|
-
root.style.setProperty(key, value as string);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
138
|
+
|
|
93
139
|
if (shouldBumpRevision) {
|
|
94
140
|
setConfigRevision((r) => r + 1);
|
|
95
141
|
}
|
|
@@ -34,7 +34,7 @@ function QuestionPreviewInner({ question, initialValue }: QuestionPreviewProps)
|
|
|
34
34
|
|
|
35
35
|
const mergedQuestion = useMemo(
|
|
36
36
|
() => mergePreviewQuestion(question, previewState),
|
|
37
|
-
[question, previewState],
|
|
37
|
+
[question, previewState, configRevision],
|
|
38
38
|
);
|
|
39
39
|
|
|
40
40
|
const heatmapInitial =
|
|
@@ -22,15 +22,15 @@ function SurveyPagePreviewInner() {
|
|
|
22
22
|
|
|
23
23
|
const mcqQuestion = useMemo(
|
|
24
24
|
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_MCQ, previewState),
|
|
25
|
-
[previewState],
|
|
25
|
+
[previewState, configRevision],
|
|
26
26
|
);
|
|
27
27
|
const matrixQuestion = useMemo(
|
|
28
28
|
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_CFM_LIKERT, previewState),
|
|
29
|
-
[previewState],
|
|
29
|
+
[previewState, configRevision],
|
|
30
30
|
);
|
|
31
31
|
const npsQuestion = useMemo(
|
|
32
32
|
() => mergeSurveyPageQuestion(FIXTURE_SURVEY_PAGE_NPS, previewState),
|
|
33
|
-
[previewState],
|
|
33
|
+
[previewState, configRevision],
|
|
34
34
|
);
|
|
35
35
|
|
|
36
36
|
const allQuestions = [mcqQuestion, matrixQuestion, npsQuestion];
|
|
@@ -181,7 +181,7 @@ export const FIXTURE_CFM_LIKERT = base({
|
|
|
181
181
|
showColumnHeaders: true,
|
|
182
182
|
repeatColumnHeaders: false,
|
|
183
183
|
hasNotApplicableOption: false,
|
|
184
|
-
statementRows:
|
|
184
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
185
185
|
scaleColumns: LIKERT_COLUMNS,
|
|
186
186
|
});
|
|
187
187
|
|
|
@@ -221,7 +221,7 @@ export const FIXTURE_CFM_CAROUSEL = base({
|
|
|
221
221
|
showColumnHeaders: true,
|
|
222
222
|
repeatColumnHeaders: false,
|
|
223
223
|
hasNotApplicableOption: false,
|
|
224
|
-
statementRows:
|
|
224
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
225
225
|
scaleColumns: LIKERT_COLUMNS,
|
|
226
226
|
});
|
|
227
227
|
|
|
@@ -267,7 +267,7 @@ export const FIXTURE_CSAT_NUMBERED = base({
|
|
|
267
267
|
type: 'CSAT_MATRIX',
|
|
268
268
|
displayStyle: 'numbered',
|
|
269
269
|
gridLayout: 'standard',
|
|
270
|
-
statementRows:
|
|
270
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
271
271
|
scaleColumns: LIKERT_COLUMNS,
|
|
272
272
|
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
273
273
|
});
|
|
@@ -307,7 +307,7 @@ export const FIXTURE_RATING_STAR = base({
|
|
|
307
307
|
displayStyle: 'star',
|
|
308
308
|
gridLayout: 'standard',
|
|
309
309
|
showColumnHeaders: true,
|
|
310
|
-
statementRows:
|
|
310
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
311
311
|
scaleColumns: RATING_TEN_COLUMNS,
|
|
312
312
|
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
313
313
|
});
|
|
@@ -316,7 +316,7 @@ export const FIXTURE_RATING_NUMBERED = base({
|
|
|
316
316
|
type: 'RATING_MATRIX',
|
|
317
317
|
displayStyle: 'numbered',
|
|
318
318
|
gridLayout: 'standard',
|
|
319
|
-
statementRows:
|
|
319
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
320
320
|
scaleColumns: RATING_TEN_COLUMNS,
|
|
321
321
|
scaleAnchorLabels: LIKERT_ANCHOR_LABELS,
|
|
322
322
|
});
|
|
@@ -352,10 +352,7 @@ export const FIXTURE_RATING_SLIDER = base({
|
|
|
352
352
|
type: 'RATING_MATRIX',
|
|
353
353
|
displayStyle: 'graphics',
|
|
354
354
|
gridLayout: 'standard',
|
|
355
|
-
statementRows:
|
|
356
|
-
{ id: 'r1', statementText: 'Statement Item 1' },
|
|
357
|
-
{ id: 'r2', statementText: 'Statement Item 2' },
|
|
358
|
-
],
|
|
355
|
+
statementRows: MATRIX_ROW_SINGLE,
|
|
359
356
|
scaleColumns: [
|
|
360
357
|
{ id: 'c1', label: 'Likely' },
|
|
361
358
|
{ id: 'c2', label: 'Unlikely' },
|
|
@@ -37,6 +37,46 @@ const MULTI_STATEMENT_MATRIX_TYPES = new Set([
|
|
|
37
37
|
'SLIDER_MATRIX',
|
|
38
38
|
]);
|
|
39
39
|
|
|
40
|
+
/** Each preview iframe loads one fixture — infer its format tab from fixture shape. */
|
|
41
|
+
function inferPreviewKeyFromQuestion(q: SurveyQuestion): string | null {
|
|
42
|
+
if (q.type === 'CFM_MATRIX') {
|
|
43
|
+
if (q.statementLayout === 'bipolar') return 'CFM_bipolar';
|
|
44
|
+
if (q.transposeTable) return 'CFM_transpose';
|
|
45
|
+
if (q.gridLayout === 'carousel') return 'CFM_carousel';
|
|
46
|
+
if (q.gridLayout === 'dropdown') return 'CFM_dropdown';
|
|
47
|
+
return 'CFM_likert';
|
|
48
|
+
}
|
|
49
|
+
if (q.type === 'RANK_ORDER') {
|
|
50
|
+
const mode = (q as { interactionMode?: string }).interactionMode;
|
|
51
|
+
if (mode === 'dropdown') return 'RANK_dropdown';
|
|
52
|
+
return 'RANK_drag';
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function resolvePreviewKey(
|
|
58
|
+
previewState: PreviewStatePatch,
|
|
59
|
+
question: SurveyQuestion,
|
|
60
|
+
): string {
|
|
61
|
+
if (previewState.activePreviewKey === 'survey_page') return 'survey_page';
|
|
62
|
+
const inferred = inferPreviewKeyFromQuestion(question);
|
|
63
|
+
if (inferred) return inferred;
|
|
64
|
+
return previewState.activePreviewKey ?? '';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function resolveMultiStatementFlag(
|
|
68
|
+
previewState: PreviewStatePatch,
|
|
69
|
+
): boolean | undefined {
|
|
70
|
+
if (previewState.multiStatement !== undefined) return previewState.multiStatement;
|
|
71
|
+
if (typeof document === 'undefined') return undefined;
|
|
72
|
+
const css = getComputedStyle(document.documentElement)
|
|
73
|
+
.getPropertyValue('--cfm-matrix-multi-statement')
|
|
74
|
+
.trim();
|
|
75
|
+
if (css === '1') return true;
|
|
76
|
+
if (css === '0') return false;
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
40
80
|
export function applyMatrixRowCount<T extends MatrixRowCapable>(
|
|
41
81
|
q: T,
|
|
42
82
|
multiStatement: boolean | undefined,
|
|
@@ -52,18 +92,27 @@ export function applyMatrixRowCount<T extends MatrixRowCapable>(
|
|
|
52
92
|
|
|
53
93
|
if (multiStatement === true) {
|
|
54
94
|
if (isBipolar) {
|
|
55
|
-
return {
|
|
95
|
+
return {
|
|
96
|
+
...q,
|
|
97
|
+
statementRows: BIPOLAR_ROWS_MULTI,
|
|
98
|
+
showColumnHeaders: false,
|
|
99
|
+
statementLayout: 'bipolar',
|
|
100
|
+
} as T;
|
|
56
101
|
}
|
|
57
102
|
if (isSlider) {
|
|
58
103
|
return { ...q, statementRows: SLIDER_ROWS_MULTI } as T;
|
|
59
104
|
}
|
|
60
|
-
if (q.statementRows.length >= 3) return q;
|
|
61
105
|
return { ...q, statementRows: MATRIX_ROWS_MULTI } as T;
|
|
62
106
|
}
|
|
63
107
|
|
|
64
108
|
if (multiStatement === false) {
|
|
65
109
|
if (isBipolar) {
|
|
66
|
-
return {
|
|
110
|
+
return {
|
|
111
|
+
...q,
|
|
112
|
+
statementRows: BIPOLAR_ROWS_SINGLE,
|
|
113
|
+
showColumnHeaders: false,
|
|
114
|
+
statementLayout: 'bipolar',
|
|
115
|
+
} as T;
|
|
67
116
|
}
|
|
68
117
|
if (isSlider) {
|
|
69
118
|
return { ...q, statementRows: SLIDER_ROWS_SINGLE } as T;
|
|
@@ -71,7 +120,6 @@ export function applyMatrixRowCount<T extends MatrixRowCapable>(
|
|
|
71
120
|
return { ...q, statementRows: [...MATRIX_ROW_SINGLE] } as T;
|
|
72
121
|
}
|
|
73
122
|
|
|
74
|
-
// Before bridge snapshot — keep fixture row count (single-row fixtures stay single).
|
|
75
123
|
return q;
|
|
76
124
|
}
|
|
77
125
|
|
|
@@ -84,7 +132,19 @@ function applyCfmMatrixLayout(
|
|
|
84
132
|
},
|
|
85
133
|
previewKey: string,
|
|
86
134
|
): SurveyQuestion {
|
|
87
|
-
if (previewKey === 'survey_page'
|
|
135
|
+
if (previewKey === 'survey_page') {
|
|
136
|
+
return {
|
|
137
|
+
...q,
|
|
138
|
+
statementLayout: 'likert',
|
|
139
|
+
gridLayout: 'standard',
|
|
140
|
+
transposeTable: false,
|
|
141
|
+
showColumnHeaders: true,
|
|
142
|
+
} as SurveyQuestion;
|
|
143
|
+
}
|
|
144
|
+
if (!previewKey) {
|
|
145
|
+
return q as SurveyQuestion;
|
|
146
|
+
}
|
|
147
|
+
if (previewKey === 'CFM_likert' || !previewKey.startsWith('CFM_')) {
|
|
88
148
|
return {
|
|
89
149
|
...q,
|
|
90
150
|
statementLayout: 'likert',
|
|
@@ -120,7 +180,7 @@ export function mergePreviewQuestion(
|
|
|
120
180
|
previewState: PreviewStatePatch,
|
|
121
181
|
): SurveyQuestion {
|
|
122
182
|
let q = { ...question } as SurveyQuestion;
|
|
123
|
-
const previewKey = previewState
|
|
183
|
+
const previewKey = resolvePreviewKey(previewState, question);
|
|
124
184
|
const isSurveyPage = previewKey === 'survey_page';
|
|
125
185
|
|
|
126
186
|
if (previewState.textfieldPlaceholder && q.type === 'TEXTFIELD') {
|
|
@@ -159,7 +219,7 @@ export function mergePreviewQuestion(
|
|
|
159
219
|
}
|
|
160
220
|
}
|
|
161
221
|
|
|
162
|
-
return applyMatrixRowCount(q, previewState
|
|
222
|
+
return applyMatrixRowCount(q, resolveMultiStatementFlag(previewState), {
|
|
163
223
|
preserveSurveyPageRows: isSurveyPage,
|
|
164
224
|
});
|
|
165
225
|
}
|
|
@@ -90,6 +90,14 @@ html.cfm-live-edit .cfm-footer-inner {
|
|
|
90
90
|
flex-direction: var(--cfm-footer-flex-direction, row) !important;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
html.cfm-live-edit [data-cfm-footer-logo] {
|
|
94
|
+
object-fit: contain !important;
|
|
95
|
+
object-position: left center !important;
|
|
96
|
+
height: var(--cfm-footer-logo-height, 32px) !important;
|
|
97
|
+
max-width: var(--cfm-footer-logo-width, 120px) !important;
|
|
98
|
+
width: auto !important;
|
|
99
|
+
}
|
|
100
|
+
|
|
93
101
|
html.cfm-live-edit .rounded-xl,
|
|
94
102
|
html.cfm-live-edit .rounded-md,
|
|
95
103
|
html.cfm-live-edit .rounded-lg {
|
|
@@ -228,6 +228,19 @@ body {
|
|
|
228
228
|
grid-row: 1;
|
|
229
229
|
justify-self: var(--cfm-footer-logo-justify, start);
|
|
230
230
|
align-self: end;
|
|
231
|
+
display: flex;
|
|
232
|
+
justify-content: flex-start;
|
|
233
|
+
width: 100%;
|
|
234
|
+
max-width: 100%;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
.cfm-footer-logo-slot img,
|
|
238
|
+
[data-cfm-footer-logo] {
|
|
239
|
+
object-fit: contain;
|
|
240
|
+
object-position: left center;
|
|
241
|
+
height: var(--cfm-footer-logo-height, 32px);
|
|
242
|
+
max-width: var(--cfm-footer-logo-width, 120px);
|
|
243
|
+
width: auto;
|
|
231
244
|
}
|
|
232
245
|
|
|
233
246
|
.cfm-footer-links {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as x,j as e}from"./index-
|
|
1
|
+
import{u as x,j as e}from"./index-C7RSJr09.js";import{b as t}from"./vendor-BwkXDkd3.js";function p(d=150){const l=x(r=>r.config),[a,s]=t.useState(l);return t.useEffect(()=>{const r=window.setTimeout(()=>s(l),d);return()=>window.clearTimeout(r)},[l,d]),a}const h=t.memo(function(){const l=p(150),a=x(n=>n.logoPreviewDataUrl),{global:s}=l,{layout:r,colorScheme:o,buttons:c}=s,m=t.useMemo(()=>r.borderStyle==="sharp"?"rounded-none":r.borderStyle==="pill"?"rounded-[32px]":"rounded-2xl",[r.borderStyle]),i=t.useMemo(()=>r.fontStyle==="serif"?"Georgia, serif":r.fontStyle==="system"?"system-ui, sans-serif":"Inter, sans-serif",[r.fontStyle]),u=a??s.logo.url,f=t.useMemo(()=>({backgroundColor:o.background,color:o.text,borderColor:o.secondary,fontFamily:i}),[o,i]);return e.jsxs("div",{className:`overflow-hidden border shadow-md ${m}`,style:f,children:[r.showHeader&&e.jsxs("div",{className:"flex items-center gap-3 border-b px-5 py-4",style:{borderColor:o.secondary},children:[u&&e.jsx("img",{src:u,alt:"Logo",className:"max-h-6 w-auto object-contain",loading:"lazy"}),e.jsx("span",{className:"text-xs font-semibold tracking-wider",children:s.companyName})]}),e.jsxs("div",{className:"space-y-6 p-6",children:[r.showProgressBar&&e.jsxs("div",{className:"space-y-1.5",children:[e.jsxs("div",{className:"flex justify-between text-[10px] font-semibold text-slate-400",children:[e.jsx("span",{children:"Progress"}),e.jsx("span",{children:"35%"})]}),e.jsx("div",{className:"h-1.5 w-full overflow-hidden rounded-full bg-slate-100",children:e.jsx("div",{className:"h-full w-[35%] rounded-full",style:{backgroundColor:o.accent}})})]}),e.jsxs("div",{className:"space-y-3",children:[e.jsxs("h4",{className:"flex items-start gap-1.5 text-sm font-bold leading-snug",children:[r.showQuestionNumbers&&e.jsx("span",{className:"font-medium text-slate-400",children:"Q1."}),e.jsx("span",{children:s.surveyTitle}),r.showRequiredAsterisk&&e.jsx("span",{className:"text-red-500",children:"*"})]}),e.jsx("p",{className:"text-[11px] text-slate-400",children:"How would you rate your overall experience?"}),e.jsx("div",{className:"grid grid-cols-5 gap-2",children:[1,2,3,4,5].map(n=>e.jsx("div",{className:`flex h-9 items-center justify-center border text-xs font-semibold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:n===1?{backgroundColor:o.secondary,borderColor:o.primary,color:o.primary}:{backgroundColor:o.background,borderColor:o.secondary,color:o.text},children:n},n))})]})]}),e.jsxs("div",{className:"flex items-center justify-between border-t bg-slate-50/50 px-6 py-4",children:[r.showBackButton&&e.jsx("span",{className:`border px-3 py-1.5 text-[10px] font-semibold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:{borderColor:o.secondary,color:o.text},children:c.back}),e.jsx("div",{className:"flex-1"}),r.showNextButton&&e.jsx("span",{className:`px-4 py-1.5 text-[10px] font-bold ${r.borderStyle==="pill"?"rounded-full":r.borderStyle==="sharp"?"rounded-none":"rounded-lg"}`,style:{backgroundColor:o.primary,color:o.buttonText},children:c.next})]})]})});export{h as PreviewMock};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as m,j as e,T as P,S as b,R as d,C as i,N as t,a as R,M as z}from"./index-C7RSJr09.js";import"./vendor-BwkXDkd3.js";function C({values:n,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Label text color",value:n.columnLabelColor,onChange:a=>r({columnLabelColor:a})}),e.jsx(i,{label:"Label background",value:n.columnLabelBgColor,onChange:a=>r({columnLabelBgColor:a})})]})}function T({values:n,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Min hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:n.hintMinText,onChange:a=>r({hintMinText:a.target.value})})]}),e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Max hint label"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:n.hintMaxText,onChange:a=>r({hintMaxText:a.target.value})})]}),e.jsx(i,{label:"Hint text color",value:n.hintLabelColor,onChange:a=>r({hintLabelColor:a})}),e.jsx(i,{label:"Hint label background",value:n.hintLabelBgColor,onChange:a=>r({hintLabelBgColor:a})})]})}function M({values:n,onPatch:r,count:a=11}){return e.jsxs("div",{className:"space-y-3",children:[e.jsx(b,{label:"Number label style",value:n.numberLabelMode,onChange:c=>r({numberLabelMode:c}),options:[{value:"traffic",label:"Traffic light (default)"},{value:"monochrome",label:"Monochrome (one color)"},{value:"individual",label:"Individual per number"}]}),n.numberLabelMode==="monochrome"&&e.jsx(i,{label:"Monochrome color",value:n.monochromeNumberColor,onChange:c=>r({monochromeNumberColor:c})}),n.numberLabelMode==="individual"&&e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Array.from({length:a},(c,x)=>e.jsx(i,{label:`#${x}`,value:n.individualNumberColors[x]??"#9CA3AF",onChange:j=>{const h=[...n.individualNumberColors];h[x]=j,r({individualNumberColors:h})}},x))})]})}function s({title:n,children:r}){return e.jsxs("div",{className:"space-y-3 rounded-xl border border-white/5 bg-slate-950/20 p-4",children:[e.jsx("h4",{className:"text-xs font-semibold uppercase tracking-wider text-slate-400",children:n}),r]})}function I({type:n,activeFormat:r}){const a=m(l=>l.config.questionTypes[n]),c=m(l=>l.updateQuestionType),x=m(l=>l.previewMultiStatementByType),j=m(l=>l.setPreviewMultiStatementForType),h=m(l=>l.heatmapPreviewPin);if(!a)return e.jsx("p",{className:"text-sm text-slate-500",children:"No configuration available for this type."});const o=l=>c(n,l),f=z.includes(n),B=!!x[n],g=r.includes("star"),u=r.includes("emoji"),p=r.includes("numbered"),v=r.includes("drag"),S=r.includes("dropdown"),N=r.includes("radio"),k=r==="CFM_bipolar",w=r.includes("graphics"),y=a.optionStyle??a.cardStyle??"outlined",L=a.buttonStyle??"numbered";return e.jsxs("div",{className:"space-y-4",children:[f&&e.jsx(P,{label:"Preview multiple statements",checked:B,onChange:l=>j(n,l)}),n==="MCQ"&&"optionGap"in a&&e.jsx(s,{title:"Option style",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(b,{label:"Option style",value:a.optionStyle??a.cardStyle??"outlined",onChange:l=>o({optionStyle:l}),options:[{value:"outlined",label:"Outlined"},{value:"filled",label:"Filled"},{value:"minimal",label:"Minimal"}]}),e.jsx(d,{label:"Option gap",value:a.optionGap,onChange:l=>o({optionGap:l}),min:0,max:32}),e.jsx(d,{label:"Border radius",value:a.borderRadius,onChange:l=>o({borderRadius:l}),min:0,max:24}),e.jsx(d,{label:"Option padding",value:a.optionPadding??12,onChange:l=>o({optionPadding:l}),min:4,max:24}),e.jsx(i,{label:"Hover border",value:a.hoverBorderColor,onChange:l=>o({hoverBorderColor:l})}),y==="filled"&&e.jsx(i,{label:"Unselected fill color",value:a.filledOptionBg??"#F9FAFB",onChange:l=>o({filledOptionBg:l})})]})}),n==="TEXTFIELD"&&"defaultPlaceholder"in a&&e.jsx(s,{title:"Text input",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsxs("label",{className:"space-y-1 sm:col-span-2",children:[e.jsx("span",{className:"text-[10px] font-semibold uppercase tracking-wider text-slate-500",children:"Default placeholder"}),e.jsx("input",{className:"w-full rounded-lg border border-white/10 bg-slate-950/50 px-3 py-2 text-sm text-white",value:a.defaultPlaceholder,onChange:l=>o({defaultPlaceholder:l.target.value})})]}),e.jsx(t,{label:"Input radius (px)",value:a.inputRadius,onChange:l=>o({inputRadius:l}),min:0,max:24}),e.jsx(i,{label:"Border color",value:a.borderColor,onChange:l=>o({borderColor:l})}),e.jsx(i,{label:"Placeholder color",value:a.placeholderColor,onChange:l=>o({placeholderColor:l})}),e.jsx(t,{label:"Input height (px)",value:a.inputHeight,onChange:l=>o({inputHeight:l}),min:32,max:64}),e.jsx(t,{label:"Input padding (px)",value:a.inputPadding,onChange:l=>o({inputPadding:l}),min:8,max:24})]})}),n==="NPS_SCALE"&&"buttonStyle"in a&&e.jsxs(e.Fragment,{children:[e.jsxs(s,{title:"NPS buttons",children:[e.jsx(b,{label:"Button style",value:a.buttonStyle,onChange:l=>o({buttonStyle:l}),options:[{value:"standard",label:"Radio"},{value:"numbered",label:"Numbered badges"}]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell and focus ring come from Theme → Question card."})]}),e.jsx(s,{title:"Hint labels",children:e.jsx(T,{values:a,onPatch:o})}),L==="numbered"&&e.jsx(s,{title:"Number labels",children:e.jsx(M,{values:a,onPatch:o})}),e.jsx(s,{title:"Track & cells",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(t,{label:"Cell size (px)",value:a.cellSize,onChange:l=>o({cellSize:l}),min:24,max:56}),e.jsx(t,{label:"Cell gap (px)",value:a.cellGap,onChange:l=>o({cellGap:l}),min:0,max:16}),e.jsx(i,{label:"Track bar",value:a.trackBarColor,onChange:l=>o({trackBarColor:l})})]})})]}),n==="CFM_MATRIX"&&"rowLabelWidth"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Matrix layout",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>o({rowLabelWidth:l}),min:120,max:280}),k&&e.jsx(t,{label:"Bipolar column width (%)",value:a.bipolarColumnWidthPercent,onChange:l=>o({bipolarColumnWidthPercent:l}),min:15,max:40}),e.jsx(t,{label:"Cell padding (px)",value:a.cellPadding,onChange:l=>o({cellPadding:l}),min:4,max:24})]})}),e.jsx(s,{title:"Label items",children:e.jsx(C,{values:a,onPatch:o})})]}),n==="CSAT_MATRIX"&&"emojiSize"in a&&e.jsxs(e.Fragment,{children:[(u||g||p)&&e.jsxs(s,{title:`${R.CSAT_MATRIX} — ${r.replace("CSAT_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[u&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>o({emojiSize:l}),min:16,max:40}),g&&e.jsx(i,{label:"Star color",value:a.accentColor,onChange:l=>o({accentColor:l})}),(u||g||p)&&e.jsx(d,{label:"Unselected opacity",value:Math.round(a.unselectedOpacity*100),onChange:l=>o({unselectedOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsxs(s,{title:"Label items",children:[e.jsx("p",{className:"text-xs text-slate-500",children:"Applies to the 5 text labels above options in all formats."}),e.jsx(C,{values:a,onPatch:o})]}),w&&e.jsx(s,{title:"Graphics track",children:e.jsx(i,{label:"Track color",value:a.graphicsTrackColor,onChange:l=>o({graphicsTrackColor:l})})})]}),n==="RATING_MATRIX"&&"unselectedStarOpacity"in a&&e.jsxs(e.Fragment,{children:[(u||g||p||N)&&e.jsxs(s,{title:`Rating — ${r.replace("RATING_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[u&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>o({emojiSize:l}),min:16,max:40}),g&&e.jsx(i,{label:"Star color",value:a.starColor,onChange:l=>o({starColor:l})}),(u||g||p||N)&&e.jsx(d,{label:"Unselected opacity",value:Math.round(a.unselectedStarOpacity*100),onChange:l=>o({unselectedStarOpacity:l/100}),min:10,max:100})]}),e.jsx("p",{className:"text-xs text-slate-500",children:"Selected cell color and focus ring come from Theme → Question card."})]}),e.jsxs(s,{title:"Label items",children:[e.jsx("p",{className:"text-xs text-slate-500",children:"Applies to the 5 text anchor labels in all formats."}),e.jsx(C,{values:a,onPatch:o})]}),w&&e.jsx(s,{title:"Graphics track",children:e.jsx(i,{label:"Track color",value:a.graphicsTrackColor,onChange:l=>o({graphicsTrackColor:l})})})]}),n==="SLIDER_MATRIX"&&"trackColor"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"Slider track",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Track",value:a.trackColor,onChange:l=>o({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>o({thumbColor:l})}),e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>o({rowLabelWidth:l}),min:120,max:280}),e.jsx(i,{label:"Row band",value:a.rowBandColor,onChange:l=>o({rowBandColor:l})}),e.jsx(t,{label:"Tick badge size (px)",value:a.tickBadgeSize,onChange:l=>o({tickBadgeSize:l}),min:20,max:40})]})}),e.jsx(s,{title:"Anchor hint labels",children:e.jsx(T,{values:a,onPatch:o})}),e.jsx(s,{title:"Tick number labels",children:e.jsx(M,{values:a,onPatch:o,count:11})})]}),n==="FILE_UPLOAD"&&"dropzoneStyle"in a&&e.jsx(s,{title:"Dropzone",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(b,{label:"Dropzone border",value:a.dropzoneStyle,onChange:l=>o({dropzoneStyle:l}),options:[{value:"dashed",label:"Dashed"},{value:"solid",label:"Solid"}]}),e.jsx(i,{label:"Border color",value:a.borderColor??a.accentColor,onChange:l=>o({borderColor:l})}),e.jsx(i,{label:"Fill color",value:a.dropzoneFillColor,onChange:l=>o({dropzoneFillColor:l})}),e.jsx(t,{label:"Padding (px)",value:a.dropzonePadding,onChange:l=>o({dropzonePadding:l}),min:12,max:48})]})}),n==="TEXT_AND_MEDIA"&&"mediaMaxWidth"in a&&e.jsx(s,{title:"Text & media",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(d,{label:"Media max width (%)",value:a.mediaMaxWidth,onChange:l=>o({mediaMaxWidth:l}),min:50,max:100}),e.jsx(d,{label:"Media corner radius",value:a.mediaRadius,onChange:l=>o({mediaRadius:l}),min:0,max:24}),e.jsx(i,{label:"Caption color",value:a.captionColor,onChange:l=>o({captionColor:l})}),e.jsx(t,{label:"Caption size (px)",value:a.captionSize,onChange:l=>o({captionSize:l}),min:10,max:24})]})}),n==="HEATMAP"&&"pinColor"in a&&e.jsx(s,{title:"Heatmap pin",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Pin color",value:a.pinColor,onChange:l=>o({pinColor:l})}),e.jsx(i,{label:"Pin border",value:a.pinBorderColor,onChange:l=>o({pinBorderColor:l})}),e.jsx(d,{label:"Pin size",value:a.pinSize,onChange:l=>o({pinSize:l}),min:8,max:32}),e.jsx(d,{label:"Overlay opacity",value:Math.round(a.overlayOpacity*100),onChange:l=>o({overlayOpacity:l/100}),min:0,max:80}),e.jsxs("p",{className:"text-xs text-slate-500 sm:col-span-2",children:["Click the heatmap image in the preview to place a pin and see styling update live. Pin preview position: ",Math.round(h.x*100),"%, ",Math.round(h.y*100),"%"]})]})}),n==="RANK_ORDER"&&"drag"in a&&e.jsxs(e.Fragment,{children:[e.jsx(s,{title:"List",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"List bg",value:a.drag.itemBg,onChange:l=>o({drag:{...a.drag,itemBg:l},dropdown:{...a.dropdown,itemBg:l}})}),e.jsx(i,{label:"List hover",value:a.dropdown.itemHoverBg??a.drag.itemHoverBg??"#F3F4F6",onChange:l=>o({drag:{...a.drag,itemHoverBg:l},dropdown:{...a.dropdown,itemHoverBg:l}})})]})}),e.jsx(s,{title:v?"Drag & drop":S?"Dropdown rank":"Rank order",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[v&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Drag handle",value:a.drag.dragHandleColor,onChange:l=>o({drag:{...a.drag,dragHandleColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.drag.rankBadgeColor,onChange:l=>o({drag:{...a.drag,rankBadgeColor:l},dropdown:{...a.dropdown,rankBadgeColor:l}})})]}),S&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Select border",value:a.dropdown.selectBorderColor,onChange:l=>o({dropdown:{...a.dropdown,selectBorderColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.drag.rankBadgeColor,onChange:l=>o({drag:{...a.drag,rankBadgeColor:l},dropdown:{...a.dropdown,rankBadgeColor:l}})})]})]})})]})]})}export{I as TypePanel};
|