@handled-ai/design-system 0.18.2 → 0.18.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.
Files changed (37) hide show
  1. package/dist/charts/chart.d.ts +1 -1
  2. package/dist/components/feedback-primitives.d.ts +2 -21
  3. package/dist/components/feedback-primitives.js +6 -90
  4. package/dist/components/feedback-primitives.js.map +1 -1
  5. package/dist/components/score-why-chips.d.ts +1 -1
  6. package/dist/components/score-why-chips.js +5 -26
  7. package/dist/components/score-why-chips.js.map +1 -1
  8. package/dist/components/signal-priority-popover.d.ts +1 -1
  9. package/dist/components/signal-priority-popover.js +7 -172
  10. package/dist/components/signal-priority-popover.js.map +1 -1
  11. package/dist/components/timeline-activity.d.ts +16 -1
  12. package/dist/components/timeline-activity.js +69 -1
  13. package/dist/components/timeline-activity.js.map +1 -1
  14. package/dist/index.d.ts +3 -3
  15. package/dist/index.js.map +1 -1
  16. package/dist/prototype/index.d.ts +1 -1
  17. package/dist/prototype/prototype-accounts-view.d.ts +1 -1
  18. package/dist/prototype/prototype-admin-view.d.ts +1 -1
  19. package/dist/prototype/prototype-config.d.ts +1 -1
  20. package/dist/prototype/prototype-inbox-view.d.ts +12 -2
  21. package/dist/prototype/prototype-inbox-view.js +102 -37
  22. package/dist/prototype/prototype-inbox-view.js.map +1 -1
  23. package/dist/prototype/prototype-insights-view.d.ts +1 -1
  24. package/dist/prototype/prototype-shell.d.ts +1 -1
  25. package/dist/{signal-priority-popover-DWaAMhPI.d.ts → signal-priority-popover-DQ_VuHac.d.ts} +2 -26
  26. package/package.json +1 -3
  27. package/src/components/__tests__/timeline-activity.test.tsx +137 -0
  28. package/src/components/feedback-primitives.tsx +26 -148
  29. package/src/components/score-why-chips.tsx +2 -28
  30. package/src/components/signal-priority-popover.tsx +3 -194
  31. package/src/components/timeline-activity.tsx +112 -1
  32. package/src/index.ts +1 -1
  33. package/src/prototype/__tests__/detail-view-attention.test.tsx +2 -2
  34. package/src/prototype/__tests__/detail-view-timeline-system-events.test.tsx +322 -0
  35. package/src/prototype/prototype-config.ts +1 -11
  36. package/src/prototype/prototype-inbox-view.tsx +131 -33
  37. package/src/components/__tests__/wit-636-feedback-states.test.tsx +0 -546
@@ -17,11 +17,7 @@ import {
17
17
  Minus,
18
18
  ChevronDown,
19
19
  ChevronUp,
20
- Info,
21
- ThumbsUp,
22
- ThumbsDown,
23
- Check,
24
- Pencil
20
+ Info
25
21
  } from "lucide-react";
26
22
  import { cn } from "../lib/utils.js";
27
23
  import { FeedbackFooter } from "./feedback-primitives.js";
@@ -84,50 +80,12 @@ function DirectionIcon({ direction }) {
84
80
  return /* @__PURE__ */ jsx(Minus, { className: cls });
85
81
  }
86
82
  }
87
- function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }) {
88
- var _a, _b, _c, _d, _e;
83
+ function PriorityFactorRow({ factor }) {
84
+ var _a;
89
85
  const IconComponent = (_a = FACTOR_ICONS[factor.icon]) != null ? _a : Activity;
90
86
  const toneClasses = TONE_ICON_CLASSES[factor.tone];
91
87
  const directionClasses = DIRECTION_CLASSES[factor.direction];
92
88
  const directionLabel = factor.direction === "raises" ? "Raises" : factor.direction === "lowers" ? "Lowers" : "Neutral";
93
- const [thumbState, setThumbState] = React.useState(
94
- (_b = initialFeedback == null ? void 0 : initialFeedback.type) != null ? _b : null
95
- );
96
- const [showInput, setShowInput] = React.useState(false);
97
- const [detailText, setDetailText] = React.useState((_c = initialFeedback == null ? void 0 : initialFeedback.detail) != null ? _c : "");
98
- const [saved, setSaved] = React.useState(!!initialFeedback);
99
- const [savedDetail, setSavedDetail] = React.useState((_d = initialFeedback == null ? void 0 : initialFeedback.detail) != null ? _d : "");
100
- const ownershipLabel = (_e = initialFeedback == null ? void 0 : initialFeedback.ownershipLabel) != null ? _e : "Your feedback";
101
- React.useEffect(() => {
102
- if (initialFeedback) {
103
- setThumbState(initialFeedback.type);
104
- setSaved(true);
105
- setSavedDetail(initialFeedback.detail);
106
- }
107
- }, [initialFeedback]);
108
- const handleThumbClick = React.useCallback(
109
- (type) => {
110
- if (thumbState === type) {
111
- setThumbState(null);
112
- setShowInput(false);
113
- setSaved(false);
114
- onFactorFeedback == null ? void 0 : onFactorFeedback(factor.key, null);
115
- } else {
116
- setThumbState(type);
117
- setShowInput(true);
118
- setSaved(false);
119
- }
120
- },
121
- [thumbState, factor.key, onFactorFeedback]
122
- );
123
- const handleSubmitDetail = React.useCallback(() => {
124
- if (!thumbState) return;
125
- const text = detailText.trim();
126
- onFactorFeedback == null ? void 0 : onFactorFeedback(factor.key, thumbState, text);
127
- setSaved(true);
128
- setSavedDetail(text);
129
- setShowInput(false);
130
- }, [thumbState, detailText, factor.key, onFactorFeedback]);
131
89
  return /* @__PURE__ */ jsxs(
132
90
  "div",
133
91
  {
@@ -175,116 +133,7 @@ function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }) {
175
133
  style: { width: `${Math.min(100, Math.max(0, factor.score))}%` }
176
134
  }
177
135
  ) }),
178
- /* @__PURE__ */ jsx("div", {}),
179
- onFactorFeedback && /* @__PURE__ */ jsxs(Fragment, { children: [
180
- /* @__PURE__ */ jsx("div", {}),
181
- /* @__PURE__ */ jsxs("div", { className: "col-span-2 mt-1", children: [
182
- saved && !showInput ? (
183
- /* Persisted / saved indicator */
184
- /* @__PURE__ */ jsxs(
185
- "button",
186
- {
187
- type: "button",
188
- onClick: () => {
189
- setDetailText(savedDetail);
190
- setShowInput(true);
191
- setSaved(false);
192
- },
193
- className: "group flex items-center gap-1.5 text-[11px] text-muted-foreground hover:text-foreground transition-colors",
194
- "data-testid": `factor-feedback-persisted-${factor.key}`,
195
- children: [
196
- /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
197
- ownershipLabel,
198
- ":"
199
- ] }),
200
- thumbState === "up" ? /* @__PURE__ */ jsx(ThumbsUp, { className: "h-[10px] w-[10px]" }) : /* @__PURE__ */ jsx(ThumbsDown, { className: "h-[10px] w-[10px]" }),
201
- savedDetail && /* @__PURE__ */ jsx("span", { className: "max-w-[180px] truncate text-muted-foreground/70", children: savedDetail }),
202
- /* @__PURE__ */ jsx(Pencil, { className: "h-[9px] w-[9px] opacity-0 group-hover:opacity-100 transition-opacity" })
203
- ]
204
- }
205
- )
206
- ) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
207
- /* @__PURE__ */ jsx(
208
- "button",
209
- {
210
- type: "button",
211
- onClick: () => handleThumbClick("up"),
212
- className: cn(
213
- "p-1 rounded transition-colors",
214
- thumbState === "up" ? "text-foreground bg-muted" : "text-muted-foreground/40 hover:text-foreground hover:bg-muted/50"
215
- ),
216
- title: "This factor is accurate",
217
- "data-testid": `factor-thumb-up-${factor.key}`,
218
- children: /* @__PURE__ */ jsx(ThumbsUp, { className: "h-[10px] w-[10px]" })
219
- }
220
- ),
221
- /* @__PURE__ */ jsx(
222
- "button",
223
- {
224
- type: "button",
225
- onClick: () => handleThumbClick("down"),
226
- className: cn(
227
- "p-1 rounded transition-colors",
228
- thumbState === "down" ? "text-red-600 bg-red-50" : "text-muted-foreground/40 hover:text-red-600 hover:bg-red-50/50"
229
- ),
230
- title: "Report issue with this factor",
231
- "data-testid": `factor-thumb-down-${factor.key}`,
232
- children: /* @__PURE__ */ jsx(ThumbsDown, { className: "h-[10px] w-[10px]" })
233
- }
234
- ),
235
- saved && /* @__PURE__ */ jsxs(
236
- "span",
237
- {
238
- className: "inline-flex items-center gap-1 text-[11px] font-medium text-emerald-600",
239
- role: "status",
240
- "data-testid": `factor-saved-${factor.key}`,
241
- children: [
242
- /* @__PURE__ */ jsx(Check, { className: "h-[10px] w-[10px]" }),
243
- "Saved"
244
- ]
245
- }
246
- )
247
- ] }),
248
- showInput && thumbState && /* @__PURE__ */ jsxs("div", { className: "mt-1.5", children: [
249
- /* @__PURE__ */ jsx(
250
- "input",
251
- {
252
- type: "text",
253
- value: detailText,
254
- onChange: (e) => setDetailText(e.target.value),
255
- onKeyDown: (e) => {
256
- if (e.key === "Enter") handleSubmitDetail();
257
- if (e.key === "Escape") setShowInput(false);
258
- },
259
- placeholder: thumbState === "up" ? "What\u2019s accurate? (optional)" : "What\u2019s wrong? (optional)",
260
- className: "w-full h-6 rounded border border-border bg-background px-2 text-[11px] text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring",
261
- "data-testid": `factor-detail-input-${factor.key}`
262
- }
263
- ),
264
- /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5", children: [
265
- /* @__PURE__ */ jsx(
266
- "button",
267
- {
268
- type: "button",
269
- onClick: handleSubmitDetail,
270
- className: "bg-foreground text-background rounded px-2 py-0.5 text-[10px] font-semibold",
271
- "data-testid": `factor-submit-${factor.key}`,
272
- children: "Submit"
273
- }
274
- ),
275
- /* @__PURE__ */ jsx(
276
- "button",
277
- {
278
- type: "button",
279
- onClick: () => setShowInput(false),
280
- className: "border border-border rounded px-2 py-0.5 text-[10px] font-medium",
281
- children: "Cancel"
282
- }
283
- )
284
- ] })
285
- ] })
286
- ] })
287
- ] })
136
+ /* @__PURE__ */ jsx("div", {})
288
137
  ]
