@explorer02/cfm-survey-sdk 0.2.2 → 0.2.3
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/package.json +1 -1
- package/templates/AGENT.md +8 -4
- package/templates/docs/00-integration/analytics-events-catalog.md +54 -0
- package/templates/docs/00-integration/client-integration-guide.md +1 -1
- package/templates/docs/00-integration/component-checklist.md +10 -0
- package/templates/docs/00-integration/display-logic-and-navigation.md +16 -1
- package/templates/docs/00-integration/file-upload-aws.md +116 -0
- package/templates/docs/00-integration/logic-fields-catalog.md +105 -0
- package/templates/docs/00-integration/partial-save-and-recovery.md +24 -0
- package/templates/docs/00-integration/question-type-sdk-matrix.md +11 -9
- package/templates/docs/00-integration/setup.md +3 -3
- package/templates/docs/00-integration/skip-logic-and-navigation.md +1 -1
- package/templates/docs/00-integration/survey-lifecycle-analytics.md +1 -1
- package/templates/docs/01-components/06-likert-matrix-scale.md +2 -1
- package/templates/docs/01-components/08-file-upload-scale.md +15 -52
- package/templates/docs/01-components/13-matrix-dropdown.md +28 -33
- package/templates/docs/01-components/17-heatmap-scale.md +4 -4
- package/templates/docs/01-components/18-rank-order-scale.md +24 -31
- package/templates/docs/02-reference/question-types/11-file-upload.md +36 -21
- package/templates/docs/02-reference/question-types/README.md +11 -1
- package/templates/docs/03-ui-specs/01-rating.md +10 -2
- package/templates/docs/03-ui-specs/02-radio.md +80 -25
- package/templates/docs/03-ui-specs/04-csat.md +35 -5
- package/templates/docs/03-ui-specs/07-matrix-cfm.md +20 -4
- package/templates/docs/03-ui-specs/08-matrix-csat-rating.md +5 -1
- package/templates/docs/03-ui-specs/09-slider-matrix.md +17 -0
- package/templates/docs/03-ui-specs/10-file-upload.md +41 -20
- package/templates/docs/03-ui-specs/12-survey-chrome.md +38 -0
- package/templates/docs/03-ui-specs/13-heatmap.md +9 -2
- package/templates/docs/03-ui-specs/14-rank-order.md +98 -29
- package/templates/docs/03-ui-specs/README.md +7 -5
- package/templates/docs/03-ui-specs/shared/custom-slider-track.md +28 -35
- package/templates/docs/MANIFEST.json +28 -3
- package/templates/docs/index.md +5 -4
- package/templates/docs/templates/CustomSliderTrack.tsx +144 -0
- package/templates/docs/templates/MatrixDropdown.tsx +216 -0
- package/templates/docs/templates/RankOrderScale.tsx +353 -0
- package/templates/docs/templates/implementation_plan.md +20 -0
- package/templates/docs/templates/survey-inventory.schema.json +28 -23
- package/templates/docs/templates/surveyUiIcons.tsx +52 -0
- package/templates/docs/templates/verify-agent-build.sh +32 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Portable CustomSliderTrack template — copy to src/components/CustomSliderTrack.tsx
|
|
5
|
+
* Also copy surveyUiIcons.tsx to the same folder (or src/lib/surveyUiIcons.tsx)
|
|
6
|
+
* Pass tickLabels from scaleColumns[].label for matrix scale label rendering (Day 19 fix)
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React from 'react';
|
|
10
|
+
import { getEmojiForIndex } from './surveyUiIcons';
|
|
11
|
+
|
|
12
|
+
type CustomSliderTrackProps = {
|
|
13
|
+
min: number;
|
|
14
|
+
max: number;
|
|
15
|
+
htmlStep: number;
|
|
16
|
+
value: number;
|
|
17
|
+
disabled: boolean;
|
|
18
|
+
displayValues?: boolean;
|
|
19
|
+
hasSelectedValue: boolean;
|
|
20
|
+
sliderType?: 'graphics';
|
|
21
|
+
ticks?: number;
|
|
22
|
+
/** Pass scaleColumns.map(c => c.label) for visible column labels under slider */
|
|
23
|
+
tickLabels?: string[];
|
|
24
|
+
reverseScaleOrder?: boolean;
|
|
25
|
+
onChange: (v: number) => void;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export function CustomSliderTrack({
|
|
29
|
+
min,
|
|
30
|
+
max,
|
|
31
|
+
htmlStep,
|
|
32
|
+
value,
|
|
33
|
+
disabled,
|
|
34
|
+
sliderType,
|
|
35
|
+
ticks,
|
|
36
|
+
tickLabels,
|
|
37
|
+
reverseScaleOrder,
|
|
38
|
+
onChange,
|
|
39
|
+
}: CustomSliderTrackProps) {
|
|
40
|
+
const [isHovered, setIsHovered] = React.useState(false);
|
|
41
|
+
const [isDragging, setIsDragging] = React.useState(false);
|
|
42
|
+
|
|
43
|
+
const percentage = ((value - min) / (max - min)) * 100;
|
|
44
|
+
const tickIndex = Math.min(
|
|
45
|
+
Math.max(0, Math.round(value)),
|
|
46
|
+
tickLabels && tickLabels.length > 0 ? tickLabels.length - 1 : Math.round(value)
|
|
47
|
+
);
|
|
48
|
+
const tooltipLabel = tickLabels?.[tickIndex];
|
|
49
|
+
const tooltipText = tooltipLabel
|
|
50
|
+
? tooltipLabel.replace(/<[^>]*>/g, '')
|
|
51
|
+
: String(Math.round(value));
|
|
52
|
+
|
|
53
|
+
const themeColor = disabled ? '#9ca3af' : '#e20074';
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<div
|
|
57
|
+
style={{ position: 'relative', height: '32px', display: 'flex', alignItems: 'center', margin: '0 16px', opacity: disabled ? 0.5 : 1 }}
|
|
58
|
+
onMouseEnter={() => !disabled && setIsHovered(true)}
|
|
59
|
+
onMouseLeave={() => { setIsHovered(false); setIsDragging(false); }}
|
|
60
|
+
>
|
|
61
|
+
<div style={{
|
|
62
|
+
position: 'absolute', top: '50%', left: 0, right: 0, transform: 'translateY(-50%)',
|
|
63
|
+
height: '4px', borderRadius: '2px', backgroundColor: '#e5e7eb',
|
|
64
|
+
}} />
|
|
65
|
+
|
|
66
|
+
<div style={{
|
|
67
|
+
position: 'absolute', top: '50%', left: 0, width: `${percentage}%`, transform: 'translateY(-50%)',
|
|
68
|
+
height: '4px', borderRadius: '2px', backgroundColor: themeColor,
|
|
69
|
+
transition: isDragging ? 'none' : 'width 0.15s ease-in-out',
|
|
70
|
+
}} />
|
|
71
|
+
|
|
72
|
+
{ticks && ticks > 1 && Array.from({ length: ticks }).map((_, idx) => {
|
|
73
|
+
const tickPct = (idx / (ticks - 1)) * 100;
|
|
74
|
+
return (
|
|
75
|
+
<div
|
|
76
|
+
key={idx}
|
|
77
|
+
style={{
|
|
78
|
+
position: 'absolute', top: '50%', left: `${tickPct}%`, transform: 'translate(-50%, -50%)',
|
|
79
|
+
width: '1px', height: '8px', backgroundColor: '#d1d5db', pointerEvents: 'none',
|
|
80
|
+
}}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
})}
|
|
84
|
+
|
|
85
|
+
<input
|
|
86
|
+
type="range"
|
|
87
|
+
min={min} max={max} step={htmlStep} value={value}
|
|
88
|
+
disabled={disabled}
|
|
89
|
+
onChange={(e) => onChange(Number(e.target.value))}
|
|
90
|
+
onMouseDown={() => !disabled && setIsDragging(true)}
|
|
91
|
+
onMouseUp={() => setIsDragging(false)}
|
|
92
|
+
onTouchStart={() => !disabled && setIsDragging(true)}
|
|
93
|
+
onTouchEnd={() => setIsDragging(false)}
|
|
94
|
+
style={{
|
|
95
|
+
position: 'absolute', top: '50%', left: '-16px', right: '-16px', width: 'calc(100% + 32px)', height: '100%',
|
|
96
|
+
transform: 'translateY(-50%)', opacity: 0, cursor: disabled ? 'not-allowed' : 'pointer', zIndex: 10, margin: 0,
|
|
97
|
+
}}
|
|
98
|
+
/>
|
|
99
|
+
|
|
100
|
+
{sliderType === 'graphics' ? (
|
|
101
|
+
<div style={{
|
|
102
|
+
position: 'absolute', top: '50%', left: `${percentage}%`, transform: 'translate(-50%, -50%)',
|
|
103
|
+
transition: isDragging ? 'none' : 'left 0.15s ease-in-out', pointerEvents: 'none', zIndex: 11,
|
|
104
|
+
opacity: disabled ? 0.5 : 1,
|
|
105
|
+
}}>
|
|
106
|
+
{getEmojiForIndex(
|
|
107
|
+
reverseScaleOrder
|
|
108
|
+
? (ticks || 10) - 1 - Math.min((ticks || 10) - 1, Math.max(0, Math.round(((value - min) / (max - min)) * ((ticks || 10) - 1))))
|
|
109
|
+
: Math.min((ticks || 10) - 1, Math.max(0, Math.round(((value - min) / (max - min)) * ((ticks || 10) - 1)))),
|
|
110
|
+
ticks || 10
|
|
111
|
+
) as React.ReactNode}
|
|
112
|
+
</div>
|
|
113
|
+
) : (
|
|
114
|
+
<div style={{
|
|
115
|
+
position: 'absolute', top: '50%', left: `${percentage}%`, transform: 'translate(-50%, -50%)',
|
|
116
|
+
width: '18px', height: '18px', borderRadius: '50%', backgroundColor: '#ffffff',
|
|
117
|
+
border: `2.5px solid ${themeColor}`,
|
|
118
|
+
boxShadow: (isHovered || isDragging) && !disabled
|
|
119
|
+
? '0 0 0 6px rgba(226, 0, 116, 0.2), 0 1px 3px rgba(0,0,0,0.2)'
|
|
120
|
+
: '0 1px 3px rgba(0,0,0,0.2)',
|
|
121
|
+
pointerEvents: 'none',
|
|
122
|
+
transition: isDragging ? 'none' : 'left 0.15s ease-in-out, box-shadow 0.15s, border-color 0.2s',
|
|
123
|
+
boxSizing: 'border-box',
|
|
124
|
+
}} />
|
|
125
|
+
)}
|
|
126
|
+
|
|
127
|
+
{(isHovered || isDragging) && !disabled && (
|
|
128
|
+
<div style={{
|
|
129
|
+
position: 'absolute', bottom: '100%', left: `${percentage}%`, transform: 'translate(-50%, -10px)',
|
|
130
|
+
backgroundColor: '#1f2937', color: '#fff', fontSize: '13px', fontWeight: 600,
|
|
131
|
+
padding: '4px 10px', borderRadius: '6px', pointerEvents: 'none',
|
|
132
|
+
boxShadow: '0 4px 6px -1px rgba(0, 0, 0, 0.1)', zIndex: 20,
|
|
133
|
+
}}>
|
|
134
|
+
{tooltipText}
|
|
135
|
+
<div style={{
|
|
136
|
+
position: 'absolute', top: '100%', left: '50%', transform: 'translateX(-50%)',
|
|
137
|
+
borderWidth: '5px', borderStyle: 'solid',
|
|
138
|
+
borderColor: '#1f2937 transparent transparent transparent',
|
|
139
|
+
}} />
|
|
140
|
+
</div>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Portable MatrixDropdown template — copy to src/components/MatrixDropdown.tsx
|
|
5
|
+
* Import SDK from your package.json: @explorer02/cfm-survey-sdk or @repo/sdk
|
|
6
|
+
* UI spec: docs/03-ui-specs/shared/matrix-dropdown.md
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import React, { useState, useRef, useEffect } from 'react';
|
|
10
|
+
import type { ScaleColumn } from '@explorer02/cfm-survey-sdk';
|
|
11
|
+
import { matrixColumnStoredValue } from '@explorer02/cfm-survey-sdk';
|
|
12
|
+
|
|
13
|
+
type MatrixDropdownProps = {
|
|
14
|
+
options: ScaleColumn[];
|
|
15
|
+
value: string | number | null | Array<string | number | null> | undefined;
|
|
16
|
+
onChange: (val: string | number | null | Array<string | number | null>) => void;
|
|
17
|
+
multiple?: boolean;
|
|
18
|
+
placeholder?: string;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default function MatrixDropdown({
|
|
22
|
+
options,
|
|
23
|
+
value,
|
|
24
|
+
onChange,
|
|
25
|
+
multiple = false,
|
|
26
|
+
placeholder = 'Select Answer',
|
|
27
|
+
}: MatrixDropdownProps) {
|
|
28
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
29
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
30
|
+
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
33
|
+
if (containerRef.current && !containerRef.current.contains(event.target as Node)) {
|
|
34
|
+
setIsOpen(false);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
document.addEventListener('mousedown', handleClickOutside);
|
|
38
|
+
return () => document.removeEventListener('mousedown', handleClickOutside);
|
|
39
|
+
}, []);
|
|
40
|
+
|
|
41
|
+
const multiValues: Array<string | number | null> = Array.isArray(value) ? value : [];
|
|
42
|
+
const selectedOptionSingle = !multiple
|
|
43
|
+
? options.find(o => matrixColumnStoredValue(o) === value)
|
|
44
|
+
: null;
|
|
45
|
+
|
|
46
|
+
const toggleMultiOption = (val: string | number | null) => {
|
|
47
|
+
if (val === null) {
|
|
48
|
+
if (multiValues.includes(null)) onChange([]);
|
|
49
|
+
else onChange([null]);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
let nextVals = multiValues.filter(v => v !== null);
|
|
54
|
+
if (nextVals.includes(val)) {
|
|
55
|
+
nextVals = nextVals.filter(v => v !== val);
|
|
56
|
+
} else {
|
|
57
|
+
nextVals = [...nextVals, val];
|
|
58
|
+
}
|
|
59
|
+
onChange(nextVals);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const removeMultiOption = (e: React.MouseEvent, val: string | number | null) => {
|
|
63
|
+
e.stopPropagation();
|
|
64
|
+
onChange(multiValues.filter(v => v !== val));
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const renderTrigger = () => {
|
|
68
|
+
if (multiple) {
|
|
69
|
+
return (
|
|
70
|
+
<div
|
|
71
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
72
|
+
style={{
|
|
73
|
+
display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '8px',
|
|
74
|
+
width: '100%', padding: '10px 14px', backgroundColor: '#fff',
|
|
75
|
+
border: `1px solid ${isOpen ? '#e20074' : '#d1d5db'}`, borderRadius: '8px',
|
|
76
|
+
cursor: 'pointer', transition: 'all 0.2s', minHeight: '44px',
|
|
77
|
+
boxShadow: isOpen ? '0 0 0 3px rgba(226, 0, 116, 0.1)' : '0 1px 2px rgba(0,0,0,0.05)',
|
|
78
|
+
}}
|
|
79
|
+
>
|
|
80
|
+
{multiValues.length === 0 ? (
|
|
81
|
+
<span style={{ fontSize: '15px', color: '#6b7280', flex: 1 }}>{placeholder}</span>
|
|
82
|
+
) : (
|
|
83
|
+
multiValues.map(v => {
|
|
84
|
+
const opt = options.find(o => matrixColumnStoredValue(o) === v);
|
|
85
|
+
return (
|
|
86
|
+
<div
|
|
87
|
+
key={String(v)}
|
|
88
|
+
style={{
|
|
89
|
+
display: 'flex', alignItems: 'center', gap: '6px',
|
|
90
|
+
backgroundColor: '#f3f4f6', padding: '4px 8px', borderRadius: '4px',
|
|
91
|
+
fontSize: '14px', color: '#374151', fontWeight: 500,
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
<span dangerouslySetInnerHTML={{ __html: opt?.label || String(v) }} />
|
|
95
|
+
<div
|
|
96
|
+
onClick={e => removeMultiOption(e, v)}
|
|
97
|
+
style={{
|
|
98
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
99
|
+
width: '16px', height: '16px', borderRadius: '50%', backgroundColor: '#e5e7eb',
|
|
100
|
+
color: '#6b7280', cursor: 'pointer', fontSize: '12px', fontWeight: 'bold',
|
|
101
|
+
}}
|
|
102
|
+
>
|
|
103
|
+
×
|
|
104
|
+
</div>
|
|
105
|
+
</div>
|
|
106
|
+
);
|
|
107
|
+
})
|
|
108
|
+
)}
|
|
109
|
+
<div style={{ marginLeft: 'auto' }}>
|
|
110
|
+
<svg
|
|
111
|
+
style={{ width: '18px', height: '18px', color: '#6b7280', transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s' }}
|
|
112
|
+
fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
|
113
|
+
>
|
|
114
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
115
|
+
</svg>
|
|
116
|
+
</div>
|
|
117
|
+
</div>
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
return (
|
|
122
|
+
<div
|
|
123
|
+
onClick={() => setIsOpen(!isOpen)}
|
|
124
|
+
style={{
|
|
125
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between',
|
|
126
|
+
width: '100%', padding: '14px 16px', backgroundColor: '#fff',
|
|
127
|
+
border: `1px solid ${isOpen ? '#e20074' : '#d1d5db'}`, borderRadius: '8px',
|
|
128
|
+
cursor: 'pointer', transition: 'all 0.2s',
|
|
129
|
+
boxShadow: isOpen ? '0 0 0 3px rgba(226, 0, 116, 0.1)' : '0 1px 2px rgba(0,0,0,0.05)',
|
|
130
|
+
}}
|
|
131
|
+
>
|
|
132
|
+
<span
|
|
133
|
+
style={{ fontSize: '15px', color: selectedOptionSingle ? '#111827' : '#6b7280', fontWeight: selectedOptionSingle ? 500 : 400 }}
|
|
134
|
+
dangerouslySetInnerHTML={{ __html: selectedOptionSingle ? selectedOptionSingle.label : placeholder }}
|
|
135
|
+
/>
|
|
136
|
+
<svg
|
|
137
|
+
style={{ width: '18px', height: '18px', color: '#6b7280', transform: isOpen ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s' }}
|
|
138
|
+
fill="none" stroke="currentColor" viewBox="0 0 24 24"
|
|
139
|
+
>
|
|
140
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
|
|
141
|
+
</svg>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
return (
|
|
147
|
+
<div ref={containerRef} style={{ position: 'relative', width: '100%', userSelect: 'none' }}>
|
|
148
|
+
{renderTrigger()}
|
|
149
|
+
|
|
150
|
+
{isOpen && (
|
|
151
|
+
<div style={{
|
|
152
|
+
position: 'absolute', top: 'calc(100% + 8px)', left: 0, right: 0,
|
|
153
|
+
backgroundColor: '#fff', border: '1px solid #e5e5e5', borderRadius: '8px',
|
|
154
|
+
boxShadow: '0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
|
|
155
|
+
zIndex: 50, overflow: 'hidden', maxHeight: '280px', overflowY: 'auto',
|
|
156
|
+
}}>
|
|
157
|
+
{options.map(col => {
|
|
158
|
+
const submitValue = matrixColumnStoredValue(col);
|
|
159
|
+
const isSelected = multiple ? multiValues.includes(submitValue) : value === submitValue;
|
|
160
|
+
const isNaSelected = multiple && multiValues.includes(null);
|
|
161
|
+
const isDisabled = multiple && isNaSelected && submitValue !== null;
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div
|
|
165
|
+
key={col.id}
|
|
166
|
+
style={{
|
|
167
|
+
padding: '12px 16px', cursor: isDisabled ? 'not-allowed' : 'pointer', transition: 'background-color 0.15s',
|
|
168
|
+
backgroundColor: isSelected ? '#fdf2f8' : '#fff',
|
|
169
|
+
opacity: isDisabled ? 0.5 : 1,
|
|
170
|
+
display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: '12px',
|
|
171
|
+
}}
|
|
172
|
+
onMouseEnter={e => { if (!isDisabled) e.currentTarget.style.backgroundColor = '#fdf2f8'; }}
|
|
173
|
+
onMouseLeave={e => { if (!isDisabled) e.currentTarget.style.backgroundColor = isSelected ? '#fdf2f8' : '#fff'; }}
|
|
174
|
+
onClick={e => {
|
|
175
|
+
e.preventDefault();
|
|
176
|
+
if (isDisabled) return;
|
|
177
|
+
if (multiple) {
|
|
178
|
+
toggleMultiOption(submitValue);
|
|
179
|
+
} else {
|
|
180
|
+
onChange(submitValue);
|
|
181
|
+
setIsOpen(false);
|
|
182
|
+
}
|
|
183
|
+
}}
|
|
184
|
+
>
|
|
185
|
+
<div style={{ display: 'flex', alignItems: 'center', gap: '12px', flex: 1 }}>
|
|
186
|
+
{multiple && (
|
|
187
|
+
<div style={{
|
|
188
|
+
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
189
|
+
width: '18px', height: '18px', borderRadius: '4px',
|
|
190
|
+
border: isSelected ? '2px solid #e20074' : '2px solid #d1d5db',
|
|
191
|
+
backgroundColor: isSelected ? '#e20074' : '#fff',
|
|
192
|
+
flexShrink: 0, transition: 'all 0.15s',
|
|
193
|
+
}}>
|
|
194
|
+
{isSelected && (
|
|
195
|
+
<svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="#fff" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
|
|
196
|
+
<polyline points="20 6 9 17 4 12" />
|
|
197
|
+
</svg>
|
|
198
|
+
)}
|
|
199
|
+
</div>
|
|
200
|
+
)}
|
|
201
|
+
<span style={{ fontSize: '15px', fontWeight: isSelected ? 600 : 400, color: isSelected ? '#e20074' : '#374151', userSelect: 'none' }}
|
|
202
|
+
dangerouslySetInnerHTML={{ __html: col.label }} />
|
|
203
|
+
</div>
|
|
204
|
+
{!multiple && isSelected && (
|
|
205
|
+
<svg style={{ width: '18px', height: '18px', color: '#e20074', flexShrink: 0 }} fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
206
|
+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2.5} d="M5 13l4 4L19 7" />
|
|
207
|
+
</svg>
|
|
208
|
+
)}
|
|
209
|
+
</div>
|
|
210
|
+
);
|
|
211
|
+
})}
|
|
212
|
+
</div>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
215
|
+
);
|
|
216
|
+
}
|