@explorer02/cfm-survey-sdk 0.2.9 → 0.3.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 +41 -38
- package/dist/cli/index.mjs +39 -36
- package/package.json +1 -1
- package/templates/docs/00-integration/agent-execution-flow.md +6 -6
- package/templates/docs/00-integration/agent-operating-contract.md +1 -2
- package/templates/docs/00-integration/client-lib-folder.md +1 -0
- package/templates/docs/00-integration/component-checklist.md +0 -1
- package/templates/docs/00-integration/ui-customization-wizard.md +38 -29
- package/templates/docs/00-integration/wizard-chrome-contract.md +3 -12
- package/templates/docs/00-integration/wizard-config-handoff.md +19 -11
- package/templates/docs/00-integration/wizard-post-customize-build.md +0 -6
- package/templates/docs/00-integration/wizard-preview-build-guide.md +17 -0
- package/templates/docs/00-integration/wizard-question-type-styling.md +3 -3
- package/templates/docs/00-integration/wizard-troubleshooting.md +4 -20
- package/templates/docs/01-components/03-rating-scale.md +8 -3
- package/templates/docs/02-reference/value-derivation.md +2 -0
- package/templates/docs/03-ui-specs/01-rating.md +15 -1
- package/templates/docs/index.md +1 -1
- package/templates/docs/templates/CsatMatrixScale.tsx +59 -53
- package/templates/docs/templates/CustomSliderTrack.tsx +8 -17
- package/templates/docs/templates/FileUploadScale.tsx +4 -12
- package/templates/docs/templates/Header.tsx +49 -32
- package/templates/docs/templates/HeatmapScale.tsx +2 -5
- package/templates/docs/templates/LikertMatrixScale.tsx +45 -57
- package/templates/docs/templates/MatrixDropdown.tsx +11 -12
- package/templates/docs/templates/Question.tsx +24 -4
- package/templates/docs/templates/RankOrderScale.tsx +9 -42
- package/templates/docs/templates/RatingScale.tsx +73 -75
- package/templates/docs/templates/SliderMatrixScale.tsx +3 -4
- package/templates/docs/templates/selectionStyles.ts +3 -2
- package/templates/docs/templates/surveyUiScaleUtils.ts +15 -1
- package/templates/docs/templates/verify-agent-build.sh +0 -17
- package/templates/preview-harness/preview-bridge.inline.js +61 -14
- package/templates/preview-harness/previewPages.js +84 -48
- package/templates/preview-harness/previewPages.ts +7 -5
- package/templates/preview-harness/vite-app/src/QuestionPreview.tsx +22 -14
- package/templates/preview-harness/vite-app/src/fixtures/questions.ts +13 -2
- package/templates/preview-harness/vite-app/src/preview-live-overrides.css +6 -11
- package/templates/previewBridge.ts +38 -5
- package/templates/survey-theme.css +17 -17
- package/templates/wizard-dist/assets/{PreviewMock-CysRws9G.js → PreviewMock-Bax7oRAL.js} +1 -1
- package/templates/wizard-dist/assets/{TypePanel-DWX1LL3q.js → TypePanel-D2t4FPSd.js} +1 -1
- package/templates/wizard-dist/assets/index-BhWM50Yu.css +1 -0
- package/templates/wizard-dist/assets/index-c5lka74l.js +34 -0
- package/templates/wizard-dist/index.html +2 -2
- package/templates/wizard-dist/assets/index-DIuc7AU2.js +0 -34
- package/templates/wizard-dist/assets/index-pCM8n0FT.css +0 -1
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
2
|
import type { CsatQuestion, RatingMatrixQuestion, MatrixRowAnswers, ScaleColumn } from '@explorer02/cfm-survey-sdk';
|
|
3
|
-
import {
|
|
3
|
+
import { getEmojiForIndex, CsatStarIcons } from './surveyUiIcons';
|
|
4
|
+
import { columnSubmitValue, nonNaScaleColumns } from './surveyUiScaleUtils';
|
|
5
|
+
import { CustomSliderTrack } from './CustomSliderTrack';
|
|
6
|
+
import MatrixDropdown from './MatrixDropdown';
|
|
4
7
|
import {
|
|
5
|
-
cellSelectedVar,
|
|
6
|
-
focusRingVar,
|
|
7
|
-
matrixRadioDotStyle,
|
|
8
8
|
matrixRadioRingStyle,
|
|
9
|
+
matrixRadioDotStyle,
|
|
9
10
|
scaleCellSelectedStyle,
|
|
10
|
-
emojiSizeStyle,
|
|
11
11
|
unselectedOpacityStyle,
|
|
12
|
+
emojiSizeStyle,
|
|
13
|
+
cellSelectedVar,
|
|
14
|
+
focusRingVar,
|
|
12
15
|
} from '@/lib/surveyUi/selectionStyles';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import MatrixDropdown from './MatrixDropdown';
|
|
16
|
+
import { csatColumnLabelStyle } from '@/lib/surveyUi/labelStyles';
|
|
17
|
+
|
|
18
|
+
const MATRIX_ROW_LABEL_WIDTH = 'var(--cfm-matrix-row-width, 180px)';
|
|
17
19
|
|
|
18
20
|
type CsatMatrixQuestion = CsatQuestion | RatingMatrixQuestion;
|
|
19
21
|
|
|
@@ -36,10 +38,10 @@ function GraphicsColumnLabelsRow({ scaleColumns }: { scaleColumns: ScaleColumn[]
|
|
|
36
38
|
textAlign: 'center',
|
|
37
39
|
fontSize: '12px',
|
|
38
40
|
fontWeight: 500,
|
|
41
|
+
color: '#4b5563',
|
|
39
42
|
lineHeight: 1.2,
|
|
40
43
|
wordBreak: 'break-word',
|
|
41
44
|
width: '64px',
|
|
42
|
-
...csatColumnLabelStyle(),
|
|
43
45
|
}}
|
|
44
46
|
>
|
|
45
47
|
<span dangerouslySetInnerHTML={{ __html: col.label }} />
|
|
@@ -104,10 +106,10 @@ function CsatMatrixVerticalList({
|
|
|
104
106
|
onClick={() => onCellSelect(row.id, submitValue)}
|
|
105
107
|
style={{
|
|
106
108
|
width: '100%', display: 'flex', alignItems: 'center', justifyContent: 'flex-start',
|
|
107
|
-
borderRadius: '8px', border: `1px solid ${isSelected ?
|
|
109
|
+
borderRadius: '8px', border: `1px solid ${isSelected ? '#e20074' : '#d1d5db'}`,
|
|
108
110
|
padding: '14px 18px', cursor: 'pointer', transition: 'all 0.15s',
|
|
109
|
-
backgroundColor: isSelected ? '
|
|
110
|
-
color: isSelected ?
|
|
111
|
+
backgroundColor: isSelected ? '#fdf2f8' : '#fff',
|
|
112
|
+
color: isSelected ? '#e20074' : '#374151',
|
|
111
113
|
fontWeight: isSelected ? 600 : 400, fontSize: '15px', textAlign: 'left',
|
|
112
114
|
}}
|
|
113
115
|
>
|
|
@@ -126,9 +128,9 @@ function CsatMatrixVerticalList({
|
|
|
126
128
|
key={col.id}
|
|
127
129
|
style={{
|
|
128
130
|
display: 'flex', alignItems: 'center', gap: '16px',
|
|
129
|
-
borderRadius: '8px', border: `1px solid ${isSelected ?
|
|
131
|
+
borderRadius: '8px', border: `1px solid ${isSelected ? '#e20074' : '#e5e5e5'}`,
|
|
130
132
|
padding: '16px 20px', cursor: 'pointer', transition: 'all 0.15s',
|
|
131
|
-
backgroundColor: isSelected ? '
|
|
133
|
+
backgroundColor: isSelected ? '#fdf2f8' : '#fff',
|
|
132
134
|
}}
|
|
133
135
|
>
|
|
134
136
|
<input type="radio" name={`${question.id}-${row.id}`}
|
|
@@ -136,8 +138,13 @@ function CsatMatrixVerticalList({
|
|
|
136
138
|
onChange={() => onCellSelect(row.id, submitValue)}
|
|
137
139
|
style={{ position: 'absolute', width: 0, height: 0, opacity: 0 }}
|
|
138
140
|
/>
|
|
139
|
-
<div style={
|
|
140
|
-
|
|
141
|
+
<div style={{
|
|
142
|
+
display: 'flex', width: '20px', height: '20px', flexShrink: 0,
|
|
143
|
+
alignItems: 'center', justifyContent: 'center', borderRadius: '50%',
|
|
144
|
+
border: isSelected ? '2px solid #e20074' : '1.5px solid #9ca3af',
|
|
145
|
+
backgroundColor: '#fff',
|
|
146
|
+
}}>
|
|
147
|
+
{isSelected && <div style={{ width: '10px', height: '10px', borderRadius: '50%', backgroundColor: '#e20074' }} />}
|
|
141
148
|
</div>
|
|
142
149
|
<span style={{ fontSize: '15px', fontWeight: 500, color: '#111827' }}
|
|
143
150
|
dangerouslySetInnerHTML={{ __html: col.label }} />
|
|
@@ -151,7 +158,7 @@ function CsatMatrixVerticalList({
|
|
|
151
158
|
<label style={{ display: 'flex', alignItems: 'center', gap: '12px', cursor: 'pointer', userSelect: 'none' }}>
|
|
152
159
|
<input type="checkbox" checked={selectedValue[row.id] === null}
|
|
153
160
|
onChange={() => onCellSelect(row.id, selectedValue[row.id] === null ? undefined : null)}
|
|
154
|
-
style={{ width: '16px', height: '16px', accentColor:
|
|
161
|
+
style={{ width: '16px', height: '16px', accentColor: '#e20074', cursor: 'pointer' }} />
|
|
155
162
|
<span style={{ fontSize: '14px', fontWeight: 500, color: '#4b5563' }}>Not Applicable</span>
|
|
156
163
|
</label>
|
|
157
164
|
)}
|
|
@@ -195,7 +202,7 @@ function CsatMatrixGrid({
|
|
|
195
202
|
{/* Labels row */}
|
|
196
203
|
{showLabels && m > 0 && (
|
|
197
204
|
<div style={{ display: 'flex', alignItems: 'flex-end', marginBottom: '12px' }}>
|
|
198
|
-
<div style={{ width:
|
|
205
|
+
<div style={{ width: MATRIX_ROW_LABEL_WIDTH, flexShrink: 0 }} />
|
|
199
206
|
<div style={{ flex: 1, display: 'flex' }}>
|
|
200
207
|
<div style={{ flex: 1, position: 'relative', height: '24px', ...(isGraphics ? { margin: '0 40px' } : {}) }}>
|
|
201
208
|
{labels!.map((label, i) => {
|
|
@@ -209,8 +216,7 @@ function CsatMatrixGrid({
|
|
|
209
216
|
left: `${percent}%`,
|
|
210
217
|
transform: 'translateX(-50%)',
|
|
211
218
|
textAlign: 'center', fontSize: '13px', fontWeight: 600,
|
|
212
|
-
lineHeight: 1.3, whiteSpace: 'nowrap'
|
|
213
|
-
...csatColumnLabelStyle(),
|
|
219
|
+
color: '#4b5563', lineHeight: 1.3, whiteSpace: 'nowrap'
|
|
214
220
|
}}>
|
|
215
221
|
{label}
|
|
216
222
|
</div>
|
|
@@ -225,7 +231,7 @@ function CsatMatrixGrid({
|
|
|
225
231
|
{/* Column tick labels for graphics sliders (shown with or without anchor labels) */}
|
|
226
232
|
{isGraphics && m > 0 && (
|
|
227
233
|
<div style={{ display: 'flex', alignItems: 'flex-end', marginBottom: showLabels ? '8px' : '16px', minHeight: '24px' }}>
|
|
228
|
-
<div style={{ width:
|
|
234
|
+
<div style={{ width: MATRIX_ROW_LABEL_WIDTH, flexShrink: 0 }} />
|
|
229
235
|
<div style={{ flex: 1, display: 'flex' }}>
|
|
230
236
|
<GraphicsColumnLabelsRow scaleColumns={scaleColumns} />
|
|
231
237
|
{hasNotApplicable && (
|
|
@@ -238,7 +244,7 @@ function CsatMatrixGrid({
|
|
|
238
244
|
{/* Column Headers for non-graphics */}
|
|
239
245
|
{!isGraphics && !showLabels && m > 0 && (
|
|
240
246
|
<div style={{ display: 'flex', alignItems: 'flex-end', marginBottom: '16px', minHeight: '24px' }}>
|
|
241
|
-
<div style={{ width:
|
|
247
|
+
<div style={{ width: MATRIX_ROW_LABEL_WIDTH, flexShrink: 0 }} />
|
|
242
248
|
<div style={{ flex: 1, display: 'flex' }}>
|
|
243
249
|
<div style={{ flex: 1, display: 'grid', gridTemplateColumns: `repeat(${scaleColumns.length}, 1fr)` }}>
|
|
244
250
|
{scaleColumns.map(col => (
|
|
@@ -264,9 +270,9 @@ function CsatMatrixGrid({
|
|
|
264
270
|
{statementRows.map((row, rowIdx) => (
|
|
265
271
|
<div key={row.id} style={{
|
|
266
272
|
display: 'flex', alignItems: 'center', borderRadius: '8px',
|
|
267
|
-
padding: '12px 0', backgroundColor: rowIdx % 2 === 0 ? '
|
|
273
|
+
padding: '12px 0', backgroundColor: rowIdx % 2 === 0 ? 'rgba(249, 250, 251, 0.8)' : '#fff',
|
|
268
274
|
}}>
|
|
269
|
-
<div style={{ width:
|
|
275
|
+
<div style={{ width: MATRIX_ROW_LABEL_WIDTH, flexShrink: 0, padding: '0 16px' }}>
|
|
270
276
|
<span style={{ fontSize: '14px', fontWeight: 500, color: '#111827', lineHeight: 1.4 }}
|
|
271
277
|
dangerouslySetInnerHTML={{ __html: row.statementText }} />
|
|
272
278
|
</div>
|
|
@@ -305,7 +311,7 @@ function CsatMatrixGrid({
|
|
|
305
311
|
|
|
306
312
|
const RadioNode = (
|
|
307
313
|
<div style={matrixRadioRingStyle(isSelected)}>
|
|
308
|
-
|
|
314
|
+
<div style={matrixRadioDotStyle(isSelected)} />
|
|
309
315
|
</div>
|
|
310
316
|
);
|
|
311
317
|
|
|
@@ -328,23 +334,22 @@ function CsatMatrixGrid({
|
|
|
328
334
|
...emojiSizeStyle(),
|
|
329
335
|
transform: isSelected ? 'scale(1.1)' : isHovered ? 'scale(1.25)' : 'scale(1)',
|
|
330
336
|
...(isSelected ? {
|
|
331
|
-
|
|
332
|
-
|
|
337
|
+
outline: `2px solid ${focusRingVar}`,
|
|
338
|
+
backgroundColor: cellSelectedVar,
|
|
333
339
|
borderRadius: '50%',
|
|
334
|
-
} :
|
|
340
|
+
} : unselectedOpacityStyle()),
|
|
335
341
|
} : isStar ? {
|
|
336
342
|
padding: '4px',
|
|
337
343
|
transform: isHovered ? 'scale(1.1)' : 'scale(1)',
|
|
344
|
+
color: isSelected ? cellSelectedVar : focusRingVar,
|
|
338
345
|
...(isSelected ? {} : unselectedOpacityStyle()),
|
|
339
|
-
opacity: isSelected ? 1 : isHovered ? 1 : undefined,
|
|
340
346
|
} : isNumbered ? {
|
|
341
|
-
width: '
|
|
347
|
+
width: '40px', height: '40px', borderRadius: '8px',
|
|
342
348
|
fontSize: '14px', fontWeight: 500,
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
349
|
+
...(isSelected
|
|
350
|
+
? scaleCellSelectedStyle(true)
|
|
351
|
+
: { border: '1px solid #d1d5db', backgroundColor: '#fff', color: '#111827' }),
|
|
346
352
|
transition: 'all 0.15s',
|
|
347
|
-
...(isSelected ? scaleCellSelectedStyle(true) : {}),
|
|
348
353
|
} : { padding: '8px' }),
|
|
349
354
|
}}
|
|
350
355
|
>
|
|
@@ -382,7 +387,7 @@ function CsatMatrixGrid({
|
|
|
382
387
|
<label style={{ cursor: 'pointer' }}>
|
|
383
388
|
<input type="checkbox" checked={selectedValue[row.id] === null}
|
|
384
389
|
onChange={() => onCellSelect(row.id, selectedValue[row.id] === null ? undefined : null)}
|
|
385
|
-
style={{ width: '16px', height: '16px', accentColor:
|
|
390
|
+
style={{ width: '16px', height: '16px', accentColor: '#e20074', cursor: 'pointer' }} />
|
|
386
391
|
</label>
|
|
387
392
|
</div>
|
|
388
393
|
)}
|
|
@@ -441,8 +446,7 @@ function CsatMatrixCarousel({
|
|
|
441
446
|
<div key={i} style={{
|
|
442
447
|
position: 'absolute', left: `${percent}%`, transform: 'translateX(-50%)',
|
|
443
448
|
textAlign: 'center', fontSize: '13px', fontWeight: 600,
|
|
444
|
-
lineHeight: 1.3, whiteSpace: 'nowrap'
|
|
445
|
-
...csatColumnLabelStyle(),
|
|
449
|
+
color: '#4b5563', lineHeight: 1.3, whiteSpace: 'nowrap'
|
|
446
450
|
}}>
|
|
447
451
|
{label}
|
|
448
452
|
</div>
|
|
@@ -486,8 +490,13 @@ function CsatMatrixCarousel({
|
|
|
486
490
|
const EmojiNode = isEmoji ? getEmojiForIndex(displayIdx, scaleColumns.length) : null;
|
|
487
491
|
const StarNode = isStar ? (isSelected ? (CsatStarIcons.filled as any) : (CsatStarIcons.empty as any)) : null;
|
|
488
492
|
const RadioNode = (
|
|
489
|
-
<div style={
|
|
490
|
-
|
|
493
|
+
<div style={{
|
|
494
|
+
display: 'flex', width: '18px', height: '18px',
|
|
495
|
+
alignItems: 'center', justifyContent: 'center', borderRadius: '50%',
|
|
496
|
+
margin: '0 auto', border: isSelected ? '2px solid #e20074' : '2px solid #d1d5db',
|
|
497
|
+
backgroundColor: '#fff',
|
|
498
|
+
}}>
|
|
499
|
+
{isSelected && <div style={{ width: '8px', height: '8px', borderRadius: '50%', backgroundColor: '#e20074' }} />}
|
|
491
500
|
</div>
|
|
492
501
|
);
|
|
493
502
|
|
|
@@ -503,23 +512,19 @@ function CsatMatrixCarousel({
|
|
|
503
512
|
transition: 'all 0.15s', border: 'none', backgroundColor: 'transparent',
|
|
504
513
|
cursor: 'pointer', borderRadius: '6px', pointerEvents: 'none',
|
|
505
514
|
...(isEmoji ? {
|
|
506
|
-
padding: '6px',
|
|
507
|
-
|
|
508
|
-
...(isSelected ? { backgroundColor: 'var(--cfm-mcq-selected-bg)', boxShadow: `0 0 0 2px ${focusRingVar}`, borderRadius: '50%' } : {}),
|
|
515
|
+
padding: '6px', transform: isSelected ? 'scale(1.1)' : isHovered ? 'scale(1.25)' : 'scale(1)',
|
|
516
|
+
...(isSelected ? { backgroundColor: 'rgba(252, 231, 243, 0.6)', boxShadow: '0 0 0 2px rgba(226, 0, 116, 0.3)', borderRadius: '50%' } : {}),
|
|
509
517
|
} : isStar ? {
|
|
510
|
-
padding: '4px', transform: isHovered ? 'scale(1.1)' : 'scale(1)',
|
|
511
|
-
...(isSelected ? {} : unselectedOpacityStyle()),
|
|
512
|
-
opacity: isSelected ? 1 : isHovered ? 1 : undefined,
|
|
518
|
+
padding: '4px', transform: isHovered ? 'scale(1.1)' : 'scale(1)', opacity: isSelected ? 1 : isHovered ? 1 : 0.5,
|
|
513
519
|
} : isNumbered ? {
|
|
514
|
-
width: '
|
|
515
|
-
border: `1px solid ${isSelected ?
|
|
516
|
-
...(isSelected ? scaleCellSelectedStyle(true) : {}),
|
|
520
|
+
width: '40px', height: '40px', borderRadius: '8px', fontSize: '14px', fontWeight: 500,
|
|
521
|
+
border: `1px solid ${isSelected ? '#e20074' : '#d1d5db'}`, backgroundColor: isSelected ? '#e20074' : '#fff', color: isSelected ? '#fff' : '#111827',
|
|
517
522
|
} : { padding: '8px' }),
|
|
518
523
|
}}
|
|
519
524
|
>
|
|
520
525
|
{(EmojiNode ?? StarNode ?? (isNumbered ? (displayIdx + 1) : RadioNode)) as React.ReactNode}
|
|
521
526
|
</button>
|
|
522
|
-
<span style={{ fontSize: '13px', fontWeight: 500, textAlign: 'center', lineHeight: 1.2
|
|
527
|
+
<span style={{ fontSize: '13px', fontWeight: 500, color: '#4b5563', textAlign: 'center', lineHeight: 1.2 }}
|
|
523
528
|
dangerouslySetInnerHTML={{ __html: col.label }} />
|
|
524
529
|
</div>
|
|
525
530
|
);
|
|
@@ -532,7 +537,7 @@ function CsatMatrixCarousel({
|
|
|
532
537
|
<label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
|
|
533
538
|
<input type="checkbox" checked={selectedValue[row.id] === null}
|
|
534
539
|
onChange={() => onCellSelect(row.id, selectedValue[row.id] === null ? undefined : null)}
|
|
535
|
-
style={{ width: '16px', height: '16px', accentColor:
|
|
540
|
+
style={{ width: '16px', height: '16px', accentColor: '#e20074', cursor: 'pointer' }} />
|
|
536
541
|
<span style={{ fontSize: '14px', fontWeight: 500, color: '#4b5563' }}>N/A</span>
|
|
537
542
|
</label>
|
|
538
543
|
</div>
|
|
@@ -554,7 +559,7 @@ function CsatMatrixCarousel({
|
|
|
554
559
|
<button key={i} type="button" onClick={() => setActiveCarouselIndex(i)}
|
|
555
560
|
style={{
|
|
556
561
|
width: i === activeCarouselIndex ? '20px' : '8px', height: '8px', borderRadius: '4px',
|
|
557
|
-
backgroundColor: i === activeCarouselIndex ?
|
|
562
|
+
backgroundColor: i === activeCarouselIndex ? '#e20074' : '#d1d5db', border: 'none', padding: 0,
|
|
558
563
|
cursor: 'pointer', transition: 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'
|
|
559
564
|
}} />
|
|
560
565
|
))}
|
|
@@ -594,6 +599,7 @@ export function CsatMatrixScale({ question, selectedValue = {}, onSelect }: Csat
|
|
|
594
599
|
const isStar = displayStyle === 'star';
|
|
595
600
|
const isNumbered = displayStyle === 'numbered';
|
|
596
601
|
const isGraphics = displayStyle === 'graphics';
|
|
602
|
+
const isStandardRadio = displayStyle === 'standard';
|
|
597
603
|
|
|
598
604
|
const scaleColumns = nonNaScaleColumns(question.scaleColumns);
|
|
599
605
|
|
|
@@ -612,7 +618,7 @@ export function CsatMatrixScale({ question, selectedValue = {}, onSelect }: Csat
|
|
|
612
618
|
);
|
|
613
619
|
}
|
|
614
620
|
|
|
615
|
-
if (isDropdown || isSelectBox) {
|
|
621
|
+
if (isDropdown || isSelectBox || (isStandardRadio && question.type !== 'RATING_MATRIX')) {
|
|
616
622
|
return (
|
|
617
623
|
<CsatMatrixVerticalList
|
|
618
624
|
question={question}
|
|
@@ -7,7 +7,6 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import React from 'react';
|
|
10
|
-
import { focusRingVar, cellSelectedVar } from '@/lib/surveyUi/selectionStyles';
|
|
11
10
|
import { getEmojiForIndex } from './surveyUiIcons';
|
|
12
11
|
|
|
13
12
|
type CustomSliderTrackProps = {
|
|
@@ -51,8 +50,7 @@ export function CustomSliderTrack({
|
|
|
51
50
|
? tooltipLabel.replace(/<[^>]*>/g, '')
|
|
52
51
|
: String(Math.round(value));
|
|
53
52
|
|
|
54
|
-
const
|
|
55
|
-
const thumbBorderColor = disabled ? 'var(--cfm-slider-tick, #9ca3af)' : focusRingVar;
|
|
53
|
+
const themeColor = disabled ? '#9ca3af' : 'var(--cfm-input-focus-ring, var(--cfm-primary))';
|
|
56
54
|
|
|
57
55
|
return (
|
|
58
56
|
<div
|
|
@@ -62,12 +60,12 @@ export function CustomSliderTrack({
|
|
|
62
60
|
>
|
|
63
61
|
<div style={{
|
|
64
62
|
position: 'absolute', top: '50%', left: 0, right: 0, transform: 'translateY(-50%)',
|
|
65
|
-
height: '4px', borderRadius: '2px', backgroundColor: 'var(--cfm-slider-
|
|
63
|
+
height: '4px', borderRadius: '2px', backgroundColor: 'var(--cfm-slider-track, #e5e7eb)',
|
|
66
64
|
}} />
|
|
67
65
|
|
|
68
66
|
<div style={{
|
|
69
67
|
position: 'absolute', top: '50%', left: 0, width: `${percentage}%`, transform: 'translateY(-50%)',
|
|
70
|
-
height: '4px', borderRadius: '2px', backgroundColor:
|
|
68
|
+
height: '4px', borderRadius: '2px', backgroundColor: themeColor,
|
|
71
69
|
transition: isDragging ? 'none' : 'width 0.15s ease-in-out',
|
|
72
70
|
}} />
|
|
73
71
|
|
|
@@ -78,7 +76,7 @@ export function CustomSliderTrack({
|
|
|
78
76
|
key={idx}
|
|
79
77
|
style={{
|
|
80
78
|
position: 'absolute', top: '50%', left: `${tickPct}%`, transform: 'translate(-50%, -50%)',
|
|
81
|
-
width: '1px', height: '8px', backgroundColor: '
|
|
79
|
+
width: '1px', height: '8px', backgroundColor: '#d1d5db', pointerEvents: 'none',
|
|
82
80
|
}}
|
|
83
81
|
/>
|
|
84
82
|
);
|
|
@@ -115,22 +113,15 @@ export function CustomSliderTrack({
|
|
|
115
113
|
) : (
|
|
116
114
|
<div style={{
|
|
117
115
|
position: 'absolute', top: '50%', left: `${percentage}%`, transform: 'translate(-50%, -50%)',
|
|
118
|
-
width: '18px', height: '18px', borderRadius: '50%',
|
|
119
|
-
border: `2.5px solid ${
|
|
120
|
-
backgroundColor: cellSelectedVar,
|
|
121
|
-
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
116
|
+
width: '18px', height: '18px', borderRadius: '50%', backgroundColor: '#ffffff',
|
|
117
|
+
border: `2.5px solid ${themeColor}`,
|
|
122
118
|
boxShadow: (isHovered || isDragging) && !disabled
|
|
123
|
-
? '0 0 0 6px
|
|
119
|
+
? '0 0 0 6px rgba(226, 0, 116, 0.2), 0 1px 3px rgba(0,0,0,0.2)'
|
|
124
120
|
: '0 1px 3px rgba(0,0,0,0.2)',
|
|
125
121
|
pointerEvents: 'none',
|
|
126
122
|
transition: isDragging ? 'none' : 'left 0.15s ease-in-out, box-shadow 0.15s, border-color 0.2s',
|
|
127
123
|
boxSizing: 'border-box',
|
|
128
|
-
}}
|
|
129
|
-
<div style={{
|
|
130
|
-
width: '33%', height: '33%', borderRadius: '50%',
|
|
131
|
-
backgroundColor: 'var(--cfm-slider-thumb, var(--cfm-primary))',
|
|
132
|
-
}} />
|
|
133
|
-
</div>
|
|
124
|
+
}} />
|
|
134
125
|
)}
|
|
135
126
|
|
|
136
127
|
{(isHovered || isDragging) && !disabled && (
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
import React, { useState, useRef } from 'react';
|
|
10
10
|
import type { FileUploadQuestion } from '@explorer02/cfm-survey-sdk';
|
|
11
|
-
import { focusRingVar } from '@/lib/surveyUi/selectionStyles';
|
|
12
11
|
|
|
13
12
|
type UploadedFileAnswer = {
|
|
14
13
|
id: string;
|
|
@@ -87,15 +86,8 @@ function FileUploadDropzone({
|
|
|
87
86
|
onDrag: (e: React.DragEvent) => void;
|
|
88
87
|
onDrop: (e: React.DragEvent) => void;
|
|
89
88
|
}) {
|
|
90
|
-
const dropzoneStyleAttr =
|
|
91
|
-
typeof document !== 'undefined'
|
|
92
|
-
? document.documentElement.getAttribute('data-cfm-dropzone-style') ?? undefined
|
|
93
|
-
: undefined;
|
|
94
|
-
|
|
95
89
|
return (
|
|
96
90
|
<div
|
|
97
|
-
className="cfm-dropzone"
|
|
98
|
-
{...(dropzoneStyleAttr ? { 'data-cfm-dropzone-style': dropzoneStyleAttr } : {})}
|
|
99
91
|
onDragEnter={onDrag}
|
|
100
92
|
onDragOver={onDrag}
|
|
101
93
|
onDragLeave={onDrag}
|
|
@@ -106,10 +98,10 @@ function FileUploadDropzone({
|
|
|
106
98
|
flexDirection: 'column',
|
|
107
99
|
alignItems: 'center',
|
|
108
100
|
justifyContent: 'center',
|
|
109
|
-
border: `2px var(--cfm-upload-border-style, dashed)
|
|
110
|
-
borderRadius: '12px',
|
|
111
|
-
backgroundColor: isDragActive ? 'var(--cfm-mcq-selected-bg)' : 'var(--cfm-upload-fill)',
|
|
112
|
-
padding: 'var(--cfm-upload-padding)',
|
|
101
|
+
border: `2px ${isDragActive ? 'solid' : 'var(--cfm-upload-border-style, dashed)'} var(--cfm-upload-border-color, #d1d5db)`,
|
|
102
|
+
borderRadius: 'var(--cfm-border-radius, 12px)',
|
|
103
|
+
backgroundColor: isDragActive ? 'var(--cfm-mcq-selected-bg, #fdf2f8)' : 'var(--cfm-upload-fill, #f9fafb)',
|
|
104
|
+
padding: 'var(--cfm-upload-padding, 40px 24px)',
|
|
113
105
|
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
114
106
|
opacity: disabled ? 0.6 : 1,
|
|
115
107
|
textAlign: 'center',
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Wizard-ready Header — copy to src/components/Header.tsx
|
|
3
3
|
*
|
|
4
4
|
* Brand row: [logo image] [company name] — company sits after logo when both exist.
|
|
5
|
-
*
|
|
5
|
+
* When no logo file: text fallback via data-cfm-logo-text (company name or empty).
|
|
6
6
|
*
|
|
7
7
|
* After wizard save, logo src MUST come from survey-ui-config.json global.logo.fileName
|
|
8
8
|
* via uiConfig.ts — never hardcode telekom-logo.svg or change fileName manually.
|
|
@@ -33,30 +33,43 @@ export default function Header({ embedded = false }: HeaderProps) {
|
|
|
33
33
|
}}
|
|
34
34
|
>
|
|
35
35
|
<div
|
|
36
|
-
className="cfm-header-inner
|
|
36
|
+
className="cfm-header-inner grid h-full w-full items-center"
|
|
37
37
|
style={{
|
|
38
|
+
gridTemplateColumns: '1fr 1fr 1fr',
|
|
38
39
|
padding: `0 var(--cfm-header-padding-x, 40px)`,
|
|
39
40
|
}}
|
|
40
41
|
>
|
|
41
42
|
<div
|
|
42
|
-
className="cfm-header-brand flex
|
|
43
|
+
className="cfm-header-brand flex items-center"
|
|
43
44
|
style={{
|
|
45
|
+
gridColumn: 'var(--cfm-header-logo-col, 1)',
|
|
46
|
+
justifySelf: 'var(--cfm-header-logo-justify, start)',
|
|
44
47
|
gap: 'var(--cfm-header-brand-gap, 16px)',
|
|
45
48
|
}}
|
|
46
49
|
>
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
50
|
+
{hasLogoFile ? (
|
|
51
|
+
<img
|
|
52
|
+
data-cfm-logo
|
|
53
|
+
src={seedLogoSrc!}
|
|
54
|
+
alt={seedCompany || 'Logo'}
|
|
55
|
+
className="shrink-0 object-contain"
|
|
56
|
+
style={{
|
|
57
|
+
width: 'var(--cfm-header-logo-width, 120px)',
|
|
58
|
+
height: 'var(--cfm-header-logo-height, 120px)',
|
|
59
|
+
maxHeight: 'calc(var(--cfm-header-height, 120px) - 8px)',
|
|
60
|
+
padding: 'var(--cfm-header-logo-padding, 10px)',
|
|
61
|
+
background: 'transparent',
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
) : (
|
|
65
|
+
<img
|
|
66
|
+
data-cfm-logo
|
|
67
|
+
src=""
|
|
68
|
+
alt="Logo"
|
|
69
|
+
className="shrink-0 object-contain"
|
|
70
|
+
style={{ display: 'none' }}
|
|
71
|
+
/>
|
|
72
|
+
)}
|
|
60
73
|
|
|
61
74
|
<span
|
|
62
75
|
data-cfm-logo-text
|
|
@@ -71,22 +84,26 @@ export default function Header({ embedded = false }: HeaderProps) {
|
|
|
71
84
|
{seedCompany}
|
|
72
85
|
</span>
|
|
73
86
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
<span
|
|
88
|
+
data-cfm-company
|
|
89
|
+
className="font-semibold"
|
|
90
|
+
style={{
|
|
91
|
+
display:
|
|
92
|
+
seedShowCompany && (hasLogoFile || seedCompany)
|
|
93
|
+
? hasLogoFile
|
|
94
|
+
? ''
|
|
95
|
+
: 'none'
|
|
96
|
+
: 'none',
|
|
97
|
+
marginTop: 'var(--cfm-header-company-margin-top, 0)',
|
|
98
|
+
marginLeft: 'var(--cfm-header-company-margin-left, 0)',
|
|
99
|
+
marginRight: 'var(--cfm-header-company-margin-right, 0)',
|
|
100
|
+
color: 'var(--cfm-header-company-color, var(--cfm-text))',
|
|
101
|
+
fontSize: 'var(--cfm-header-company-size, 18px)',
|
|
102
|
+
fontWeight: 'var(--cfm-header-company-weight, 600)',
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
{seedCompany}
|
|
106
|
+
</span>
|
|
90
107
|
</div>
|
|
91
108
|
</div>
|
|
92
109
|
</header>
|
|
@@ -29,8 +29,8 @@ function HeatmapSpot({ spot }: { spot: { id: string; x: number; y: number } }) {
|
|
|
29
29
|
width: 'var(--cfm-heatmap-pin-size, 16px)',
|
|
30
30
|
height: 'var(--cfm-heatmap-pin-size, 16px)',
|
|
31
31
|
transform: 'translate(-50%, -50%)',
|
|
32
|
-
backgroundColor: 'var(--cfm-heatmap-pin)',
|
|
33
|
-
border: '2px solid var(--cfm-heatmap-pin-border,
|
|
32
|
+
backgroundColor: 'var(--cfm-heatmap-pin, #F97316)',
|
|
33
|
+
border: '2px solid var(--cfm-heatmap-pin-border, #fff)',
|
|
34
34
|
boxShadow: '0 1px 3px rgba(0,0,0,0.25)',
|
|
35
35
|
}}
|
|
36
36
|
/>
|
|
@@ -63,9 +63,6 @@ export function HeatmapScale({ question, selectedValue = [], onSelect }: Heatmap
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
onSelect([...spots, createNewSpot(x, y)]);
|
|
66
|
-
if (typeof window !== 'undefined' && window.parent !== window) {
|
|
67
|
-
window.parent.postMessage({ type: 'CFM_HEATMAP_PIN', pin: { x, y } }, '*');
|
|
68
|
-
}
|
|
69
66
|
}
|
|
70
67
|
|
|
71
68
|
function handleImageLoad() {
|