289
138
  }
290
139
  );
@@ -297,10 +146,7 @@ function SignalPriorityPopover({
297
146
  metaText,
298
147
  feedbackChips,
299
148
  onFeedbackSubmit,
300
- className,
301
- initialFactorFeedback,
302
- onFactorFeedback,
303
- initialPriorityFeedback
149
+ className
304
150
  }) {
305
151
  const urgencyLabel = getSignalScoreUrgencyLabel(score, providedLabel);
306
152
  const scoreRange = scoreRangeForUrgency(urgencyLabel);
@@ -309,7 +155,6 @@ function SignalPriorityPopover({
309
155
  const triggerDefault = URGENCY_TRIGGER_DEFAULT[urgencyLabel];
310
156
  const triggerHover = URGENCY_TRIGGER_HOVER[urgencyLabel];
311
157
  const triggerOpen = URGENCY_TRIGGER_OPEN[urgencyLabel];
312
- const footerFeedbackKey = `priority-${score}-${urgencyLabel}`;
313
158
  return /* @__PURE__ */ jsxs(PopoverPrimitive.Root, { open, onOpenChange: setOpen, children: [
314
159
  /* @__PURE__ */ jsx(PopoverPrimitive.Trigger, { asChild: true, children: /* @__PURE__ */ jsxs(
315
160
  "button",
@@ -377,15 +222,7 @@ function SignalPriorityPopover({
377
222
  "Score = weighted sum"
378
223
  ] })
379
224
  ] }),
380
- /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/40", children: factors.map((factor) => /* @__PURE__ */ jsx(
381
- PriorityFactorRow,
382
- {
383
- factor,
384
- initialFeedback: initialFactorFeedback == null ? void 0 : initialFactorFeedback[factor.key],
385
- onFactorFeedback
386
- },
387
- factor.key
388
- )) })
225
+ /* @__PURE__ */ jsx("div", { className: "divide-y divide-border/40", children: factors.map((factor) => /* @__PURE__ */ jsx(PriorityFactorRow, { factor }, factor.key)) })
389
226
  ] }),
