chordia-ui 3.4.7 → 3.4.8

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chordia-ui",
3
- "version": "3.4.7",
3
+ "version": "3.4.8",
4
4
  "description": "Chordia Design System - UI components, tokens, and Tailwind preset",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs.js",
@@ -191,50 +191,61 @@ function CoachingColumn({ icon, label, items }) {
191
191
  const UpdatedCoachingSynthesisCard = ({ data, loading, error }) => {
192
192
  React.useEffect(() => { ensureKeyframes(); }, []);
193
193
 
194
- // Loading state
194
+ // Loading state — ThreeCirclesSpinner
195
195
  if (loading) {
196
196
  return (
197
- <div style={{
198
- display: "flex",
199
- flexDirection: "column",
200
- gap: 12,
201
- }}>
197
+ <>
198
+ <style>{`
199
+ @keyframes coaching-spinner-spin {
200
+ from { transform: rotate(0deg); }
201
+ to { transform: rotate(360deg); }
202
+ }
203
+ `}</style>
202
204
  <div style={{
203
205
  display: "flex",
206
+ flexDirection: "column",
204
207
  alignItems: "center",
205
- gap: 8,
208
+ justifyContent: "center",
209
+ gap: 12,
210
+ padding: "48px 24px",
206
211
  }}>
207
- <div style={{
208
- width: 6,
209
- height: 6,
210
- borderRadius: "50%",
211
- background: COLORS.accent,
212
- animation: "updated-coaching-pulse 1.5s ease-in-out infinite",
213
- }} />
212
+ <svg
213
+ width={48}
214
+ height={48}
215
+ viewBox="0 0 48 48"
216
+ fill="none"
217
+ xmlns="http://www.w3.org/2000/svg"
218
+ style={{ animation: "coaching-spinner-spin 1.2s linear infinite" }}
219
+ >
220
+ <path
221
+ d="M43 24C43 26.4951 42.5086 28.9658 41.5537 31.271C40.5989 33.5762 39.1993 35.6707 37.435 37.435C35.6707 39.1993 33.5762 40.5989 31.271 41.5537C28.9658 42.5086 26.4951 43 24 43C21.5049 43 19.0342 42.5086 16.729 41.5537C14.4238 40.5989 12.3293 39.1993 10.565 37.435C8.80066 35.6707 7.40113 33.5762 6.44629 31.271C5.49145 28.9658 5 26.4951 5 24"
222
+ stroke="#F3E7C7"
223
+ strokeWidth="4"
224
+ strokeLinecap="round"
225
+ />
226
+ <path
227
+ d="M12 24C12 22.4241 12.3104 20.8637 12.9134 19.4078C13.5165 17.9519 14.4004 16.629 15.5147 15.5147C16.629 14.4004 17.9519 13.5165 19.4078 12.9134C20.8637 12.3104 22.4241 12 24 12C25.5759 12 27.1363 12.3104 28.5922 12.9134C30.0481 13.5165 31.371 14.4004 32.4853 15.5147C33.5996 16.629 34.4835 17.9519 35.0866 19.4078C35.6896 20.8637 36 22.4241 36 24"
228
+ stroke="#00A66E"
229
+ strokeWidth="4"
230
+ strokeLinecap="round"
231
+ />
232
+ <path
233
+ d="M20 24C20 24.5253 20.1035 25.0454 20.3045 25.5307C20.5055 26.016 20.8001 26.457 21.1716 26.8284C21.543 27.1999 21.984 27.4945 22.4693 27.6955C22.9546 27.8965 23.4747 28 24 28C24.5253 28 25.0454 27.8965 25.5307 27.6955C26.016 27.4945 26.457 27.1999 26.8284 26.8284C27.1999 26.457 27.4945 26.016 27.6955 25.5307C27.8965 25.0454 28 24.5253 28 24"
234
+ stroke="#F3E7C7"
235
+ strokeWidth="4"
236
+ strokeLinecap="round"
237
+ />
238
+ </svg>
214
239
  <span style={{
215
240
  fontSize: 14,
216
241
  color: COLORS.muted,
217
242
  fontWeight: 500,
243
+ textAlign: "center",
218
244
  }}>
219
245
  Synthesizing coaching summary...
220
246
  </span>
221
247
  </div>
222
- {[180, 260, 220].map((w, i) => (
223
- <div
224
- key={i}
225
- style={{
226
- height: 10,
227
- width: w,
228
- maxWidth: "100%",
229
- borderRadius: 4,
230
- background: `linear-gradient(90deg, ${COLORS.absent} 25%, var(--shimmer-mid, #ECECEC) 50%, ${COLORS.absent} 75%)`,
231
- backgroundSize: "200% 100%",
232
- animation: "updated-coaching-shimmer 1.8s ease-in-out infinite",
233
- animationDelay: `${i * 0.2}s`,
234
- }}
235
- />
236
- ))}
237
- </div>
248
+ </>
238
249
  );
239
250
  }
240
251
 
@@ -1,21 +1,8 @@
1
- import { ExternalLink } from 'lucide-react';
1
+ import { useState } from 'react';
2
+ import { ChevronDown, ChevronUp } from 'lucide-react';
2
3
 
3
4
  /*
4
- * Figma node: 101-2385 (Context grid right column top, inside Frame 53 > Frame 56)
5
- *
6
- * Outer: display: flex; gap: 24px; horizontal
7
- * Two columns: flex: 1, vertical, gap: 12px
8
- *
9
- * Each metadata row:
10
- * padding: 8px 8px 12px 8px;
11
- * justify-content: space-between;
12
- * align-items: center;
13
- * border-bottom: 1px solid #D9D9D9;
14
- *
15
- * Label: 13px / 400 / #2E3236 (Grey/Strong)
16
- * Value: 13px / 400 / #808183 (Grey/Muted)
17
- *
18
- * More Details: ExternalLink icon 16px #808183 + "More Details" 13px/400/#2E3236
5
+ * Figma node: 101-2385 / 495-803 (Context grid + More Details expandable)
19
6
  */
20
7
 
21
8
  function fmtDur(seconds) {
@@ -41,7 +28,7 @@ const COLUMN_STYLE = {
41
28
  display: 'flex',
42
29
  flexDirection: 'column',
43
30
  flex: '1 0 0',
44
- gap: 12,
31
+ gap: 0,
45
32
  minWidth: 0,
46
33
  };
47
34
 
@@ -52,84 +39,212 @@ const UpdatedInteractionContext = ({
52
39
  dimensions = [],
53
40
  outcomeQuality = 'Neutral',
54
41
  onMoreDetails,
42
+ moreDetails = [],
43
+ resolutionOutcome,
44
+ customerIntent,
45
+ interactionId,
55
46
  }) => {
47
+ const [expanded, setExpanded] = useState(false);
48
+
56
49
  const duration = meta.duration_seconds != null ? fmtDur(meta.duration_seconds) : null;
57
50
  const messages = meta.message_count;
58
51
  const driver = callPurpose.interaction_driver;
59
52
  const paradigm = classification.interaction_paradigm;
60
53
 
61
- // Left column rows
62
- const leftRows = [
63
- duration != null && { label: 'Duration', value: duration },
64
- driver != null && { label: 'Driver', value: driver },
65
- ...dimensions.filter((_, i) => i % 2 === 0).map((d) => ({ label: d.label || d.key, value: d.value })),
54
+ // Build paired rows: [left, right] per line
55
+ const pairedRows = [];
56
+ const rawPairs = [
57
+ [
58
+ duration != null ? { label: 'Duration', value: duration } : null,
59
+ messages != null ? { label: 'Messages', value: messages } : null,
60
+ ],
61
+ [
62
+ driver != null ? { label: 'Driver', value: driver } : null,
63
+ paradigm != null ? { label: 'Paradigm', value: paradigm } : null,
64
+ ],
65
+ ];
66
+
67
+ // Add dimension pairs
68
+ for (let i = 0; i < dimensions.length; i += 2) {
69
+ const left = dimensions[i] ? { label: dimensions[i].label || dimensions[i].key, value: dimensions[i].value } : null;
70
+ const right = dimensions[i + 1] ? { label: dimensions[i + 1].label || dimensions[i + 1].key, value: dimensions[i + 1].value } : null;
71
+ rawPairs.push([left, right]);
72
+ }
73
+
74
+ // Last row: Outcome Quality (left) + More details toggle (right)
75
+ rawPairs.push([
66
76
  { label: 'Outcome Quality', value: outcomeQuality },
67
- ].filter(Boolean);
77
+ { isMoreDetails: true },
78
+ ]);
79
+
80
+ rawPairs.forEach((pair) => pairedRows.push(pair));
68
81
 
69
- // Right column rows
70
- const rightRows = [
71
- messages != null && { label: 'Messages', value: messages },
72
- paradigm != null && { label: 'Paradigm', value: paradigm },
73
- ...dimensions.filter((_, i) => i % 2 === 1).map((d) => ({ label: d.label || d.key, value: d.value })),
74
- // { label: 'More Details', isLink: true },
82
+ // Build "More Details" expanded rows
83
+ const detailRows = [
84
+ resolutionOutcome != null && { label: 'Resolution Outcome', value: resolutionOutcome },
85
+ customerIntent != null && { label: 'Customer Intent', value: customerIntent },
86
+ interactionId != null && { label: 'Number', value: interactionId },
87
+ ...(moreDetails || []),
75
88
  ].filter(Boolean);
76
89
 
77
- const renderRow = (item) => {
78
- if (item.isLink) {
79
- return (
80
- <div
81
- key={item.label}
82
- onClick={onMoreDetails}
83
- style={{
84
- display: 'flex',
85
- alignItems: 'center',
86
- gap: 6,
87
- padding: '8px 0 8px 0',
88
- cursor: 'pointer',
89
- fontFamily: 'var(--font-sans)',
90
- }}
91
- >
92
- <ExternalLink size={16} color="#808183" strokeWidth={1.5} />
93
- <span style={{ color: 'var(--Grey-Strong, #2E3236)', fontSize: 13, fontWeight: 400 }}>
94
- {item.label}
95
- </span>
96
- </div>
97
- );
98
- }
99
-
100
- return (
101
- <div
102
- key={item.label}
103
- style={ROW_STYLE}
104
- >
105
- <span style={{ color: 'var(--Grey-Strong, #2E3236)', whiteSpace: 'nowrap', flexShrink: 0 }}>
106
- {item.label}
107
- </span>
108
- <span style={{ color: 'var(--Grey-Muted, #808183)', textAlign: 'right' }}>
109
- {item.value}
110
- </span>
111
- </div>
112
- );
113
- };
90
+ const renderRow = (item) => (
91
+ <div
92
+ key={item.label}
93
+ style={ROW_STYLE}
94
+ >
95
+ <span style={{ color: 'var(--Grey-Strong, #2E3236)', whiteSpace: 'nowrap', flexShrink: 0 }}>
96
+ {item.label}
97
+ </span>
98
+ <span style={{
99
+ color: 'var(--Grey-Muted, #808183)',
100
+ textAlign: 'right',
101
+ overflow: 'hidden',
102
+ textOverflow: 'ellipsis',
103
+ whiteSpace: 'nowrap',
104
+ minWidth: 0,
105
+ }}>
106
+ {item.value}
107
+ </span>
108
+ </div>
109
+ );
110
+
111
+ const renderMoreDetailsToggle = () => (
112
+ <div
113
+ key="more-details"
114
+ onClick={() => {
115
+ setExpanded((p) => !p);
116
+ if (onMoreDetails && !expanded) onMoreDetails();
117
+ }}
118
+ style={{
119
+ display: 'flex',
120
+ alignItems: 'center',
121
+ gap: 6,
122
+ padding: '8px 8px 12px 8px',
123
+ cursor: 'pointer',
124
+ fontFamily: 'var(--font-sans)',
125
+ borderBottom: '1px solid var(--Grey-absent, #D9D9D9)',
126
+ }}
127
+ >
128
+ <span style={{
129
+ color: 'var(--Grey-Strong, #2E3236)',
130
+ fontSize: 13,
131
+ fontWeight: 500,
132
+ lineHeight: 'normal',
133
+ }}>
134
+ More Details
135
+ </span>
136
+ {expanded
137
+ ? <ChevronUp size={16} color="var(--Grey-Muted, #808183)" strokeWidth={1.5} />
138
+ : <ChevronDown size={16} color="var(--Grey-Muted, #808183)" strokeWidth={1.5} />
139
+ }
140
+ </div>
141
+ );
114
142
 
115
143
  return (
116
144
  <div
117
145
  style={{
118
146
  display: 'flex',
119
- alignItems: 'flex-start',
120
- gap: 24,
147
+ flexDirection: 'column',
121
148
  alignSelf: 'stretch',
149
+ gap: 0,
150
+ position: 'relative',
151
+ overflow: 'visible',
122
152
  }}
123
153
  >
124
- {/* Left column */}
125
- <div style={COLUMN_STYLE}>
126
- {leftRows.map((row) => renderRow(row))}
127
- </div>
128
-
129
- {/* Right column */}
130
- <div style={COLUMN_STYLE}>
131
- {rightRows.map((row) => renderRow(row))}
132
- </div>
154
+ {/* Paired rows — two columns side by side */}
155
+ {pairedRows.map((pair, idx) => (
156
+ <div
157
+ key={idx}
158
+ style={{
159
+ display: 'flex',
160
+ alignItems: 'flex-start',
161
+ gap: 24,
162
+ alignSelf: 'stretch',
163
+ }}
164
+ >
165
+ {/* Left cell */}
166
+ <div style={COLUMN_STYLE}>
167
+ {pair[0] && !pair[0].isMoreDetails ? renderRow(pair[0]) : <div style={{ flex: 1 }} />}
168
+ </div>
169
+
170
+ {/* Right cell */}
171
+ <div style={COLUMN_STYLE}>
172
+ {pair[1] && !pair[1].isMoreDetails
173
+ ? renderRow(pair[1])
174
+ : pair[1]?.isMoreDetails
175
+ ? renderMoreDetailsToggle()
176
+ : <div style={{ flex: 1 }} />}
177
+ </div>
178
+ </div>
179
+ ))}
180
+
181
+ {/* More Details dropdown — absolute, full width, left-aligned */}
182
+ {expanded && detailRows.length > 0 && (
183
+ <div
184
+ style={{
185
+ position: 'absolute',
186
+ top: '100%',
187
+ right: 0,
188
+ marginTop: 4,
189
+ display: 'flex',
190
+ width: 340,
191
+ flexDirection: 'column',
192
+ alignItems: 'flex-start',
193
+ borderRadius: 4,
194
+ border: '1px solid var(--Grey-absent, #D9D9D9)',
195
+ background: 'var(--Grey-White, #FFF)',
196
+ boxShadow: '-2px 2px 2px 0 rgba(0, 0, 0, 0.25)',
197
+ overflow: 'hidden',
198
+ fontFamily: 'var(--font-sans)',
199
+ zIndex: 50,
200
+ }}
201
+ >
202
+ {/* Dropdown header */}
203
+ <div style={{
204
+ padding: '12px 16px',
205
+ fontSize: 13,
206
+ fontWeight: 600,
207
+ color: 'var(--Grey-Strong, #2E3236)',
208
+ borderBottom: '1px solid var(--Grey-absent, #D9D9D9)',
209
+ alignSelf: 'stretch',
210
+ }}>
211
+ More details
212
+ </div>
213
+
214
+ {/* Detail rows */}
215
+ {detailRows.map((row) => (
216
+ <div
217
+ key={row.label}
218
+ style={{
219
+ display: 'flex',
220
+ justifyContent: 'space-between',
221
+ alignItems: 'center',
222
+ padding: '12px 16px',
223
+ gap: 24,
224
+ fontSize: 13,
225
+ fontWeight: 400,
226
+ lineHeight: 'normal',
227
+ borderBottom: '1px solid var(--Grey-absent, #D9D9D9)',
228
+ alignSelf: 'stretch',
229
+ }}
230
+ >
231
+ <span style={{ color: 'var(--Grey-Strong, #2E3236)', whiteSpace: 'nowrap', flexShrink: 0 }}>
232
+ {row.label}
233
+ </span>
234
+ <span style={{
235
+ color: 'var(--Grey-Muted, #808183)',
236
+ fontSize: 13,
237
+ fontStyle: 'normal',
238
+ fontWeight: 400,
239
+ lineHeight: '120%',
240
+ textAlign: 'right',
241
+ }}>
242
+ {row.value}
243
+ </span>
244
+ </div>
245
+ ))}
246
+ </div>
247
+ )}
133
248
  </div>
134
249
  );
135
250
  };