@explorer02/cfm-survey-sdk 0.3.2 → 0.3.4
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 +55 -55
- package/dist/cli/index.mjs +61 -61
- package/package.json +1 -1
- package/templates/docs/00-integration/component-checklist.md +1 -0
- package/templates/docs/templates/CsatMatrixScale.tsx +86 -33
- package/templates/docs/templates/CustomSliderTrack.tsx +6 -4
- package/templates/docs/templates/Footer.tsx +69 -26
- package/templates/docs/templates/Header.tsx +102 -65
- package/templates/docs/templates/LikertMatrixScale.tsx +7 -6
- package/templates/docs/templates/Question.tsx +7 -1
- package/templates/docs/templates/RankOrderScale.tsx +8 -1
- package/templates/docs/templates/RatingScale.tsx +2 -1
- package/templates/docs/templates/SliderMatrixScale.tsx +5 -3
- package/templates/docs/templates/labelStyles.ts +59 -16
- package/templates/docs/templates/selectionStyles.ts +16 -1
- package/templates/docs/templates/surveyUiIcons.tsx +1 -1
- package/templates/preview-harness/vite-app/src/PreviewConfigContext.tsx +41 -1
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +2 -1
- package/templates/preview-harness/vite-app/src/SurveyPagePreview.tsx +3 -2
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +18 -9
- package/templates/survey-theme.css +14 -2
- package/templates/wizard-dist/assets/{PreviewMock-DbbLpHdF.js → PreviewMock-CC1UlWe-.js} +1 -1
- package/templates/wizard-dist/assets/TypePanel-DISCXm0z.js +1 -0
- package/templates/wizard-dist/assets/index-Blpq4QjK.js +34 -0
- package/templates/wizard-dist/assets/index-CVBd54V0.css +1 -0
- package/templates/wizard-dist/index.html +2 -2
- package/templates/wizard-dist/assets/TypePanel-DQbV2iCf.js +0 -1
- package/templates/wizard-dist/assets/index-BhWM50Yu.css +0 -1
- package/templates/wizard-dist/assets/index-CY7WMJ93.js +0 -34
|
@@ -2,8 +2,8 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import type { CfmMatrixQuestion, MatrixRowAnswers } from '@explorer02/cfm-survey-sdk';
|
|
3
3
|
import { columnSubmitValue } from './surveyUiScaleUtils';
|
|
4
4
|
import MatrixDropdown from './MatrixDropdown';
|
|
5
|
-
import { matrixColumnLabelStyle } from '@/lib/surveyUi/labelStyles';
|
|
6
|
-
import { focusRingVar, matrixCarouselDotVar, matrixRadioDotStyle, matrixRadioRingStyle } from '@/lib/surveyUi/selectionStyles';
|
|
5
|
+
import { columnLabelPillStyle, matrixColumnLabelStyle } from '@/lib/surveyUi/labelStyles';
|
|
6
|
+
import { focusRingVar, matrixCarouselDotVar, matrixRadioDotStyle, matrixRadioRingStyle, matrixRowBackgroundStyle } from '@/lib/surveyUi/selectionStyles';
|
|
7
7
|
|
|
8
8
|
const MATRIX_ROW_LABEL_WIDTH = 'var(--cfm-matrix-row-width, 180px)';
|
|
9
9
|
const BIPOLAR_COL_WIDTH = 'var(--cfm-matrix-bipolar-width, 25%)';
|
|
@@ -219,7 +219,7 @@ function LikertMatrixGridLayout({
|
|
|
219
219
|
position: 'absolute', left: leftPos, transform: 'translateX(-50%)',
|
|
220
220
|
bottom: 0, display: 'flex', justifyContent: 'center', whiteSpace: 'nowrap'
|
|
221
221
|
}}>
|
|
222
|
-
<span style={{ fontSize: '13px', fontWeight: 600,
|
|
222
|
+
<span style={{ fontSize: '13px', fontWeight: 600, ...columnLabelPillStyle('matrix') }}>{lbl}</span>
|
|
223
223
|
</div>
|
|
224
224
|
);
|
|
225
225
|
})}
|
|
@@ -234,7 +234,7 @@ function LikertMatrixGridLayout({
|
|
|
234
234
|
<div style={{ flex: 1, display: 'grid', gridTemplateColumns: `repeat(${gridCols.length}, 1fr)` }}>
|
|
235
235
|
{gridCols.map((col) => (
|
|
236
236
|
<div key={col.id} style={{ display: 'flex', justifyContent: 'center', padding: '0 4px' }}>
|
|
237
|
-
<span style={{ fontSize: '13px', fontWeight: 500,
|
|
237
|
+
<span style={{ fontSize: '13px', fontWeight: 500, ...columnLabelPillStyle('matrix') }}
|
|
238
238
|
dangerouslySetInnerHTML={{ __html: transposeTable ? ('statementText' in col ? col.statementText : col.label) : ('label' in col ? col.label : (col as { statementText: string }).statementText) }} />
|
|
239
239
|
</div>
|
|
240
240
|
))}
|
|
@@ -258,8 +258,9 @@ function LikertMatrixGridLayout({
|
|
|
258
258
|
{repeatColumnHeaders && renderHeader()}
|
|
259
259
|
<div style={{
|
|
260
260
|
display: 'flex', alignItems: 'center', borderRadius: '8px',
|
|
261
|
-
padding: 'var(--cfm-matrix-cell-padding, 12px) 0',
|
|
262
|
-
|
|
261
|
+
padding: 'var(--cfm-matrix-cell-padding, 12px) 0',
|
|
262
|
+
...matrixRowBackgroundStyle(rowIdx),
|
|
263
|
+
boxSizing: 'border-box',
|
|
263
264
|
}}>
|
|
264
265
|
<div style={{ flex: isBipolar ? `0 0 ${BIPOLAR_COL_WIDTH}` : `0 0 ${MATRIX_ROW_LABEL_WIDTH}`, padding: '0 16px', boxSizing: 'border-box' }}>
|
|
265
266
|
<span style={{ fontSize: '14px', fontWeight: 500, color: '#111827', lineHeight: 1.4, wordWrap: 'break-word', display: 'block' }}
|
|
@@ -121,6 +121,7 @@ export default function Question({
|
|
|
121
121
|
boxShadow: 'var(--cfm-card-shadow, 0 1px 3px rgba(0,0,0,0.1))',
|
|
122
122
|
borderRadius: 'var(--cfm-border-radius, 12px)',
|
|
123
123
|
fontFamily: 'var(--cfm-font-family)',
|
|
124
|
+
marginBottom: 'var(--cfm-card-gap, 32px)',
|
|
124
125
|
}}
|
|
125
126
|
>
|
|
126
127
|
<h2
|
|
@@ -149,15 +150,19 @@ export default function Question({
|
|
|
149
150
|
{question.type === QUESTION_TYPE.NPS_SCALE && (
|
|
150
151
|
<div className="space-y-3">
|
|
151
152
|
{(question.minLabel || question.midLabel || question.maxLabel) && (
|
|
152
|
-
<div className="relative w-full h-
|
|
153
|
+
<div className="relative w-full min-h-[24px] text-xs font-semibold">
|
|
153
154
|
<span
|
|
154
155
|
className="absolute left-0 top-0 max-w-[30%] text-left leading-tight"
|
|
156
|
+
style={{ ...hintLabelStyle(), padding: '2px 6px', borderRadius: '4px' }}
|
|
155
157
|
dangerouslySetInnerHTML={{ __html: question.minLabel ?? '' }}
|
|
156
158
|
/>
|
|
157
159
|
{question.midLabel && (
|
|
158
160
|
<span
|
|
159
161
|
className="absolute top-0 -translate-x-1/2 text-center max-w-[40%] leading-tight"
|
|
160
162
|
style={{
|
|
163
|
+
...hintLabelStyle(),
|
|
164
|
+
padding: '2px 6px',
|
|
165
|
+
borderRadius: '4px',
|
|
161
166
|
left: `${question.midLabelIndex !== undefined && question.options.length > 1
|
|
162
167
|
? (question.midLabelIndex / (question.options.length - 1)) * 100
|
|
163
168
|
: 50}%`,
|
|
@@ -167,6 +172,7 @@ export default function Question({
|
|
|
167
172
|
)}
|
|
168
173
|
<span
|
|
169
174
|
className="absolute right-0 top-0 max-w-[30%] text-right leading-tight"
|
|
175
|
+
style={{ ...hintLabelStyle(), padding: '2px 6px', borderRadius: '4px' }}
|
|
170
176
|
dangerouslySetInnerHTML={{ __html: question.maxLabel ?? '' }}
|
|
171
177
|
/>
|
|
172
178
|
</div>
|
|
@@ -121,12 +121,19 @@ function RankOrderOptionRow({
|
|
|
121
121
|
}: RankOrderOptionRowProps) {
|
|
122
122
|
return (
|
|
123
123
|
<div
|
|
124
|
-
className="flex items-center gap-3 rounded-lg border border-[#e5e5e5] transition-colors
|
|
124
|
+
className="flex items-center gap-3 rounded-lg border border-[#e5e5e5] transition-colors"
|
|
125
125
|
style={{
|
|
126
126
|
backgroundColor: 'var(--cfm-rank-item-bg, #fff)',
|
|
127
127
|
padding: 'var(--cfm-rank-item-padding, 12px 16px)',
|
|
128
128
|
marginBottom: 'var(--cfm-rank-item-gap, 12px)',
|
|
129
129
|
}}
|
|
130
|
+
onMouseEnter={(e) => {
|
|
131
|
+
e.currentTarget.style.backgroundColor =
|
|
132
|
+
'var(--cfm-rank-dropdown-hover-bg, var(--cfm-rank-item-bg, #f9fafb))';
|
|
133
|
+
}}
|
|
134
|
+
onMouseLeave={(e) => {
|
|
135
|
+
e.currentTarget.style.backgroundColor = 'var(--cfm-rank-item-bg, #fff)';
|
|
136
|
+
}}
|
|
130
137
|
>
|
|
131
138
|
{rankSelect}
|
|
132
139
|
{dragHandle}
|
|
@@ -112,7 +112,7 @@ export default function RatingScale({
|
|
|
112
112
|
<div role="radiogroup" className="w-full overflow-x-auto" data-cfm-nps-area>
|
|
113
113
|
{showNumberBadges && (
|
|
114
114
|
<div className="mb-3 min-w-0" style={gridStyle}>
|
|
115
|
-
{resolvedOptions.map((option) => {
|
|
115
|
+
{resolvedOptions.map((option, index) => {
|
|
116
116
|
const isSelected = isScaleAnswerSelected(selectedValue, option.value);
|
|
117
117
|
return (
|
|
118
118
|
<div key={`${questionId}-badge-${option.value}`} className="flex justify-center">
|
|
@@ -125,6 +125,7 @@ export default function RatingScale({
|
|
|
125
125
|
? scaleCellSelectedStyle(true)
|
|
126
126
|
: { backgroundColor: option.color }),
|
|
127
127
|
}}
|
|
128
|
+
data-cfm-number-badge={index}
|
|
128
129
|
title={option.label}
|
|
129
130
|
>
|
|
130
131
|
{option.label}
|
|
@@ -9,7 +9,7 @@ import React from 'react';
|
|
|
9
9
|
import type { SliderMatrixQuestion, MatrixRowAnswers } from '@explorer02/cfm-survey-sdk';
|
|
10
10
|
import { tickColorFromIndex } from './surveyUiScaleUtils';
|
|
11
11
|
import { CustomSliderTrack } from './CustomSliderTrack';
|
|
12
|
-
import {
|
|
12
|
+
import { columnLabelPillStyle, sliderTickLabelStyle } from '@/lib/surveyUi/labelStyles';
|
|
13
13
|
|
|
14
14
|
const MATRIX_ROW_LABEL_WIDTH = 'var(--cfm-matrix-row-width, 180px)';
|
|
15
15
|
const SLIDER_ROW_BAND = 'var(--cfm-slider-row-band, var(--cfm-row-band, #f3f4f6))';
|
|
@@ -84,12 +84,13 @@ export function SliderMatrixScale({ question, selectedValue = {}, onSelect }: Sl
|
|
|
84
84
|
marginBottom: '16px',
|
|
85
85
|
fontSize: '14px',
|
|
86
86
|
fontWeight: 500,
|
|
87
|
-
...hintLabelStyle(),
|
|
88
87
|
}}
|
|
89
88
|
>
|
|
90
89
|
{labels.map((lbl, idx) => (
|
|
91
90
|
<div key={idx} style={{ width: 0, display: 'flex', justifyContent: 'center' }}>
|
|
92
|
-
<span style={
|
|
91
|
+
<span style={columnLabelPillStyle('hint')}>
|
|
92
|
+
{lbl}
|
|
93
|
+
</span>
|
|
93
94
|
</div>
|
|
94
95
|
))}
|
|
95
96
|
</div>
|
|
@@ -180,6 +181,7 @@ export function SliderMatrixScale({ question, selectedValue = {}, onSelect }: Sl
|
|
|
180
181
|
<div key={row.id} style={{
|
|
181
182
|
display: 'flex', width: '100%', alignItems: 'center',
|
|
182
183
|
backgroundColor: SLIDER_ROW_BAND, borderRadius: '12px', padding: '16px', boxSizing: 'border-box',
|
|
184
|
+
borderBottom: '1px solid var(--cfm-card-border-color, #e5e7eb)',
|
|
183
185
|
}}>
|
|
184
186
|
<div style={{ flex: `0 0 ${MATRIX_ROW_LABEL_WIDTH}`, paddingRight: '16px', fontSize: '15px', color: '#111827', wordWrap: 'break-word', display: 'flex', alignItems: 'center' }}>
|
|
185
187
|
{row.statementText !== 'Question' && row.statementText !== '' ? (
|
|
@@ -4,30 +4,73 @@
|
|
|
4
4
|
*/
|
|
5
5
|
import type { CSSProperties } from 'react';
|
|
6
6
|
|
|
7
|
+
export type ColumnLabelScope = 'matrix' | 'csat' | 'rating' | 'hint' | 'sliderTick';
|
|
8
|
+
|
|
9
|
+
const PILL_BASE: CSSProperties = {
|
|
10
|
+
display: 'inline-flex',
|
|
11
|
+
alignItems: 'center',
|
|
12
|
+
justifyContent: 'center',
|
|
13
|
+
padding: '4px 10px',
|
|
14
|
+
borderRadius: 'var(--cfm-border-radius, 6px)',
|
|
15
|
+
textAlign: 'center',
|
|
16
|
+
lineHeight: 1.2,
|
|
17
|
+
whiteSpace: 'nowrap',
|
|
18
|
+
boxSizing: 'border-box',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function scopeColorVars(scope: ColumnLabelScope): { color: string; backgroundColor: string } {
|
|
22
|
+
switch (scope) {
|
|
23
|
+
case 'matrix':
|
|
24
|
+
return {
|
|
25
|
+
color: 'var(--cfm-matrix-column-label-color, #4b5563)',
|
|
26
|
+
backgroundColor: 'var(--cfm-matrix-column-label-bg, transparent)',
|
|
27
|
+
};
|
|
28
|
+
case 'csat':
|
|
29
|
+
return {
|
|
30
|
+
color: 'var(--cfm-csat-column-label-color, #4b5563)',
|
|
31
|
+
backgroundColor: 'var(--cfm-csat-column-label-bg, transparent)',
|
|
32
|
+
};
|
|
33
|
+
case 'rating':
|
|
34
|
+
return {
|
|
35
|
+
color: 'var(--cfm-rating-column-label-color, var(--cfm-matrix-column-label-color, #4b5563))',
|
|
36
|
+
backgroundColor: 'var(--cfm-rating-column-label-bg, var(--cfm-matrix-column-label-bg, transparent))',
|
|
37
|
+
};
|
|
38
|
+
case 'hint':
|
|
39
|
+
return {
|
|
40
|
+
color: 'var(--cfm-hint-label-color, #6b7280)',
|
|
41
|
+
backgroundColor: 'var(--cfm-hint-label-bg, transparent)',
|
|
42
|
+
};
|
|
43
|
+
case 'sliderTick':
|
|
44
|
+
return {
|
|
45
|
+
color: 'var(--cfm-slider-tick-label-color, #4b5563)',
|
|
46
|
+
backgroundColor: 'var(--cfm-slider-tick-label-bg, transparent)',
|
|
47
|
+
};
|
|
48
|
+
default:
|
|
49
|
+
return { color: '#4b5563', backgroundColor: 'transparent' };
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** Centered pill for column / anchor / tick labels — wizard Label Items customization. */
|
|
54
|
+
export function columnLabelPillStyle(scope: ColumnLabelScope): CSSProperties {
|
|
55
|
+
return { ...PILL_BASE, ...scopeColorVars(scope) };
|
|
56
|
+
}
|
|
57
|
+
|
|
7
58
|
export function hintLabelStyle(): CSSProperties {
|
|
8
|
-
return
|
|
9
|
-
color: 'var(--cfm-hint-label-color, #6b7280)',
|
|
10
|
-
backgroundColor: 'var(--cfm-hint-label-bg, transparent)',
|
|
11
|
-
};
|
|
59
|
+
return columnLabelPillStyle('hint');
|
|
12
60
|
}
|
|
13
61
|
|
|
14
62
|
export function matrixColumnLabelStyle(): CSSProperties {
|
|
15
|
-
return
|
|
16
|
-
color: 'var(--cfm-matrix-column-label-color, #4b5563)',
|
|
17
|
-
backgroundColor: 'var(--cfm-matrix-column-label-bg, transparent)',
|
|
18
|
-
};
|
|
63
|
+
return scopeColorVars('matrix');
|
|
19
64
|
}
|
|
20
65
|
|
|
21
66
|
export function csatColumnLabelStyle(): CSSProperties {
|
|
22
|
-
return
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
67
|
+
return scopeColorVars('csat');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function ratingColumnLabelStyle(): CSSProperties {
|
|
71
|
+
return scopeColorVars('rating');
|
|
26
72
|
}
|
|
27
73
|
|
|
28
74
|
export function sliderTickLabelStyle(): CSSProperties {
|
|
29
|
-
return
|
|
30
|
-
color: 'var(--cfm-slider-tick-label-color, #4b5563)',
|
|
31
|
-
backgroundColor: 'var(--cfm-slider-tick-label-bg, transparent)',
|
|
32
|
-
};
|
|
75
|
+
return scopeColorVars('sliderTick');
|
|
33
76
|
}
|
|
@@ -41,7 +41,7 @@ export function mcqOptionCardStyle(isSelected: boolean): CSSProperties {
|
|
|
41
41
|
if (optionStyle === 'filled') {
|
|
42
42
|
return {
|
|
43
43
|
...base,
|
|
44
|
-
background: isSelected ? mcqSelectedBgVar : 'var(--cfm-secondary, #f9fafb)',
|
|
44
|
+
background: isSelected ? mcqSelectedBgVar : 'var(--cfm-mcq-filled-bg, var(--cfm-secondary, #f9fafb))',
|
|
45
45
|
};
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -177,6 +177,21 @@ export function unselectedOpacityStyle(): CSSProperties {
|
|
|
177
177
|
return { opacity: 'var(--cfm-csat-unselected-opacity, 0.5)' };
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
/** Matrix statement row — zebra when --cfm-matrix-zebra-enabled is 1 (wizard multi-statement preview). */
|
|
181
|
+
export function matrixRowBackgroundStyle(rowIdx: number): CSSProperties {
|
|
182
|
+
let zebraOn = false;
|
|
183
|
+
if (typeof document !== 'undefined') {
|
|
184
|
+
zebraOn =
|
|
185
|
+
getComputedStyle(document.documentElement).getPropertyValue('--cfm-matrix-zebra-enabled').trim() ===
|
|
186
|
+
'1';
|
|
187
|
+
}
|
|
188
|
+
const useZebra = zebraOn && rowIdx % 2 === 0;
|
|
189
|
+
return {
|
|
190
|
+
backgroundColor: useZebra ? 'var(--cfm-zebra-row, rgba(249, 250, 251, 0.8))' : '#fff',
|
|
191
|
+
borderBottom: '1px solid var(--cfm-card-border-color, #e5e7eb)',
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
|
|
180
195
|
export function emojiSizeStyle(): CSSProperties {
|
|
181
196
|
return {
|
|
182
197
|
fontSize: 'var(--cfm-csat-emoji-size, 28px)',
|
|
@@ -31,7 +31,7 @@ for (let i = 0; i < 11; i++) {
|
|
|
31
31
|
const Icon = FACE_ICONS[i];
|
|
32
32
|
CsatEmojiSet[i + 1] = React.createElement(Icon as React.ElementType, {
|
|
33
33
|
className: 'transition-transform',
|
|
34
|
-
style: { color: EMOJI_COLORS[i], fontSize: '28px' },
|
|
34
|
+
style: { color: EMOJI_COLORS[i], fontSize: 'var(--cfm-csat-emoji-size, 28px)' },
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
|
|
@@ -16,16 +16,54 @@ export type PreviewStatePatch = {
|
|
|
16
16
|
export const PREVIEW_BRIDGE_SNAPSHOT = 'CFM_UI_CONFIG_SNAPSHOT';
|
|
17
17
|
export const PREVIEW_BRIDGE_DELTA = 'CFM_UI_CONFIG_DELTA';
|
|
18
18
|
|
|
19
|
+
const TRAFFIC = [
|
|
20
|
+
'#ef4444', '#f97316', '#eab308', '#84cc16', '#22c55e', '#14b8a6',
|
|
21
|
+
'#06b6d4', '#3b82f6', '#6366f1', '#8b5cf6', '#a855f7',
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
function readVar(name: string, fallback: string): string {
|
|
25
|
+
return getComputedStyle(document.documentElement).getPropertyValue(name).trim() || fallback;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function applyNumberBadgeColors(): void {
|
|
29
|
+
const mode = readVar('--cfm-number-label-mode', 'traffic');
|
|
30
|
+
const mono = readVar('--cfm-number-mono-color', '#9ca3af');
|
|
31
|
+
document.querySelectorAll('[data-cfm-number-badge]').forEach((el) => {
|
|
32
|
+
if (el.classList.contains('selected')) return;
|
|
33
|
+
const i = parseInt(el.getAttribute('data-cfm-number-badge') ?? '', 10);
|
|
34
|
+
if (Number.isNaN(i)) return;
|
|
35
|
+
let bg = TRAFFIC[i] ?? '#9ca3af';
|
|
36
|
+
if (mode === 'monochrome') bg = mono;
|
|
37
|
+
if (mode === 'individual') bg = readVar(`--cfm-number-color-${i}`, '#9ca3af');
|
|
38
|
+
(el as HTMLElement).style.backgroundColor = bg;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function applyDropzoneStyle(): void {
|
|
43
|
+
const style = readVar('--cfm-upload-border-style', 'dashed');
|
|
44
|
+
document.querySelectorAll('[data-cfm-dropzone], .cfm-dropzone').forEach((el) => {
|
|
45
|
+
(el as HTMLElement).style.borderStyle = style;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function applyThemeSideEffects(): void {
|
|
50
|
+
applyNumberBadgeColors();
|
|
51
|
+
applyDropzoneStyle();
|
|
52
|
+
}
|
|
53
|
+
|
|
19
54
|
type PreviewConfigContextValue = {
|
|
20
55
|
previewState: PreviewStatePatch;
|
|
56
|
+
configRevision: number;
|
|
21
57
|
};
|
|
22
58
|
|
|
23
59
|
const PreviewConfigContext = createContext<PreviewConfigContextValue>({
|
|
24
60
|
previewState: {},
|
|
61
|
+
configRevision: 0,
|
|
25
62
|
});
|
|
26
63
|
|
|
27
64
|
export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
28
65
|
const [previewState, setPreviewState] = useState<PreviewStatePatch>({});
|
|
66
|
+
const [configRevision, setConfigRevision] = useState(0);
|
|
29
67
|
|
|
30
68
|
useEffect(() => {
|
|
31
69
|
const handler = (event: MessageEvent) => {
|
|
@@ -47,6 +85,8 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
47
85
|
root.style.setProperty(key, value as string);
|
|
48
86
|
}
|
|
49
87
|
}
|
|
88
|
+
setConfigRevision((r) => r + 1);
|
|
89
|
+
applyThemeSideEffects();
|
|
50
90
|
};
|
|
51
91
|
|
|
52
92
|
window.addEventListener('message', handler);
|
|
@@ -63,7 +103,7 @@ export function PreviewConfigProvider({ children }: { children: ReactNode }) {
|
|
|
63
103
|
}, []);
|
|
64
104
|
|
|
65
105
|
return (
|
|
66
|
-
<PreviewConfigContext.Provider value={{ previewState }}>
|
|
106
|
+
<PreviewConfigContext.Provider value={{ previewState, configRevision }}>
|
|
67
107
|
{children}
|
|
68
108
|
</PreviewConfigContext.Provider>
|
|
69
109
|
);
|
|
@@ -48,7 +48,7 @@ function applyMatrixRowCount<T extends SurveyQuestion & { statementRows?: { id:
|
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
function QuestionPreviewInner({ question, initialValue }: QuestionPreviewProps) {
|
|
51
|
-
const { previewState } = usePreviewConfig();
|
|
51
|
+
const { previewState, configRevision } = usePreviewConfig();
|
|
52
52
|
const [value, setValue] = useState<AnswerValue | undefined>(initialValue);
|
|
53
53
|
|
|
54
54
|
const mergedQuestion = useMemo(() => {
|
|
@@ -143,6 +143,7 @@ function QuestionPreviewInner({ question, initialValue }: QuestionPreviewProps)
|
|
|
143
143
|
data-cfm-question-area
|
|
144
144
|
>
|
|
145
145
|
<Question
|
|
146
|
+
key={configRevision}
|
|
146
147
|
question={mergedQuestion}
|
|
147
148
|
selectedValue={heatmapInitial ?? value}
|
|
148
149
|
allAnswers={{}}
|
|
@@ -4,7 +4,7 @@ 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
|
-
import { PreviewConfigProvider } from './PreviewConfigContext';
|
|
7
|
+
import { PreviewConfigProvider, usePreviewConfig } from './PreviewConfigContext';
|
|
8
8
|
import {
|
|
9
9
|
FIXTURE_SURVEY_PAGE_MCQ,
|
|
10
10
|
FIXTURE_SURVEY_PAGE_NPS,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
} from './fixtures/questions';
|
|
13
13
|
|
|
14
14
|
function SurveyPagePreviewInner() {
|
|
15
|
+
const { configRevision } = usePreviewConfig();
|
|
15
16
|
const [lang, setLang] = useState('en');
|
|
16
17
|
const [mcqAnswer, setMcqAnswer] = useState<AnswerValue>('a');
|
|
17
18
|
const [npsAnswer, setNpsAnswer] = useState<AnswerValue>(8);
|
|
@@ -42,7 +43,7 @@ function SurveyPagePreviewInner() {
|
|
|
42
43
|
onChange={setLang}
|
|
43
44
|
/>
|
|
44
45
|
|
|
45
|
-
<div className="space-y-8">
|
|
46
|
+
<div className="space-y-8" key={configRevision}>
|
|
46
47
|
<Question
|
|
47
48
|
question={FIXTURE_SURVEY_PAGE_MCQ}
|
|
48
49
|
selectedValue={mcqAnswer}
|
|
@@ -209,8 +209,7 @@ export const FIXTURE_CSAT_EMOJI = base({
|
|
|
209
209
|
displayStyle: 'emoji',
|
|
210
210
|
gridLayout: 'standard',
|
|
211
211
|
statementRows: MATRIX_ROW_SINGLE,
|
|
212
|
-
scaleColumns:
|
|
213
|
-
scaleAnchorLabels: ['Very unhappy', '', '', '', 'Very happy'],
|
|
212
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
214
213
|
});
|
|
215
214
|
|
|
216
215
|
export const FIXTURE_CSAT_STAR = base({
|
|
@@ -218,7 +217,7 @@ export const FIXTURE_CSAT_STAR = base({
|
|
|
218
217
|
displayStyle: 'star',
|
|
219
218
|
gridLayout: 'standard',
|
|
220
219
|
statementRows: MATRIX_ROW_SINGLE,
|
|
221
|
-
scaleColumns:
|
|
220
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
222
221
|
});
|
|
223
222
|
|
|
224
223
|
export const FIXTURE_CSAT_NUMBERED = base({
|
|
@@ -226,7 +225,7 @@ export const FIXTURE_CSAT_NUMBERED = base({
|
|
|
226
225
|
displayStyle: 'numbered',
|
|
227
226
|
gridLayout: 'standard',
|
|
228
227
|
statementRows: MATRIX_ROWS_MULTI,
|
|
229
|
-
scaleColumns:
|
|
228
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
230
229
|
});
|
|
231
230
|
|
|
232
231
|
export const FIXTURE_CSAT_GRAPHICS = base({
|
|
@@ -234,8 +233,7 @@ export const FIXTURE_CSAT_GRAPHICS = base({
|
|
|
234
233
|
displayStyle: 'graphics',
|
|
235
234
|
gridLayout: 'standard',
|
|
236
235
|
statementRows: MATRIX_ROW_SINGLE,
|
|
237
|
-
scaleColumns:
|
|
238
|
-
scaleAnchorLabels: ['Label 1', 'Label 2'],
|
|
236
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
239
237
|
});
|
|
240
238
|
|
|
241
239
|
export const FIXTURE_CSAT_CAROUSEL = base({
|
|
@@ -243,7 +241,7 @@ export const FIXTURE_CSAT_CAROUSEL = base({
|
|
|
243
241
|
displayStyle: 'star',
|
|
244
242
|
gridLayout: 'carousel',
|
|
245
243
|
statementRows: [{ id: 'r1', statementText: 'Overall experience' }],
|
|
246
|
-
scaleColumns:
|
|
244
|
+
scaleColumns: LIKERT_COLUMNS,
|
|
247
245
|
});
|
|
248
246
|
|
|
249
247
|
export const FIXTURE_CSAT_DROPDOWN = base({
|
|
@@ -259,13 +257,22 @@ export const FIXTURE_CSAT_DROPDOWN = base({
|
|
|
259
257
|
],
|
|
260
258
|
});
|
|
261
259
|
|
|
260
|
+
const RATING_ANCHOR_LABELS = [
|
|
261
|
+
'Strongly Disagree',
|
|
262
|
+
'Disagree',
|
|
263
|
+
'Neutral',
|
|
264
|
+
'Agree',
|
|
265
|
+
'Strongly Agree',
|
|
266
|
+
];
|
|
267
|
+
|
|
262
268
|
export const FIXTURE_RATING_STAR = base({
|
|
263
269
|
type: 'RATING_MATRIX',
|
|
264
270
|
displayStyle: 'star',
|
|
265
271
|
gridLayout: 'standard',
|
|
266
272
|
showColumnHeaders: true,
|
|
267
273
|
statementRows: MATRIX_ROWS_MULTI,
|
|
268
|
-
scaleColumns:
|
|
274
|
+
scaleColumns: Array.from({ length: 10 }, (_, i) => ({ id: `c${i}`, label: String(i + 1) })),
|
|
275
|
+
scaleAnchorLabels: RATING_ANCHOR_LABELS,
|
|
269
276
|
});
|
|
270
277
|
|
|
271
278
|
export const FIXTURE_RATING_NUMBERED = base({
|
|
@@ -274,6 +281,7 @@ export const FIXTURE_RATING_NUMBERED = base({
|
|
|
274
281
|
gridLayout: 'standard',
|
|
275
282
|
statementRows: MATRIX_ROWS_MULTI,
|
|
276
283
|
scaleColumns: Array.from({ length: 10 }, (_, i) => ({ id: `c${i}`, label: String(i + 1) })),
|
|
284
|
+
scaleAnchorLabels: RATING_ANCHOR_LABELS,
|
|
277
285
|
});
|
|
278
286
|
|
|
279
287
|
export const FIXTURE_RATING_RADIO = base({
|
|
@@ -290,6 +298,7 @@ export const FIXTURE_RATING_EMOJI = base({
|
|
|
290
298
|
gridLayout: 'standard',
|
|
291
299
|
statementRows: MATRIX_ROW_SINGLE,
|
|
292
300
|
scaleColumns: Array.from({ length: 10 }, (_, i) => ({ id: `c${i}`, label: String(i + 1) })),
|
|
301
|
+
scaleAnchorLabels: RATING_ANCHOR_LABELS,
|
|
293
302
|
});
|
|
294
303
|
|
|
295
304
|
export const FIXTURE_RATING_GRAPHICS = base({
|
|
@@ -298,7 +307,7 @@ export const FIXTURE_RATING_GRAPHICS = base({
|
|
|
298
307
|
gridLayout: 'standard',
|
|
299
308
|
statementRows: MATRIX_ROW_SINGLE,
|
|
300
309
|
scaleColumns: Array.from({ length: 10 }, (_, i) => ({ id: `c${i}`, label: String(i + 1) })),
|
|
301
|
-
scaleAnchorLabels:
|
|
310
|
+
scaleAnchorLabels: RATING_ANCHOR_LABELS,
|
|
302
311
|
});
|
|
303
312
|
|
|
304
313
|
export const FIXTURE_RATING_SLIDER = base({
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
--cfm-header-company-weight: 600;
|
|
26
26
|
--cfm-header-border: #e5e7eb;
|
|
27
27
|
--cfm-header-padding-x: 40px;
|
|
28
|
+
--cfm-header-padding-y: 12px;
|
|
29
|
+
--cfm-header-brand-row-display: none;
|
|
30
|
+
--cfm-header-logo-slot-display: flex;
|
|
31
|
+
--cfm-header-company-slot-display: flex;
|
|
28
32
|
--cfm-header-logo-col: 1;
|
|
29
33
|
--cfm-header-logo-justify: start;
|
|
30
34
|
--cfm-header-company-col: 1;
|
|
@@ -42,6 +46,8 @@
|
|
|
42
46
|
--cfm-footer-logo-height: 32px;
|
|
43
47
|
--cfm-footer-padding-y: 24px;
|
|
44
48
|
--cfm-footer-padding-x: 40px;
|
|
49
|
+
--cfm-footer-logo-copyright-gap: 12px;
|
|
50
|
+
--cfm-footer-inner-gap: 24px;
|
|
45
51
|
--cfm-footer-inner-display: grid;
|
|
46
52
|
--cfm-footer-inner-direction: row;
|
|
47
53
|
--cfm-footer-inner-align: end;
|
|
@@ -104,10 +110,16 @@
|
|
|
104
110
|
--cfm-csat-unselected-opacity: 0.5;
|
|
105
111
|
--cfm-csat-ring-color: var(--cfm-accent);
|
|
106
112
|
--cfm-csat-cell-size: 40px;
|
|
113
|
+
--cfm-csat-track: var(--cfm-accent);
|
|
114
|
+
--cfm-csat-thumb: var(--cfm-primary);
|
|
107
115
|
|
|
108
116
|
--cfm-star-color: #f59e0b;
|
|
109
117
|
--cfm-badge-color: var(--cfm-primary);
|
|
110
118
|
--cfm-star-unselected-opacity: 0.5;
|
|
119
|
+
--cfm-rating-column-label-color: #4b5563;
|
|
120
|
+
--cfm-rating-column-label-bg: transparent;
|
|
121
|
+
--cfm-rating-track: var(--cfm-accent);
|
|
122
|
+
--cfm-rating-thumb: var(--cfm-primary);
|
|
111
123
|
|
|
112
124
|
--cfm-slider-track: var(--cfm-accent);
|
|
113
125
|
--cfm-slider-thumb: var(--cfm-primary);
|
|
@@ -192,8 +204,8 @@ body {
|
|
|
192
204
|
gap: var(--cfm-header-brand-gap, 16px);
|
|
193
205
|
padding-left: var(--cfm-header-padding-x);
|
|
194
206
|
padding-right: var(--cfm-header-padding-x);
|
|
195
|
-
padding-top: 12px;
|
|
196
|
-
padding-bottom: 12px;
|
|
207
|
+
padding-top: var(--cfm-header-padding-y, 12px);
|
|
208
|
+
padding-bottom: var(--cfm-header-padding-y, 12px);
|
|
197
209
|
min-height: var(--cfm-header-height);
|
|
198
210
|
box-sizing: border-box;
|
|
199
211
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{u as x,j as e}from"./index-
|
|
1
|
+
import{u as x,j as e}from"./index-Blpq4QjK.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 R,S as C,R as d,C as i,N as t,a as z,M as A}from"./index-Blpq4QjK.js";import"./vendor-BwkXDkd3.js";function b({values:o,onPatch:r}){return e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Label text color",value:o.columnLabelColor,onChange:a=>r({columnLabelColor:a})}),e.jsx(i,{label:"Label background",value:o.columnLabelBgColor,onChange:a=>r({columnLabelBgColor:a})})]})}function k({values:o,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:o.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:o.hintMaxText,onChange:a=>r({hintMaxText:a.target.value})})]}),e.jsx(i,{label:"Hint text color",value:o.hintLabelColor,onChange:a=>r({hintLabelColor:a})}),e.jsx(i,{label:"Hint label background",value:o.hintLabelBgColor,onChange:a=>r({hintLabelBgColor:a})})]})}function j({values:o,onPatch:r,count:a=11}){return e.jsxs("div",{className:"space-y-3",children:[e.jsx(C,{label:"Number label style",value:o.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"}]}),o.numberLabelMode==="monochrome"&&e.jsx(i,{label:"Monochrome color",value:o.monochromeNumberColor,onChange:c=>r({monochromeNumberColor:c})}),o.numberLabelMode==="individual"&&e.jsx("div",{className:"grid grid-cols-2 gap-2 sm:grid-cols-3",children:Array.from({length:a},(c,u)=>e.jsx(i,{label:`#${u}`,value:o.individualNumberColors[u]??"#9CA3AF",onChange:v=>{const x=[...o.individualNumberColors];x[u]=v,r({individualNumberColors:x})}},u))})]})}function s({title:o,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:o}),r]})}function O({type:o,activeFormat:r}){const a=m(l=>l.config.questionTypes[o]),c=m(l=>l.updateQuestionType),u=m(l=>l.previewMultiStatementByType),v=m(l=>l.setPreviewMultiStatementForType),x=m(l=>l.heatmapPreviewPin);if(!a)return e.jsx("p",{className:"text-sm text-slate-500",children:"No configuration available for this type."});const n=l=>c(o,l),M=A.includes(o),y=!!u[o],h=r.includes("star"),g=r.includes("emoji"),S=r.includes("numbered"),N=r.includes("drag"),w=r.includes("dropdown"),f=r.includes("radio"),T=r.includes("graphics"),B=r==="CFM_bipolar",p=g||h||S||f,P=a.optionStyle??a.cardStyle??"outlined",L=a.buttonStyle??"numbered";return e.jsxs("div",{className:"space-y-4",children:[M&&e.jsx(R,{label:"Preview multiple statements",checked:y,onChange:l=>v(o,l)}),o==="MCQ"&&"optionGap"in a&&e.jsx(s,{title:"Option style",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(C,{label:"Option style",value:a.optionStyle??a.cardStyle??"outlined",onChange:l=>n({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=>n({optionGap:l}),min:0,max:32}),e.jsx(d,{label:"Border radius",value:a.borderRadius,onChange:l=>n({borderRadius:l}),min:0,max:24}),e.jsx(d,{label:"Option padding",value:a.optionPadding??12,onChange:l=>n({optionPadding:l}),min:4,max:24}),e.jsx(i,{label:"Hover border",value:a.hoverBorderColor,onChange:l=>n({hoverBorderColor:l})}),P==="filled"&&e.jsx(i,{label:"Unselected fill color",value:a.filledOptionBg??"#F9FAFB",onChange:l=>n({filledOptionBg:l})})]})}),o==="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=>n({defaultPlaceholder:l.target.value})})]}),e.jsx(t,{label:"Input radius (px)",value:a.inputRadius,onChange:l=>n({inputRadius:l}),min:0,max:24}),e.jsx(i,{label:"Border color",value:a.borderColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Placeholder color",value:a.placeholderColor,onChange:l=>n({placeholderColor:l})}),e.jsx(t,{label:"Input height (px)",value:a.inputHeight,onChange:l=>n({inputHeight:l}),min:32,max:64}),e.jsx(t,{label:"Input padding (px)",value:a.inputPadding,onChange:l=>n({inputPadding:l}),min:8,max:24})]})}),o==="NPS_SCALE"&&"buttonStyle"in a&&e.jsxs(e.Fragment,{children:[e.jsxs(s,{title:"NPS buttons",children:[e.jsx(C,{label:"Button style",value:a.buttonStyle,onChange:l=>n({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(k,{values:a,onPatch:n})}),L==="numbered"&&e.jsx(s,{title:"Number labels",children:e.jsx(j,{values:a,onPatch:n})}),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=>n({cellSize:l}),min:24,max:56}),e.jsx(t,{label:"Cell gap (px)",value:a.cellGap,onChange:l=>n({cellGap:l}),min:0,max:16}),e.jsx(i,{label:"Track bar",value:a.trackBarColor,onChange:l=>n({trackBarColor:l})}),e.jsx(i,{label:"Track highlight",value:a.trackHighlightColor,onChange:l=>n({trackHighlightColor:l})})]})})]}),o==="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=>n({rowLabelWidth:l}),min:120,max:280}),B&&e.jsx(t,{label:"Bipolar column width (%)",value:a.bipolarColumnWidthPercent,onChange:l=>n({bipolarColumnWidthPercent:l}),min:15,max:40}),e.jsx(t,{label:"Cell padding (px)",value:a.cellPadding,onChange:l=>n({cellPadding:l}),min:4,max:24})]})}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})})]}),o==="CSAT_MATRIX"&&"emojiSize"in a&&e.jsxs(e.Fragment,{children:[(g||p||h)&&e.jsxs(s,{title:`${z.CSAT_MATRIX} — ${r.replace("CSAT_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[g&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),h&&e.jsx(i,{label:"Star color",value:a.accentColor,onChange:l=>n({accentColor:l})}),p&&e.jsx(d,{label:"Unselected opacity",value:Math.round(a.unselectedOpacity*100),onChange:l=>n({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. Column labels appear above stars in the star format preview."})]}),T&&e.jsx(s,{title:"CSAT graphics track",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Track",value:a.trackColor,onChange:l=>n({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>n({thumbColor:l})})]})}),e.jsx(s,{title:"Label items",children:e.jsx(b,{values:a,onPatch:n})}),S&&e.jsx(s,{title:"Number labels",children:e.jsx(j,{values:a,onPatch:n,count:10})})]}),o==="RATING_MATRIX"&&"unselectedStarOpacity"in a&&e.jsxs(e.Fragment,{children:[(g||p||h)&&e.jsxs(s,{title:`Rating — ${r.replace("RATING_","")}`,children:[e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[g&&e.jsx(t,{label:"Emoji size (px)",value:a.emojiSize,onChange:l=>n({emojiSize:l}),min:16,max:40}),h&&e.jsx(i,{label:"Star color",value:a.starColor,onChange:l=>n({starColor:l})}),p&&e.jsx(d,{label:"Unselected opacity",value:Math.round(a.unselectedStarOpacity*100),onChange:l=>n({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."})]}),T&&e.jsx(s,{title:"Rating graphics track",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(i,{label:"Track",value:a.trackColor,onChange:l=>n({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>n({thumbColor:l})})]})}),e.jsxs(s,{title:"Label items",children:[e.jsx("p",{className:"text-xs text-slate-500",children:"Label items styles the anchor label pills (max 5), not column numbers."}),e.jsx(b,{values:a,onPatch:n})]}),S&&e.jsx(s,{title:"Number labels",children:e.jsx(j,{values:a,onPatch:n,count:10})})]}),o==="SLIDER_MATRIX"&&"tickColor"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=>n({trackColor:l})}),e.jsx(i,{label:"Thumb",value:a.thumbColor,onChange:l=>n({thumbColor:l})}),e.jsx(t,{label:"Row label width (px)",value:a.rowLabelWidth,onChange:l=>n({rowLabelWidth:l}),min:120,max:280}),e.jsx(i,{label:"Row band",value:a.rowBandColor,onChange:l=>n({rowBandColor:l})}),e.jsx(t,{label:"Tick badge size (px)",value:a.tickBadgeSize,onChange:l=>n({tickBadgeSize:l}),min:20,max:40})]})}),e.jsx(s,{title:"Anchor hint labels",children:e.jsx(k,{values:a,onPatch:n})}),e.jsx(s,{title:"Tick label items",children:e.jsx(b,{values:a,onPatch:n})}),e.jsx(s,{title:"Tick number labels",children:e.jsx(j,{values:a,onPatch:n,count:11})})]}),o==="FILE_UPLOAD"&&"dropzoneStyle"in a&&e.jsx(s,{title:"Dropzone",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[e.jsx(C,{label:"Dropzone border",value:a.dropzoneStyle,onChange:l=>n({dropzoneStyle:l}),options:[{value:"dashed",label:"Dashed"},{value:"solid",label:"Solid"}]}),e.jsx(i,{label:"Border color",value:a.borderColor??a.accentColor,onChange:l=>n({borderColor:l})}),e.jsx(i,{label:"Fill color",value:a.dropzoneFillColor,onChange:l=>n({dropzoneFillColor:l})}),e.jsx(t,{label:"Padding (px)",value:a.dropzonePadding,onChange:l=>n({dropzonePadding:l}),min:12,max:48})]})}),o==="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=>n({mediaMaxWidth:l}),min:50,max:100}),e.jsx(d,{label:"Media corner radius",value:a.mediaRadius,onChange:l=>n({mediaRadius:l}),min:0,max:24}),e.jsx(i,{label:"Caption color",value:a.captionColor,onChange:l=>n({captionColor:l})}),e.jsx(t,{label:"Caption size (px)",value:a.captionSize,onChange:l=>n({captionSize:l}),min:10,max:24})]})}),o==="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=>n({pinColor:l})}),e.jsx(i,{label:"Pin border",value:a.pinBorderColor,onChange:l=>n({pinBorderColor:l})}),e.jsx(d,{label:"Pin size",value:a.pinSize,onChange:l=>n({pinSize:l}),min:8,max:32}),e.jsx(d,{label:"Overlay opacity",value:Math.round(a.overlayOpacity*100),onChange:l=>n({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(x.x*100),"%, ",Math.round(x.y*100),"%"]})]})}),o==="RANK_ORDER"&&"drag"in a&&e.jsx(s,{title:N?"Drag & drop":w?"Dropdown rank":"Rank order",children:e.jsxs("div",{className:"grid grid-cols-2 gap-3",children:[N&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.drag.itemBg,onChange:l=>n({drag:{...a.drag,itemBg:l}})}),e.jsx(i,{label:"Drag handle",value:a.drag.dragHandleColor,onChange:l=>n({drag:{...a.drag,dragHandleColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.drag.rankBadgeColor,onChange:l=>n({drag:{...a.drag,rankBadgeColor:l}})})]}),w&&e.jsxs(e.Fragment,{children:[e.jsx(i,{label:"Item background",value:a.dropdown.itemBg,onChange:l=>n({dropdown:{...a.dropdown,itemBg:l}})}),e.jsx(i,{label:"List hover background",value:a.dropdown.itemHoverBg??"#F3F4F6",onChange:l=>n({dropdown:{...a.dropdown,itemHoverBg:l}})}),e.jsx(i,{label:"Select border",value:a.dropdown.selectBorderColor,onChange:l=>n({dropdown:{...a.dropdown,selectBorderColor:l}})}),e.jsx(i,{label:"Rank badge",value:a.dropdown.rankBadgeColor,onChange:l=>n({dropdown:{...a.dropdown,rankBadgeColor:l}})})]})]})})]})}export{O as TypePanel};
|