390
227
  onFeedbackSubmit && /* @__PURE__ */ jsx("div", { className: "border-t border-border", children: /* @__PURE__ */ jsx(
391
228
  FeedbackFooter,
@@ -396,9 +233,7 @@ function SignalPriorityPopover({
396
233
  metaText,
397
234
  negativeChips: feedbackChips != null ? feedbackChips : DEFAULT_PRIORITY_FEEDBACK_CHIPS,
398
235
  positivePrompt: "Thanks. Anything to keep about this score?",
399
- className: "px-4 py-3",
400
- initialFeedback: initialPriorityFeedback,
401
- feedbackKey: footerFeedbackKey
236
+ className: "px-4 py-3"
402
237
  }
403
238
  ) })
404
239
  ]
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/signal-priority-popover.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Popover as PopoverPrimitive } from \"radix-ui\"\nimport type { LucideIcon } from \"lucide-react\"\nimport {\n Radar,\n Wallet,\n Link2,\n MessageSquare,\n TrendingDown,\n ArrowUpRight,\n ArrowDownRight,\n Clock,\n Activity,\n Minus,\n ChevronDown,\n ChevronUp,\n Info,\n ThumbsUp,\n ThumbsDown,\n Check,\n Pencil,\n} from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\nimport { FeedbackFooter } from \"./feedback-primitives\"\nimport type { FeedbackChipTree, FeedbackSubmitData, PersistedFeedbackData } from \"./feedback-primitives\"\nimport type { SignalScoreUrgencyLabel } from \"../prototype/prototype-config\"\nimport { getSignalScoreUrgencyLabel, scoreRangeForUrgency, SIGNAL_TONE_CLASSES } from \"./score-why-chips\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A single contributing factor in the priority popover.\n */\nexport interface PriorityFactor {\n key: string\n label: string\n /** Lucide icon name (e.g. \"radar\", \"wallet\", \"link-2\", \"message-square\"). */\n icon: string\n /** Drives icon background tint. */\n tone: \"alert\" | \"warn\" | \"info\"\n /** Explicit semantic label - NOT inferred from score+weight. */\n direction: \"raises\" | \"lowers\" | \"neutral\"\n /** 0-100 */\n score: number\n /** Evidence text (e.g. \"$3.4M moved in 8h - current treasury balance $0.00\"). */\n rationale: string\n}\n\nexport interface SignalPriorityPopoverProps {\n score: number\n urgencyLabel?: SignalScoreUrgencyLabel\n /** Synthesis sentence displayed in the popover head. */\n urgencyExplanation?: string\n factors: PriorityFactor[]\n /** e.g. \"Updated 4m ago - model v3.2\" */\n metaText?: string\n /** Negative feedback issue tree. */\n feedbackChips?: FeedbackChipTree[]\n onFeedbackSubmit?: (data: FeedbackSubmitData) => void\n className?: string\n /** Persisted factor-level feedback (keyed by factor key). */\n initialFactorFeedback?: Record<string, { type: \"up\" | \"down\"; detail: string; ownershipLabel?: string }>\n /** Callback when user submits factor-level feedback. */\n onFactorFeedback?: (factorKey: string, type: \"up\" | \"down\" | null, detail?: string) => void\n /** Persisted priority-level feedback for the footer. */\n initialPriorityFeedback?: PersistedFeedbackData | null\n}\n\n// ---------------------------------------------------------------------------\n// Static class maps (required for Tailwind v4 source scanning)\n// ---------------------------------------------------------------------------\n\nconst URGENCY_TRIGGER_DEFAULT: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"border-red-200 bg-red-50 text-red-700\",\n High: \"border-orange-200 bg-orange-50 text-orange-700\",\n Medium: \"border-amber-200 bg-amber-50 text-amber-700\",\n Low: \"border-blue-200 bg-blue-50 text-blue-700\",\n}\n\nconst URGENCY_TRIGGER_HOVER: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"hover:bg-red-100\",\n High: \"hover:bg-orange-100\",\n Medium: \"hover:bg-amber-100\",\n Low: \"hover:bg-blue-100\",\n}\n\nconst URGENCY_TRIGGER_OPEN: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"bg-red-100\",\n High: \"bg-orange-100\",\n Medium: \"bg-amber-100\",\n Low: \"bg-blue-100\",\n}\n\n/** Re-use shared tone classes from score-why-chips. */\nconst TONE_ICON_CLASSES: Record<PriorityFactor[\"tone\"], string> = SIGNAL_TONE_CLASSES as Record<PriorityFactor[\"tone\"], string>\n\nconst DIRECTION_CLASSES: Record<PriorityFactor[\"direction\"], string> = {\n raises: \"text-red-600\",\n lowers: \"text-emerald-600\",\n neutral: \"text-muted-foreground\",\n}\n\n// ---------------------------------------------------------------------------\n// Icon lookup\n// ---------------------------------------------------------------------------\n\nconst FACTOR_ICONS: Record<string, LucideIcon> = {\n radar: Radar,\n wallet: Wallet,\n \"link-2\": Link2,\n \"message-square\": MessageSquare,\n \"trending-down\": TrendingDown,\n \"arrow-up-right\": ArrowUpRight,\n clock: Clock,\n activity: Activity,\n}\n\n// ---------------------------------------------------------------------------\n// Urgency dot color (static map)\n// ---------------------------------------------------------------------------\n\nconst URGENCY_DOT_CLASSES: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"bg-red-500\",\n High: \"bg-orange-500\",\n Medium: \"bg-amber-500\",\n Low: \"bg-blue-500\",\n}\n\n// ---------------------------------------------------------------------------\n// Default feedback chips\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_PRIORITY_FEEDBACK_CHIPS: FeedbackChipTree[] = [\n { label: \"Wrong factor weighting\" },\n { label: \"Missing context\" },\n { label: \"Inaccurate data\" },\n { label: \"Stale\" },\n { label: \"Other\" },\n]\n\n// ---------------------------------------------------------------------------\n// Direction icon component\n// ---------------------------------------------------------------------------\n\nfunction DirectionIcon({ direction }: { direction: PriorityFactor[\"direction\"] }) {\n const cls = \"h-2.5 w-2.5\"\n switch (direction) {\n case \"raises\":\n return <ArrowUpRight className={cls} />\n case \"lowers\":\n return <ArrowDownRight className={cls} />\n case \"neutral\":\n return <Minus className={cls} />\n }\n}\n\n// ---------------------------------------------------------------------------\n// PriorityFactorRow\n// ---------------------------------------------------------------------------\n\ninterface PriorityFactorRowProps {\n factor: PriorityFactor\n initialFeedback?: { type: \"up\" | \"down\"; detail: string; ownershipLabel?: string }\n onFactorFeedback?: (factorKey: string, type: \"up\" | \"down\" | null, detail?: string) => void\n}\n\nfunction PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }: PriorityFactorRowProps) {\n const IconComponent = FACTOR_ICONS[factor.icon] ?? Activity\n const toneClasses = TONE_ICON_CLASSES[factor.tone]\n const directionClasses = DIRECTION_CLASSES[factor.direction]\n const directionLabel =\n factor.direction === \"raises\"\n ? \"Raises\"\n : factor.direction === \"lowers\"\n ? \"Lowers\"\n : \"Neutral\"\n\n const [thumbState, setThumbState] = React.useState<\"up\" | \"down\" | null>(\n initialFeedback?.type ?? null,\n )\n const [showInput, setShowInput] = React.useState(false)\n const [detailText, setDetailText] = React.useState(initialFeedback?.detail ?? \"\")\n const [saved, setSaved] = React.useState(!!initialFeedback)\n const [savedDetail, setSavedDetail] = React.useState(initialFeedback?.detail ?? \"\")\n const ownershipLabel = initialFeedback?.ownershipLabel ?? \"Your feedback\"\n\n // Sync with initialFeedback prop changes\n React.useEffect(() => {\n if (initialFeedback) {\n setThumbState(initialFeedback.type)\n setSaved(true)\n setSavedDetail(initialFeedback.detail)\n }\n }, [initialFeedback])\n\n const handleThumbClick = React.useCallback(\n (type: \"up\" | \"down\") => {\n if (thumbState === type) {\n // Toggle off\n setThumbState(null)\n setShowInput(false)\n setSaved(false)\n onFactorFeedback?.(factor.key, null)\n } else {\n setThumbState(type)\n setShowInput(true)\n setSaved(false)\n }\n },\n [thumbState, factor.key, onFactorFeedback],\n )\n\n const handleSubmitDetail = React.useCallback(() => {\n if (!thumbState) return\n const text = detailText.trim()\n onFactorFeedback?.(factor.key, thumbState, text)\n setSaved(true)\n setSavedDetail(text)\n setShowInput(false)\n }, [thumbState, detailText, factor.key, onFactorFeedback])\n\n return (\n <div\n className=\"grid grid-cols-[20px_1fr_auto] gap-x-3 gap-y-1 px-4 py-3\"\n data-testid={`factor-row-${factor.key}`}\n >\n {/* Icon */}\n <div\n className={cn(\n \"flex h-5 w-5 items-center justify-center rounded\",\n toneClasses,\n )}\n >\n <IconComponent className=\"h-3 w-3\" />\n </div>\n\n {/* Label + direction tag */}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[13px] font-semibold text-foreground\">\n {factor.label}\n </span>\n <span\n className={cn(\n \"inline-flex items-center gap-0.5 text-[10px] font-medium\",\n directionClasses,\n )}\n >\n <DirectionIcon direction={factor.direction} />\n {directionLabel}\n </span>\n </div>\n\n {/* Score number */}\n <div className=\"flex items-center text-right\">\n <span className=\"text-sm font-bold tabular-nums\">{factor.score}</span>\n <span className=\"text-xs font-normal text-muted-foreground\">/100</span>\n </div>\n\n {/* empty grid cell under icon column */}\n <div />\n\n {/* Rationale */}\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n {factor.rationale}\n </p>\n\n {/* empty grid cell under score column */}\n <div />\n\n {/* empty grid cell under icon column */}\n <div />\n\n {/* Score track */}\n <div className=\"mt-1 h-0.5 rounded-full bg-muted\">\n <div\n className=\"h-full rounded-full bg-foreground/20\"\n style={{ width: `${Math.min(100, Math.max(0, factor.score))}%` }}\n />\n </div>\n\n {/* empty grid cell under score column */}\n <div />\n\n {/* Factor-level feedback row (spans icon + content columns) */}\n {onFactorFeedback && (\n <>\n <div />\n <div className=\"col-span-2 mt-1\">\n {saved && !showInput ? (\n /* Persisted / saved indicator */\n <button\n type=\"button\"\n onClick={() => {\n setDetailText(savedDetail)\n setShowInput(true)\n setSaved(false)\n }}\n className=\"group flex items-center gap-1.5 text-[11px] text-muted-foreground hover:text-foreground transition-colors\"\n data-testid={`factor-feedback-persisted-${factor.key}`}\n >\n <span className=\"font-medium\">{ownershipLabel}:</span>\n {thumbState === \"up\" ? (\n <ThumbsUp className=\"h-[10px] w-[10px]\" />\n ) : (\n <ThumbsDown className=\"h-[10px] w-[10px]\" />\n )}\n {savedDetail && (\n <span className=\"max-w-[180px] truncate text-muted-foreground/70\">\n {savedDetail}\n </span>\n )}\n <Pencil className=\"h-[9px] w-[9px] opacity-0 group-hover:opacity-100 transition-opacity\" />\n </button>\n ) : (\n <div className=\"flex items-center gap-1.5\">\n {/* Inline thumb buttons */}\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"up\")}\n className={cn(\n \"p-1 rounded transition-colors\",\n thumbState === \"up\"\n ? \"text-foreground bg-muted\"\n : \"text-muted-foreground/40 hover:text-foreground hover:bg-muted/50\",\n )}\n title=\"This factor is accurate\"\n data-testid={`factor-thumb-up-${factor.key}`}\n >\n <ThumbsUp className=\"h-[10px] w-[10px]\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"down\")}\n className={cn(\n \"p-1 rounded transition-colors\",\n thumbState === \"down\"\n ? \"text-red-600 bg-red-50\"\n : \"text-muted-foreground/40 hover:text-red-600 hover:bg-red-50/50\",\n )}\n title=\"Report issue with this factor\"\n data-testid={`factor-thumb-down-${factor.key}`}\n >\n <ThumbsDown className=\"h-[10px] w-[10px]\" />\n </button>\n\n {/* Transient \"Saved\" pill */}\n {saved && (\n <span\n className=\"inline-flex items-center gap-1 text-[11px] font-medium text-emerald-600\"\n role=\"status\"\n data-testid={`factor-saved-${factor.key}`}\n >\n <Check className=\"h-[10px] w-[10px]\" />\n Saved\n </span>\n )}\n </div>\n )}\n\n {/* Inline detail input */}\n {showInput && thumbState && (\n <div className=\"mt-1.5\">\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\") handleSubmitDetail()\n if (e.key === \"Escape\") setShowInput(false)\n }}\n placeholder={\n thumbState === \"up\"\n ? \"What\\u2019s accurate? (optional)\"\n : \"What\\u2019s wrong? (optional)\"\n }\n className=\"w-full h-6 rounded border border-border bg-background px-2 text-[11px] text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring\"\n data-testid={`factor-detail-input-${factor.key}`}\n />\n <div className=\"mt-1 flex items-center gap-1.5\">\n <button\n type=\"button\"\n onClick={handleSubmitDetail}\n className=\"bg-foreground text-background rounded px-2 py-0.5 text-[10px] font-semibold\"\n data-testid={`factor-submit-${factor.key}`}\n >\n Submit\n </button>\n <button\n type=\"button\"\n onClick={() => setShowInput(false)}\n className=\"border border-border rounded px-2 py-0.5 text-[10px] font-medium\"\n >\n Cancel\n </button>\n </div>\n </div>\n )}\n </div>\n </>\n )}\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// SignalPriorityPopover\n// ---------------------------------------------------------------------------\n\nexport function SignalPriorityPopover({\n score,\n urgencyLabel: providedLabel,\n urgencyExplanation,\n factors,\n metaText,\n feedbackChips,\n onFeedbackSubmit,\n className,\n initialFactorFeedback,\n onFactorFeedback,\n initialPriorityFeedback,\n}: SignalPriorityPopoverProps) {\n const urgencyLabel = getSignalScoreUrgencyLabel(score, providedLabel)\n const scoreRange = scoreRangeForUrgency(urgencyLabel)\n\n const [open, setOpen] = React.useState(false)\n const [feedback, setFeedback] = React.useState<\"positive\" | \"negative\" | null>(null)\n\n const triggerDefault = URGENCY_TRIGGER_DEFAULT[urgencyLabel]\n const triggerHover = URGENCY_TRIGGER_HOVER[urgencyLabel]\n const triggerOpen = URGENCY_TRIGGER_OPEN[urgencyLabel]\n\n // Derive a stable feedbackKey for the footer from score + urgencyLabel\n const footerFeedbackKey = `priority-${score}-${urgencyLabel}`\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"inline-flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n triggerDefault,\n triggerHover,\n open && triggerOpen,\n open && \"outline-2 outline-foreground outline-offset-2\",\n className,\n )}\n data-testid=\"priority-popover-trigger\"\n >\n {urgencyLabel} Priority\n {open ? (\n <ChevronUp className=\"h-3 w-3\" />\n ) : (\n <ChevronDown className=\"h-3 w-3\" />\n )}\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side=\"bottom\"\n align=\"start\"\n sideOffset={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n className=\"z-50 w-[420px] rounded-lg border border-border bg-background shadow-lg p-0\"\n data-testid=\"priority-popover-content\"\n >\n {/* Head section */}\n <div className=\"p-4 pb-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"text-sm font-semibold text-foreground\">\n Why this is {urgencyLabel.toLowerCase()} priority\n </p>\n <span className=\"text-2xl font-bold tabular-nums text-foreground\">\n {score}\n <span className=\"text-sm font-normal text-muted-foreground\">/100</span>\n </span>\n </div>\n\n {/* Band indicator */}\n <div className=\"mt-1 flex items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span\n className={cn(\n \"inline-block h-2 w-2 rounded-full\",\n URGENCY_DOT_CLASSES[urgencyLabel],\n )}\n />\n {urgencyLabel} range: {scoreRange}\n </div>\n\n {/* Synthesis sentence */}\n {urgencyExplanation && (\n <p className=\"mt-2 text-xs leading-relaxed text-muted-foreground\">\n {urgencyExplanation}\n </p>\n )}\n </div>\n\n {/* Section label */}\n {factors.length > 0 && (\n <>\n <div className=\"flex items-center justify-between border-t border-border px-4 py-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">\n Contributing factors\n </span>\n <span className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <Info className=\"h-3 w-3\" />\n Score = weighted sum\n </span>\n </div>\n\n {/* Factor rows */}\n <div className=\"divide-y divide-border/40\">\n {factors.map((factor) => (\n <PriorityFactorRow\n key={factor.key}\n factor={factor}\n initialFeedback={initialFactorFeedback?.[factor.key]}\n onFactorFeedback={onFactorFeedback}\n />\n ))}\n </div>\n </>\n )}\n\n {/* Feedback footer */}\n {onFeedbackSubmit && (\n <div className=\"border-t border-border\">\n <FeedbackFooter\n feedback={feedback}\n onFeedbackChange={setFeedback}\n onSubmit={onFeedbackSubmit}\n metaText={metaText}\n negativeChips={feedbackChips ?? DEFAULT_PRIORITY_FEEDBACK_CHIPS}\n positivePrompt=\"Thanks. Anything to keep about this score?\"\n className=\"px-4 py-3\"\n initialFeedback={initialPriorityFeedback}\n feedbackKey={footerFeedbackKey}\n />\n </div>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n )\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/signal-priority-popover.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { Popover as PopoverPrimitive } from \"radix-ui\"\nimport type { LucideIcon } from \"lucide-react\"\nimport {\n Radar,\n Wallet,\n Link2,\n MessageSquare,\n TrendingDown,\n ArrowUpRight,\n ArrowDownRight,\n Clock,\n Activity,\n Minus,\n ChevronDown,\n ChevronUp,\n Info,\n} from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\nimport { FeedbackFooter } from \"./feedback-primitives\"\nimport type { FeedbackChipTree, FeedbackSubmitData } from \"./feedback-primitives\"\nimport type { SignalScoreUrgencyLabel } from \"../prototype/prototype-config\"\nimport { getSignalScoreUrgencyLabel, scoreRangeForUrgency, SIGNAL_TONE_CLASSES } from \"./score-why-chips\"\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/**\n * A single contributing factor in the priority popover.\n */\nexport interface PriorityFactor {\n key: string\n label: string\n /** Lucide icon name (e.g. \"radar\", \"wallet\", \"link-2\", \"message-square\"). */\n icon: string\n /** Drives icon background tint. */\n tone: \"alert\" | \"warn\" | \"info\"\n /** Explicit semantic label - NOT inferred from score+weight. */\n direction: \"raises\" | \"lowers\" | \"neutral\"\n /** 0-100 */\n score: number\n /** Evidence text (e.g. \"$3.4M moved in 8h - current treasury balance $0.00\"). */\n rationale: string\n}\n\nexport interface SignalPriorityPopoverProps {\n score: number\n urgencyLabel?: SignalScoreUrgencyLabel\n /** Synthesis sentence displayed in the popover head. */\n urgencyExplanation?: string\n factors: PriorityFactor[]\n /** e.g. \"Updated 4m ago - model v3.2\" */\n metaText?: string\n /** Negative feedback issue tree. */\n feedbackChips?: FeedbackChipTree[]\n onFeedbackSubmit?: (data: FeedbackSubmitData) => void\n className?: string\n}\n\n// ---------------------------------------------------------------------------\n// Static class maps (required for Tailwind v4 source scanning)\n// ---------------------------------------------------------------------------\n\nconst URGENCY_TRIGGER_DEFAULT: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"border-red-200 bg-red-50 text-red-700\",\n High: \"border-orange-200 bg-orange-50 text-orange-700\",\n Medium: \"border-amber-200 bg-amber-50 text-amber-700\",\n Low: \"border-blue-200 bg-blue-50 text-blue-700\",\n}\n\nconst URGENCY_TRIGGER_HOVER: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"hover:bg-red-100\",\n High: \"hover:bg-orange-100\",\n Medium: \"hover:bg-amber-100\",\n Low: \"hover:bg-blue-100\",\n}\n\nconst URGENCY_TRIGGER_OPEN: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"bg-red-100\",\n High: \"bg-orange-100\",\n Medium: \"bg-amber-100\",\n Low: \"bg-blue-100\",\n}\n\n/** Re-use shared tone classes from score-why-chips. */\nconst TONE_ICON_CLASSES: Record<PriorityFactor[\"tone\"], string> = SIGNAL_TONE_CLASSES as Record<PriorityFactor[\"tone\"], string>\n\nconst DIRECTION_CLASSES: Record<PriorityFactor[\"direction\"], string> = {\n raises: \"text-red-600\",\n lowers: \"text-emerald-600\",\n neutral: \"text-muted-foreground\",\n}\n\n// ---------------------------------------------------------------------------\n// Icon lookup\n// ---------------------------------------------------------------------------\n\nconst FACTOR_ICONS: Record<string, LucideIcon> = {\n radar: Radar,\n wallet: Wallet,\n \"link-2\": Link2,\n \"message-square\": MessageSquare,\n \"trending-down\": TrendingDown,\n \"arrow-up-right\": ArrowUpRight,\n clock: Clock,\n activity: Activity,\n}\n\n// ---------------------------------------------------------------------------\n// Urgency dot color (static map)\n// ---------------------------------------------------------------------------\n\nconst URGENCY_DOT_CLASSES: Record<SignalScoreUrgencyLabel, string> = {\n Urgent: \"bg-red-500\",\n High: \"bg-orange-500\",\n Medium: \"bg-amber-500\",\n Low: \"bg-blue-500\",\n}\n\n// ---------------------------------------------------------------------------\n// Default feedback chips\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_PRIORITY_FEEDBACK_CHIPS: FeedbackChipTree[] = [\n { label: \"Wrong factor weighting\" },\n { label: \"Missing context\" },\n { label: \"Inaccurate data\" },\n { label: \"Stale\" },\n { label: \"Other\" },\n]\n\n// ---------------------------------------------------------------------------\n// Direction icon component\n// ---------------------------------------------------------------------------\n\nfunction DirectionIcon({ direction }: { direction: PriorityFactor[\"direction\"] }) {\n const cls = \"h-2.5 w-2.5\"\n switch (direction) {\n case \"raises\":\n return <ArrowUpRight className={cls} />\n case \"lowers\":\n return <ArrowDownRight className={cls} />\n case \"neutral\":\n return <Minus className={cls} />\n }\n}\n\n// ---------------------------------------------------------------------------\n// PriorityFactorRow\n// ---------------------------------------------------------------------------\n\nfunction PriorityFactorRow({ factor }: { factor: PriorityFactor }) {\n const IconComponent = FACTOR_ICONS[factor.icon] ?? Activity\n const toneClasses = TONE_ICON_CLASSES[factor.tone]\n const directionClasses = DIRECTION_CLASSES[factor.direction]\n const directionLabel =\n factor.direction === \"raises\"\n ? \"Raises\"\n : factor.direction === \"lowers\"\n ? \"Lowers\"\n : \"Neutral\"\n\n return (\n <div\n className=\"grid grid-cols-[20px_1fr_auto] gap-x-3 gap-y-1 px-4 py-3\"\n data-testid={`factor-row-${factor.key}`}\n >\n {/* Icon */}\n <div\n className={cn(\n \"flex h-5 w-5 items-center justify-center rounded\",\n toneClasses,\n )}\n >\n <IconComponent className=\"h-3 w-3\" />\n </div>\n\n {/* Label + direction tag */}\n <div className=\"flex items-center gap-2\">\n <span className=\"text-[13px] font-semibold text-foreground\">\n {factor.label}\n </span>\n <span\n className={cn(\n \"inline-flex items-center gap-0.5 text-[10px] font-medium\",\n directionClasses,\n )}\n >\n <DirectionIcon direction={factor.direction} />\n {directionLabel}\n </span>\n </div>\n\n {/* Score number */}\n <div className=\"flex items-center text-right\">\n <span className=\"text-sm font-bold tabular-nums\">{factor.score}</span>\n <span className=\"text-xs font-normal text-muted-foreground\">/100</span>\n </div>\n\n {/* empty grid cell under icon column */}\n <div />\n\n {/* Rationale */}\n <p className=\"text-xs leading-relaxed text-muted-foreground\">\n {factor.rationale}\n </p>\n\n {/* empty grid cell under score column */}\n <div />\n\n {/* empty grid cell under icon column */}\n <div />\n\n {/* Score track */}\n <div className=\"mt-1 h-0.5 rounded-full bg-muted\">\n <div\n className=\"h-full rounded-full bg-foreground/20\"\n style={{ width: `${Math.min(100, Math.max(0, factor.score))}%` }}\n />\n </div>\n\n {/* empty grid cell under score column */}\n <div />\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// SignalPriorityPopover\n// ---------------------------------------------------------------------------\n\nexport function SignalPriorityPopover({\n score,\n urgencyLabel: providedLabel,\n urgencyExplanation,\n factors,\n metaText,\n feedbackChips,\n onFeedbackSubmit,\n className,\n}: SignalPriorityPopoverProps) {\n const urgencyLabel = getSignalScoreUrgencyLabel(score, providedLabel)\n const scoreRange = scoreRangeForUrgency(urgencyLabel)\n\n const [open, setOpen] = React.useState(false)\n const [feedback, setFeedback] = React.useState<\"positive\" | \"negative\" | null>(null)\n\n const triggerDefault = URGENCY_TRIGGER_DEFAULT[urgencyLabel]\n const triggerHover = URGENCY_TRIGGER_HOVER[urgencyLabel]\n const triggerOpen = URGENCY_TRIGGER_OPEN[urgencyLabel]\n\n return (\n <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>\n <PopoverPrimitive.Trigger asChild>\n <button\n type=\"button\"\n className={cn(\n \"inline-flex items-center gap-1 rounded-md border px-2.5 py-1 text-xs font-semibold transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n triggerDefault,\n triggerHover,\n open && triggerOpen,\n open && \"outline-2 outline-foreground outline-offset-2\",\n className,\n )}\n data-testid=\"priority-popover-trigger\"\n >\n {urgencyLabel} Priority\n {open ? (\n <ChevronUp className=\"h-3 w-3\" />\n ) : (\n <ChevronDown className=\"h-3 w-3\" />\n )}\n </button>\n </PopoverPrimitive.Trigger>\n\n <PopoverPrimitive.Portal>\n <PopoverPrimitive.Content\n side=\"bottom\"\n align=\"start\"\n sideOffset={8}\n onOpenAutoFocus={(e) => e.preventDefault()}\n className=\"z-50 w-[420px] rounded-lg border border-border bg-background shadow-lg p-0\"\n data-testid=\"priority-popover-content\"\n >\n {/* Head section */}\n <div className=\"p-4 pb-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <p className=\"text-sm font-semibold text-foreground\">\n Why this is {urgencyLabel.toLowerCase()} priority\n </p>\n <span className=\"text-2xl font-bold tabular-nums text-foreground\">\n {score}\n <span className=\"text-sm font-normal text-muted-foreground\">/100</span>\n </span>\n </div>\n\n {/* Band indicator */}\n <div className=\"mt-1 flex items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span\n className={cn(\n \"inline-block h-2 w-2 rounded-full\",\n URGENCY_DOT_CLASSES[urgencyLabel],\n )}\n />\n {urgencyLabel} range: {scoreRange}\n </div>\n\n {/* Synthesis sentence */}\n {urgencyExplanation && (\n <p className=\"mt-2 text-xs leading-relaxed text-muted-foreground\">\n {urgencyExplanation}\n </p>\n )}\n </div>\n\n {/* Section label */}\n {factors.length > 0 && (\n <>\n <div className=\"flex items-center justify-between border-t border-border px-4 py-2\">\n <span className=\"text-[10px] font-bold uppercase tracking-wider text-muted-foreground\">\n Contributing factors\n </span>\n <span className=\"flex items-center gap-1 text-[10px] text-muted-foreground\">\n <Info className=\"h-3 w-3\" />\n Score = weighted sum\n </span>\n </div>\n\n {/* Factor rows */}\n <div className=\"divide-y divide-border/40\">\n {factors.map((factor) => (\n <PriorityFactorRow key={factor.key} factor={factor} />\n ))}\n </div>\n </>\n )}\n\n {/* Feedback footer */}\n {onFeedbackSubmit && (\n <div className=\"border-t border-border\">\n <FeedbackFooter\n feedback={feedback}\n onFeedbackChange={setFeedback}\n onSubmit={onFeedbackSubmit}\n metaText={metaText}\n negativeChips={feedbackChips ?? DEFAULT_PRIORITY_FEEDBACK_CHIPS}\n positivePrompt=\"Thanks. Anything to keep about this score?\"\n className=\"px-4 py-3\"\n />\n </div>\n )}\n </PopoverPrimitive.Content>\n </PopoverPrimitive.Portal>\n </PopoverPrimitive.Root>\n )\n}\n"],"mappings":"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","names":[]}
@@ -1,5 +1,13 @@
1
1
  import * as React from 'react';
2
2
 
3
+ type TimelineEventTone = "red" | "amber" | "emerald" | "violet" | "blue" | "slate" | "salesforce" | "gmail";
4
+ interface TimelineEventActor {
5
+ kind: "user" | "integration" | "system";
6
+ name?: string;
7
+ initials?: string;
8
+ avatarUrl?: string;
9
+ verb?: string;
10
+ }
3
11
  interface TimelineEvent {
4
12
  id: string;
5
13
  icon: React.ReactNode;
@@ -24,11 +32,18 @@ interface TimelineEvent {
24
32
  defaultExpanded?: boolean;
25
33
  isInteractive?: boolean;
26
34
  onSourceClick?: () => void;
35
+ tone?: TimelineEventTone;
36
+ actor?: TimelineEventActor;
37
+ isSystemNoise?: boolean;
27
38
  }
39
+ declare const TONE_CLASSES: Record<TimelineEventTone, {
40
+ dot: string;
41
+ icon: string;
42
+ }>;
28
43
  interface TimelineActivityProps {
29
44
  events: TimelineEvent[];
30
45
  className?: string;
31
46
  }
32
47
  declare function TimelineActivity({ events, className }: TimelineActivityProps): React.JSX.Element;
33
48
 
34
- export { TimelineActivity, type TimelineActivityProps, type TimelineEvent };
49
+ export { TONE_CLASSES, TimelineActivity, type TimelineActivityProps, type TimelineEvent, type TimelineEventActor, type TimelineEventTone };
@@ -5,6 +5,42 @@ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
5
  import * as React from "react";
6
6
  import { cn } from "../lib/utils.js";
7
7
  import { ChevronDown, ChevronUp, ExternalLink } from "lucide-react";
8
+ const TONE_CLASSES = {
9
+ red: {
10
+ dot: "bg-red-50 border-red-200 dark:bg-red-950/30 dark:border-red-900/40",
11
+ icon: "text-red-600 dark:text-red-300"
12
+ },
13
+ amber: {
14
+ dot: "bg-amber-50 border-amber-200 dark:bg-amber-950/30 dark:border-amber-900/40",
15
+ icon: "text-amber-600 dark:text-amber-300"
16
+ },
17
+ emerald: {
18
+ dot: "bg-emerald-50 border-emerald-200 dark:bg-emerald-950/30 dark:border-emerald-900/40",
19
+ icon: "text-emerald-600 dark:text-emerald-300"
20
+ },
21
+ violet: {
22
+ dot: "bg-violet-50 border-violet-200 dark:bg-violet-950/30 dark:border-violet-900/40",
23
+ icon: "text-violet-600 dark:text-violet-300"
24
+ },
25
+ blue: {
26
+ dot: "bg-blue-50 border-blue-200 dark:bg-blue-950/30 dark:border-blue-900/40",
27
+ icon: "text-blue-600 dark:text-blue-300"
28
+ },
29
+ slate: {
30
+ dot: "bg-slate-100 border-slate-200 dark:bg-slate-800/50 dark:border-slate-700",
31
+ icon: "text-slate-500 dark:text-slate-300"
32
+ },
33
+ salesforce: {
34
+ dot: "bg-white border-[#00A1E0]/25 dark:bg-background dark:border-[#00A1E0]/25",
35
+ icon: "text-[#00A1E0]"
36
+ },
37
+ gmail: {
38
+ dot: "bg-white border-red-200 dark:bg-background dark:border-red-900/40",
39
+ icon: "text-red-500 dark:text-red-300"
40
+ }
41
+ };
42
+ const NEUTRAL_DOT_CLASSES = "border-border/60 bg-background";
43
+ const NEUTRAL_ICON_CLASSES = "text-muted-foreground";
8
44
  function TimelineActivity({ events, className }) {
9
45
  return /* @__PURE__ */ jsx("div", { className: cn("space-y-0", className), children: events.map((event, index) => /* @__PURE__ */ jsx(
10
46
  TimelineItem,
@@ -15,20 +51,51 @@ function TimelineActivity({ events, className }) {
15
51
  event.id
16
52
  )) });
17
53
  }
54
+ function ActorByline({ actor, time }) {
55
+ var _a, _b, _c;
56
+ if (actor.kind === "system") return null;
57
+ if (actor.kind === "integration") {
58
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-xs text-muted-foreground", "data-testid": "actor-byline", children: [
59
+ /* @__PURE__ */ jsx("span", { children: "Integration" }),
60
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
61
+ /* @__PURE__ */ jsx("span", { children: time })
62
+ ] });
63
+ }
64
+ const verb = (_a = actor.verb) != null ? _a : "performed this action";
65
+ const displayInitials = (_b = actor.initials) != null ? _b : actor.name ? actor.name.charAt(0).toUpperCase() : "?";
66
+ return /* @__PURE__ */ jsxs("div", { className: "mt-1 flex items-center gap-1.5 text-xs text-muted-foreground", "data-testid": "actor-byline", children: [
67
+ actor.avatarUrl ? /* @__PURE__ */ jsx(
68
+ "img",
69
+ {
70
+ src: actor.avatarUrl,
71
+ alt: (_c = actor.name) != null ? _c : "User",
72
+ className: "h-4 w-4 rounded-full object-cover"
73
+ }
74
+ ) : /* @__PURE__ */ jsx("span", { className: "flex h-4 w-4 items-center justify-center rounded-full bg-muted-foreground/10 text-[8px] font-semibold text-muted-foreground", children: displayInitials }),
75
+ /* @__PURE__ */ jsx("span", { className: "text-foreground font-medium", children: actor.name }),
76
+ /* @__PURE__ */ jsx("span", { children: verb }),
77
+ /* @__PURE__ */ jsx("span", { className: "text-muted-foreground/40", children: "\xB7" }),
78
+ /* @__PURE__ */ jsx("span", { children: time })
79
+ ] });
80
+ }
18
81
  function TimelineItem({ event, isLast }) {
19
82
  var _a, _b, _c, _d;
20
83
  const [expanded, setExpanded] = React.useState((_a = event.defaultExpanded) != null ? _a : false);
21
84
  const [showAllRecipients, setShowAllRecipients] = React.useState(false);
22
85
  const hasContent = !!event.content;
23
86
  const hasEmail = !!event.email;
87
+ const toneStyle = event.tone ? TONE_CLASSES[event.tone] : null;
88
+ const dotClasses = toneStyle ? toneStyle.dot : NEUTRAL_DOT_CLASSES;
89
+ const iconClasses = toneStyle ? toneStyle.icon : NEUTRAL_ICON_CLASSES;
24
90
  return /* @__PURE__ */ jsxs("div", { className: "group relative flex gap-3.5", children: [
25
91
  !isLast && /* @__PURE__ */ jsx("div", { className: "absolute left-[9px] top-5 bottom-[-6px] w-px bg-border/60" }),
26
- /* @__PURE__ */ jsx("div", { className: "relative z-10 mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-background", children: /* @__PURE__ */ jsx("div", { className: "flex h-4.5 w-4.5 items-center justify-center rounded-full border border-border/60 bg-background text-muted-foreground ring-4 ring-background", children: event.icon }) }),
92
+ /* @__PURE__ */ jsx("div", { className: "relative z-10 mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-background", children: /* @__PURE__ */ jsx("div", { className: cn("flex h-4.5 w-4.5 items-center justify-center rounded-full border ring-4 ring-background", dotClasses, iconClasses), "data-testid": "timeline-dot", children: event.icon }) }),
27
93
  /* @__PURE__ */ jsxs("div", { className: "flex-1 pb-5 pt-0.5", children: [
28
94
  /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col gap-1 sm:flex-row sm:items-start sm:justify-between", children: [
29
95
  /* @__PURE__ */ jsx("div", { className: "pr-4 text-[13px] leading-relaxed text-foreground", children: event.title }),
30
96
  /* @__PURE__ */ jsx("span", { className: "mt-0.5 shrink-0 whitespace-nowrap text-[11px] text-muted-foreground/70", children: event.time })
31
97
  ] }),
98
+ event.actor && /* @__PURE__ */ jsx(ActorByline, { actor: event.actor, time: event.time }),
32
99
  (hasContent || hasEmail) && /* @__PURE__ */ jsx("div", { className: "mt-2", children: event.isInteractive ? hasEmail ? /* @__PURE__ */ jsx("div", { className: "overflow-hidden rounded-md border border-border/80 bg-muted/20", children: /* @__PURE__ */ jsx(
33
100
  "div",
34
101
  {
@@ -176,6 +243,7 @@ function TimelineItem({ event, isLast }) {
176
243
  ] });
177
244
  }
178
245
  export {
246
+ TONE_CLASSES,
179
247
  TimelineActivity
180
248
  };
181
249
  //# sourceMappingURL=timeline-activity.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/timeline-activity.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { ChevronDown, ChevronUp, ExternalLink } from \"lucide-react\"\n\nexport interface TimelineEvent {\n id: string\n icon: React.ReactNode\n title: React.ReactNode\n time: string\n preview?: React.ReactNode\n email?: {\n from: string\n fromEmail?: string\n to: string\n cc?: string\n bcc?: string\n date?: string\n subject?: string\n body: React.ReactNode\n }\n content?: React.ReactNode\n source?: {\n label: string\n url: string\n }\n defaultExpanded?: boolean\n isInteractive?: boolean\n onSourceClick?: () => void\n}\n\nexport interface TimelineActivityProps {\n events: TimelineEvent[]\n className?: string\n}\n\nexport function TimelineActivity({ events, className }: TimelineActivityProps) {\n return (\n <div className={cn(\"space-y-0\", className)}>\n {events.map((event, index) => (\n <TimelineItem\n key={event.id}\n event={event}\n isLast={index === events.length - 1}\n />\n ))}\n </div>\n )\n}\n\nfunction TimelineItem({ event, isLast }: { event: TimelineEvent; isLast: boolean }) {\n const [expanded, setExpanded] = React.useState(event.defaultExpanded ?? false)\n const [showAllRecipients, setShowAllRecipients] = React.useState(false)\n const hasContent = !!event.content\n const hasEmail = !!event.email\n\n return (\n <div className=\"group relative flex gap-3.5\">\n {!isLast && (\n <div className=\"absolute left-[9px] top-5 bottom-[-6px] w-px bg-border/60\" />\n )}\n\n <div className=\"relative z-10 mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-background\">\n <div className=\"flex h-4.5 w-4.5 items-center justify-center rounded-full border border-border/60 bg-background text-muted-foreground ring-4 ring-background\">\n {event.icon}\n </div>\n </div>\n\n <div className=\"flex-1 pb-5 pt-0.5\">\n <div className=\"flex min-w-0 flex-col gap-1 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"pr-4 text-[13px] leading-relaxed text-foreground\">\n {event.title}\n </div>\n <span className=\"mt-0.5 shrink-0 whitespace-nowrap text-[11px] text-muted-foreground/70\">\n {event.time}\n </span>\n </div>\n\n {(hasContent || hasEmail) && (\n <div className=\"mt-2\">\n {event.isInteractive ? (\n hasEmail ? (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-muted/20\">\n <div\n className={cn(\n \"px-3 py-2.5 text-sm\",\n !expanded && \"cursor-pointer hover:bg-muted/30 transition-colors\"\n )}\n onClick={() => !expanded && setExpanded(true)}\n >\n {expanded && event.email ? (\n <div className=\"space-y-3\">\n <div>\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex min-w-0 items-baseline gap-1.5\">\n <span className=\"font-semibold text-foreground text-[13px] whitespace-nowrap\">{event.email.from}</span>\n {event.email.fromEmail && (\n <span className=\"text-muted-foreground/60 text-xs truncate\">{event.email.fromEmail}</span>\n )}\n </div>\n {event.email.date && (\n <span className=\"shrink-0 text-xs text-muted-foreground/50 whitespace-nowrap\">{event.email.date}</span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-1 text-xs text-muted-foreground\">\n <span className=\"truncate\">\n To {event.email.to}\n {!showAllRecipients && (event.email.cc || event.email.bcc) ? (\n <>, ...</>\n ) : null}\n {showAllRecipients && event.email.cc ? (\n <>, {event.email.cc}</>\n ) : null}\n {showAllRecipients && event.email.bcc ? (\n <> <span className=\"text-muted-foreground/40\">bcc</span> {event.email.bcc}</>\n ) : null}\n </span>\n {(event.email.cc || event.email.bcc) && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n setShowAllRecipients((prev) => !prev)\n }}\n className=\"shrink-0 text-muted-foreground/40 hover:text-muted-foreground transition-colors\"\n >\n <ChevronDown className={cn(\"h-3 w-3 transition-transform\", showAllRecipients && \"rotate-180\")} />\n </button>\n )}\n </div>\n </div>\n\n <div className=\"whitespace-pre-line text-sm leading-relaxed text-foreground/90\">\n {event.email.body}\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation()\n setExpanded(false)\n }}\n className=\"mt-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Show less <ChevronUp className=\"h-3 w-3\" />\n </button>\n </div>\n ) : (\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n <span className=\"line-clamp-1 pr-3 text-[13px]\">\n <span className=\"text-muted-foreground\">{event.email?.from}</span>\n <span className=\"mx-1.5 text-muted-foreground/40\">&middot;</span>\n {event.email?.subject ? (\n <>\n <span className=\"text-muted-foreground\">{event.email.subject}</span>\n <span className=\"mx-1.5 text-muted-foreground/40\">&middot;</span>\n </>\n ) : null}\n <span className=\"text-muted-foreground\">{event.preview}</span>\n </span>\n <button className=\"flex shrink-0 items-center gap-1 text-[11px] font-semibold uppercase tracking-wider transition-colors hover:text-foreground\">\n Expand <ChevronDown className=\"h-3 w-3\" />\n </button>\n </div>\n )}\n </div>\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-muted/20\">\n <div\n className={cn(\n \"px-3 py-2.5 text-sm\",\n !expanded && \"cursor-pointer hover:bg-muted/30 transition-colors\"\n )}\n onClick={() => !expanded && setExpanded(true)}\n >\n {expanded ? (\n <div className=\"space-y-2\">\n {event.content}\n <div className=\"mt-2 flex items-center gap-3\">\n {event.source ? (\n event.onSourceClick ? (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); event.onSourceClick?.(); }}\n className=\"mr-auto inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Open in {event.source.label}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <a\n href={event.source.url}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"mr-auto inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Open in {event.source.label}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n )\n ) : null}\n <button\n onClick={(e) => { e.stopPropagation(); setExpanded(false); }}\n className=\"flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Show less <ChevronUp className=\"h-3 w-3\" />\n </button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n <span className=\"line-clamp-1 pr-3\">\n {event.preview ?? event.content}\n </span>\n <button className=\"flex shrink-0 items-center gap-1 text-[11px] font-semibold uppercase tracking-wider transition-colors hover:text-foreground\">\n Expand <ChevronDown className=\"h-3 w-3\" />\n </button>\n </div>\n )}\n </div>\n </div>\n )\n ) : (\n <div className=\"pr-2 text-sm leading-relaxed text-muted-foreground\">\n {event.content}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../../src/components/timeline-activity.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { cn } from \"../lib/utils\"\nimport { ChevronDown, ChevronUp, ExternalLink } from \"lucide-react\"\n\nexport type TimelineEventTone =\n | \"red\"\n | \"amber\"\n | \"emerald\"\n | \"violet\"\n | \"blue\"\n | \"slate\"\n | \"salesforce\"\n | \"gmail\"\n\nexport interface TimelineEventActor {\n kind: \"user\" | \"integration\" | \"system\"\n name?: string\n initials?: string\n avatarUrl?: string\n verb?: string\n}\n\nexport interface TimelineEvent {\n id: string\n icon: React.ReactNode\n title: React.ReactNode\n time: string\n preview?: React.ReactNode\n email?: {\n from: string\n fromEmail?: string\n to: string\n cc?: string\n bcc?: string\n date?: string\n subject?: string\n body: React.ReactNode\n }\n content?: React.ReactNode\n source?: {\n label: string\n url: string\n }\n defaultExpanded?: boolean\n isInteractive?: boolean\n onSourceClick?: () => void\n tone?: TimelineEventTone\n actor?: TimelineEventActor\n isSystemNoise?: boolean\n}\n\n// ---------------------------------------------------------------------------\n// Tone class map — every class is a complete static string literal so\n// Tailwind's JIT scanner can detect them. NO interpolation.\n// ---------------------------------------------------------------------------\n\nexport const TONE_CLASSES: Record<\n TimelineEventTone,\n { dot: string; icon: string }\n> = {\n red: {\n dot: \"bg-red-50 border-red-200 dark:bg-red-950/30 dark:border-red-900/40\",\n icon: \"text-red-600 dark:text-red-300\",\n },\n amber: {\n dot: \"bg-amber-50 border-amber-200 dark:bg-amber-950/30 dark:border-amber-900/40\",\n icon: \"text-amber-600 dark:text-amber-300\",\n },\n emerald: {\n dot: \"bg-emerald-50 border-emerald-200 dark:bg-emerald-950/30 dark:border-emerald-900/40\",\n icon: \"text-emerald-600 dark:text-emerald-300\",\n },\n violet: {\n dot: \"bg-violet-50 border-violet-200 dark:bg-violet-950/30 dark:border-violet-900/40\",\n icon: \"text-violet-600 dark:text-violet-300\",\n },\n blue: {\n dot: \"bg-blue-50 border-blue-200 dark:bg-blue-950/30 dark:border-blue-900/40\",\n icon: \"text-blue-600 dark:text-blue-300\",\n },\n slate: {\n dot: \"bg-slate-100 border-slate-200 dark:bg-slate-800/50 dark:border-slate-700\",\n icon: \"text-slate-500 dark:text-slate-300\",\n },\n salesforce: {\n dot: \"bg-white border-[#00A1E0]/25 dark:bg-background dark:border-[#00A1E0]/25\",\n icon: \"text-[#00A1E0]\",\n },\n gmail: {\n dot: \"bg-white border-red-200 dark:bg-background dark:border-red-900/40\",\n icon: \"text-red-500 dark:text-red-300\",\n },\n}\n\nconst NEUTRAL_DOT_CLASSES = \"border-border/60 bg-background\"\nconst NEUTRAL_ICON_CLASSES = \"text-muted-foreground\"\n\nexport interface TimelineActivityProps {\n events: TimelineEvent[]\n className?: string\n}\n\nexport function TimelineActivity({ events, className }: TimelineActivityProps) {\n return (\n <div className={cn(\"space-y-0\", className)}>\n {events.map((event, index) => (\n <TimelineItem\n key={event.id}\n event={event}\n isLast={index === events.length - 1}\n />\n ))}\n </div>\n )\n}\n\nfunction ActorByline({ actor, time }: { actor: TimelineEventActor; time: string }) {\n if (actor.kind === \"system\") return null\n\n if (actor.kind === \"integration\") {\n return (\n <div className=\"mt-1 flex items-center gap-1.5 text-xs text-muted-foreground\" data-testid=\"actor-byline\">\n <span>Integration</span>\n <span className=\"text-muted-foreground/40\">&middot;</span>\n <span>{time}</span>\n </div>\n )\n }\n\n // actor.kind === \"user\"\n const verb = actor.verb ?? \"performed this action\"\n const displayInitials = actor.initials ?? (actor.name ? actor.name.charAt(0).toUpperCase() : \"?\")\n\n return (\n <div className=\"mt-1 flex items-center gap-1.5 text-xs text-muted-foreground\" data-testid=\"actor-byline\">\n {actor.avatarUrl ? (\n <img\n src={actor.avatarUrl}\n alt={actor.name ?? \"User\"}\n className=\"h-4 w-4 rounded-full object-cover\"\n />\n ) : (\n <span className=\"flex h-4 w-4 items-center justify-center rounded-full bg-muted-foreground/10 text-[8px] font-semibold text-muted-foreground\">\n {displayInitials}\n </span>\n )}\n <span className=\"text-foreground font-medium\">{actor.name}</span>\n <span>{verb}</span>\n <span className=\"text-muted-foreground/40\">&middot;</span>\n <span>{time}</span>\n </div>\n )\n}\n\nfunction TimelineItem({ event, isLast }: { event: TimelineEvent; isLast: boolean }) {\n const [expanded, setExpanded] = React.useState(event.defaultExpanded ?? false)\n const [showAllRecipients, setShowAllRecipients] = React.useState(false)\n const hasContent = !!event.content\n const hasEmail = !!event.email\n\n const toneStyle = event.tone ? TONE_CLASSES[event.tone] : null\n const dotClasses = toneStyle ? toneStyle.dot : NEUTRAL_DOT_CLASSES\n const iconClasses = toneStyle ? toneStyle.icon : NEUTRAL_ICON_CLASSES\n\n return (\n <div className=\"group relative flex gap-3.5\">\n {!isLast && (\n <div className=\"absolute left-[9px] top-5 bottom-[-6px] w-px bg-border/60\" />\n )}\n\n <div className=\"relative z-10 mt-1 flex h-5 w-5 shrink-0 items-center justify-center rounded-full bg-background\">\n <div className={cn(\"flex h-4.5 w-4.5 items-center justify-center rounded-full border ring-4 ring-background\", dotClasses, iconClasses)} data-testid=\"timeline-dot\">\n {event.icon}\n </div>\n </div>\n\n <div className=\"flex-1 pb-5 pt-0.5\">\n <div className=\"flex min-w-0 flex-col gap-1 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"pr-4 text-[13px] leading-relaxed text-foreground\">\n {event.title}\n </div>\n <span className=\"mt-0.5 shrink-0 whitespace-nowrap text-[11px] text-muted-foreground/70\">\n {event.time}\n </span>\n </div>\n\n {event.actor && <ActorByline actor={event.actor} time={event.time} />}\n\n {(hasContent || hasEmail) && (\n <div className=\"mt-2\">\n {event.isInteractive ? (\n hasEmail ? (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-muted/20\">\n <div\n className={cn(\n \"px-3 py-2.5 text-sm\",\n !expanded && \"cursor-pointer hover:bg-muted/30 transition-colors\"\n )}\n onClick={() => !expanded && setExpanded(true)}\n >\n {expanded && event.email ? (\n <div className=\"space-y-3\">\n <div>\n <div className=\"flex items-center justify-between gap-4\">\n <div className=\"flex min-w-0 items-baseline gap-1.5\">\n <span className=\"font-semibold text-foreground text-[13px] whitespace-nowrap\">{event.email.from}</span>\n {event.email.fromEmail && (\n <span className=\"text-muted-foreground/60 text-xs truncate\">{event.email.fromEmail}</span>\n )}\n </div>\n {event.email.date && (\n <span className=\"shrink-0 text-xs text-muted-foreground/50 whitespace-nowrap\">{event.email.date}</span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-1 text-xs text-muted-foreground\">\n <span className=\"truncate\">\n To {event.email.to}\n {!showAllRecipients && (event.email.cc || event.email.bcc) ? (\n <>, ...</>\n ) : null}\n {showAllRecipients && event.email.cc ? (\n <>, {event.email.cc}</>\n ) : null}\n {showAllRecipients && event.email.bcc ? (\n <> <span className=\"text-muted-foreground/40\">bcc</span> {event.email.bcc}</>\n ) : null}\n </span>\n {(event.email.cc || event.email.bcc) && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation()\n setShowAllRecipients((prev) => !prev)\n }}\n className=\"shrink-0 text-muted-foreground/40 hover:text-muted-foreground transition-colors\"\n >\n <ChevronDown className={cn(\"h-3 w-3 transition-transform\", showAllRecipients && \"rotate-180\")} />\n </button>\n )}\n </div>\n </div>\n\n <div className=\"whitespace-pre-line text-sm leading-relaxed text-foreground/90\">\n {event.email.body}\n </div>\n\n <button\n onClick={(e) => {\n e.stopPropagation()\n setExpanded(false)\n }}\n className=\"mt-2 flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Show less <ChevronUp className=\"h-3 w-3\" />\n </button>\n </div>\n ) : (\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n <span className=\"line-clamp-1 pr-3 text-[13px]\">\n <span className=\"text-muted-foreground\">{event.email?.from}</span>\n <span className=\"mx-1.5 text-muted-foreground/40\">&middot;</span>\n {event.email?.subject ? (\n <>\n <span className=\"text-muted-foreground\">{event.email.subject}</span>\n <span className=\"mx-1.5 text-muted-foreground/40\">&middot;</span>\n </>\n ) : null}\n <span className=\"text-muted-foreground\">{event.preview}</span>\n </span>\n <button className=\"flex shrink-0 items-center gap-1 text-[11px] font-semibold uppercase tracking-wider transition-colors hover:text-foreground\">\n Expand <ChevronDown className=\"h-3 w-3\" />\n </button>\n </div>\n )}\n </div>\n </div>\n ) : (\n <div className=\"overflow-hidden rounded-md border border-border/80 bg-muted/20\">\n <div\n className={cn(\n \"px-3 py-2.5 text-sm\",\n !expanded && \"cursor-pointer hover:bg-muted/30 transition-colors\"\n )}\n onClick={() => !expanded && setExpanded(true)}\n >\n {expanded ? (\n <div className=\"space-y-2\">\n {event.content}\n <div className=\"mt-2 flex items-center gap-3\">\n {event.source ? (\n event.onSourceClick ? (\n <button\n type=\"button\"\n onClick={(e) => { e.stopPropagation(); event.onSourceClick?.(); }}\n className=\"mr-auto inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Open in {event.source.label}\n <ExternalLink className=\"h-3 w-3\" />\n </button>\n ) : (\n <a\n href={event.source.url}\n target=\"_blank\"\n rel=\"noreferrer noopener\"\n className=\"mr-auto inline-flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Open in {event.source.label}\n <ExternalLink className=\"h-3 w-3\" />\n </a>\n )\n ) : null}\n <button\n onClick={(e) => { e.stopPropagation(); setExpanded(false); }}\n className=\"flex items-center gap-1.5 text-[11px] font-semibold uppercase tracking-wider text-muted-foreground transition-colors hover:text-foreground\"\n >\n Show less <ChevronUp className=\"h-3 w-3\" />\n </button>\n </div>\n </div>\n ) : (\n <div className=\"flex items-center justify-between gap-2 text-muted-foreground\">\n <span className=\"line-clamp-1 pr-3\">\n {event.preview ?? event.content}\n </span>\n <button className=\"flex shrink-0 items-center gap-1 text-[11px] font-semibold uppercase tracking-wider transition-colors hover:text-foreground\">\n Expand <ChevronDown className=\"h-3 w-3\" />\n </button>\n </div>\n )}\n </div>\n </div>\n )\n ) : (\n <div className=\"pr-2 text-sm leading-relaxed text-muted-foreground\">\n {event.content}\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
package/dist/index.d.ts CHANGED
@@ -27,8 +27,8 @@ export { Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, Di
27
27
  export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './components/dropdown-menu.js';
28
28
  export { EmptyState, EmptyStateProps } from './components/empty-state.js';
29
29
  export { ActivityItem, ConnectedApps, EntityActivityItem, EntityDetails, EntityMetadataField, EntityMetadataGrid, EntityPanel, EntityPanelBrandIcons, EntityPanelHeader, EntityPanelTabs, EntitySection, PanelMode, PotentialContacts, RecentActivity, SystemActivity, useEntityPanel } from './components/entity-panel.js';
30
- export { FeedbackActions, FeedbackActionsProps, FeedbackChipGroup, FeedbackChipGroupProps, FeedbackChipTree, FeedbackFooter, FeedbackFooterProps, FeedbackInput, FeedbackInputProps, FeedbackSubmitData, PersistedFeedbackData } from './components/feedback-primitives.js';
31
- export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, P as PriorityFactor, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, S as SignalPriorityPopover, k as SignalPriorityPopoverProps, l as SignalScoreData, m as SignalScoreExplanationBucket, n as SignalScoreExplanationSignal, o as SignalScoreUrgencyLabel, W as WorkQueueViewConfig } from './signal-priority-popover-DWaAMhPI.js';
30
+ export { FeedbackActions, FeedbackActionsProps, FeedbackChipGroup, FeedbackChipGroupProps, FeedbackChipTree, FeedbackFooter, FeedbackFooterProps, FeedbackInput, FeedbackInputProps, FeedbackSubmitData } from './components/feedback-primitives.js';
31
+ export { A as AccountFilterTab, a as AccountsViewConfig, b as AdminTab, c as AdminViewConfig, B as BriefStyleVariant, E as EntityPanelConfig, d as EntityPanelSection, I as InboxDetailSections, e as InboxSortOption, f as InboxViewConfig, g as InsightsCustomTab, h as InsightsViewConfig, P as PriorityFactor, i as PrototypeBrandConfig, j as PrototypeConfig, Q as QueueItem, S as SignalPriorityPopover, k as SignalPriorityPopoverProps, l as SignalScoreData, m as SignalScoreExplanationBucket, n as SignalScoreExplanationSignal, o as SignalScoreUrgencyLabel, W as WorkQueueViewConfig } from './signal-priority-popover-DQ_VuHac.js';
32
32
  export { FilterChip, FilterChipProps } from './components/filter-chip.js';
33
33
  export { InboxGroupHeader, InboxRow, InboxRowProps } from './components/inbox-row.js';
34
34
  export { AssigneeFilter, InboxFilterCategory, InboxToolbar, InboxToolbarProps } from './components/inbox-toolbar.js';
@@ -76,7 +76,7 @@ export { Switch } from './components/switch.js';
76
76
  export { Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow } from './components/table.js';
77
77
  export { Tabs, TabsContent, TabsList, TabsTrigger, tabsListVariants } from './components/tabs.js';
78
78
  export { Textarea } from './components/textarea.js';
79
- export { TimelineActivity, TimelineActivityProps, TimelineEvent } from './components/timeline-activity.js';
79
+ export { TONE_CLASSES, TimelineActivity, TimelineActivityProps, TimelineEvent, TimelineEventActor, TimelineEventTone } from './components/timeline-activity.js';
80
80
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/tooltip.js';
81
81
  export { ActorByline, ActorBylineProps, UserPill, UserPillProps } from './components/user-display.js';
82
82
  export { VariableAutocomplete, VariableAutocompleteProps, VariableDef, VariableGroup } from './components/variable-autocomplete.js';