@handled-ai/design-system 0.18.4 → 0.18.5

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 (76) hide show
  1. package/dist/charts/chart.d.ts +1 -1
  2. package/dist/charts/empty-chart-state.d.ts +11 -0
  3. package/dist/charts/empty-chart-state.js +70 -0
  4. package/dist/charts/empty-chart-state.js.map +1 -0
  5. package/dist/charts/index.d.ts +1 -0
  6. package/dist/charts/index.js +1 -0
  7. package/dist/charts/index.js.map +1 -1
  8. package/dist/charts/pipeline-overview.d.ts +2 -1
  9. package/dist/charts/pipeline-overview.js +32 -1
  10. package/dist/charts/pipeline-overview.js.map +1 -1
  11. package/dist/components/badge.d.ts +1 -1
  12. package/dist/components/button.d.ts +1 -1
  13. package/dist/components/days-open-cell.d.ts +16 -0
  14. package/dist/components/days-open-cell.js +73 -0
  15. package/dist/components/days-open-cell.js.map +1 -0
  16. package/dist/components/detail-drawer.d.ts +16 -0
  17. package/dist/components/detail-drawer.js +45 -0
  18. package/dist/components/detail-drawer.js.map +1 -0
  19. package/dist/components/feedback-primitives.d.ts +2 -41
  20. package/dist/components/feedback-primitives.js +6 -241
  21. package/dist/components/feedback-primitives.js.map +1 -1
  22. package/dist/components/insights-filter-bar.d.ts +2 -1
  23. package/dist/components/insights-filter-bar.js +13 -5
  24. package/dist/components/insights-filter-bar.js.map +1 -1
  25. package/dist/components/linked-entity-cell.d.ts +14 -0
  26. package/dist/components/linked-entity-cell.js +96 -0
  27. package/dist/components/linked-entity-cell.js.map +1 -0
  28. package/dist/components/metric-card.d.ts +14 -1
  29. package/dist/components/metric-card.js +97 -0
  30. package/dist/components/metric-card.js.map +1 -1
  31. package/dist/components/pill.d.ts +26 -0
  32. package/dist/components/pill.js +77 -0
  33. package/dist/components/pill.js.map +1 -0
  34. package/dist/components/quick-segment.d.ts +13 -0
  35. package/dist/components/quick-segment.js +96 -0
  36. package/dist/components/quick-segment.js.map +1 -0
  37. package/dist/components/score-why-chips.d.ts +1 -1
  38. package/dist/components/score-why-chips.js +5 -26
  39. package/dist/components/score-why-chips.js.map +1 -1
  40. package/dist/components/signal-priority-popover.d.ts +1 -1
  41. package/dist/components/signal-priority-popover.js +6 -32
  42. package/dist/components/signal-priority-popover.js.map +1 -1
  43. package/dist/components/tabs.d.ts +1 -1
  44. package/dist/index.d.ts +9 -3
  45. package/dist/index.js +6 -2
  46. package/dist/index.js.map +1 -1
  47. package/dist/prototype/index.d.ts +1 -1
  48. package/dist/prototype/prototype-accounts-view.d.ts +1 -1
  49. package/dist/prototype/prototype-admin-view.d.ts +1 -1
  50. package/dist/prototype/prototype-config.d.ts +1 -1
  51. package/dist/prototype/prototype-inbox-view.d.ts +1 -1
  52. package/dist/prototype/prototype-inbox-view.js +1 -4
  53. package/dist/prototype/prototype-inbox-view.js.map +1 -1
  54. package/dist/prototype/prototype-insights-view.d.ts +1 -1
  55. package/dist/prototype/prototype-shell.d.ts +1 -1
  56. package/dist/{signal-priority-popover-DWaAMhPI.d.ts → signal-priority-popover-DQ_VuHac.d.ts} +2 -26
  57. package/package.json +1 -3
  58. package/src/charts/__tests__/insights-charts.test.tsx +62 -0
  59. package/src/charts/empty-chart-state.tsx +44 -0
  60. package/src/charts/index.ts +1 -0
  61. package/src/charts/pipeline-overview.tsx +41 -1
  62. package/src/components/__tests__/insights-primitives.test.tsx +135 -0
  63. package/src/components/days-open-cell.tsx +50 -0
  64. package/src/components/detail-drawer.tsx +60 -0
  65. package/src/components/feedback-primitives.tsx +26 -333
  66. package/src/components/insights-filter-bar.tsx +13 -4
  67. package/src/components/linked-entity-cell.tsx +74 -0
  68. package/src/components/metric-card.tsx +98 -0
  69. package/src/components/pill.tsx +67 -0
  70. package/src/components/quick-segment.tsx +68 -0
  71. package/src/components/score-why-chips.tsx +2 -28
  72. package/src/components/signal-priority-popover.tsx +4 -44
  73. package/src/index.ts +7 -2
  74. package/src/prototype/prototype-config.ts +1 -11
  75. package/src/prototype/prototype-inbox-view.tsx +0 -3
  76. package/src/components/__tests__/wit-636-feedback-states.test.tsx +0 -546
@@ -23,6 +23,7 @@ export interface FilterDefinition {
23
23
 
24
24
  export interface InsightsFilterBarProps {
25
25
  filters: FilterDefinition[]
26
+ variant?: "default" | "compact"
26
27
  values: Record<string, string>
27
28
  onChange: (filterId: string, value: string) => void
28
29
  onClearAll?: () => void
@@ -45,6 +46,7 @@ function InsightsFilterBar({
45
46
  onChange,
46
47
  onClearAll,
47
48
  className,
49
+ variant = "default",
48
50
  }: InsightsFilterBarProps) {
49
51
  const showClearAll = onClearAll && hasNonDefaultValue(filters, values)
50
52
 
@@ -52,11 +54,12 @@ function InsightsFilterBar({
52
54
  <div
53
55
  data-slot="insights-filter-bar"
54
56
  className={cn(
55
- "flex flex-wrap items-center gap-3 rounded-md border border-border bg-card p-4 shadow-sm",
57
+ "flex flex-wrap items-center rounded-md border border-border bg-card shadow-sm",
58
+ variant === "compact" ? "gap-2 p-2" : "gap-3 p-4",
56
59
  className
57
60
  )}
58
61
  >
59
- <div className="flex items-center gap-2">
62
+ <div className={cn("flex items-center gap-2", variant === "compact" && "sr-only")}>
60
63
  <FilterIcon className="h-4 w-4 text-muted-foreground" />
61
64
  <span className="text-sm font-medium text-muted-foreground">
62
65
  Filters:
@@ -80,7 +83,10 @@ function InsightsFilterBar({
80
83
  <Button
81
84
  variant="outline"
82
85
  size="sm"
83
- className="h-8 gap-1.5 text-xs font-normal shadow-none"
86
+ className={cn(
87
+ "gap-1.5 text-xs font-normal shadow-none",
88
+ variant === "compact" ? "h-7 px-2" : "h-8"
89
+ )}
84
90
  >
85
91
  {IconComp ? (
86
92
  <IconComp className="h-3.5 w-3.5 text-muted-foreground" />
@@ -118,7 +124,10 @@ function InsightsFilterBar({
118
124
  <Button
119
125
  variant="ghost"
120
126
  size="sm"
121
- className="h-8 text-xs text-destructive hover:text-destructive"
127
+ className={cn(
128
+ "text-xs text-destructive hover:text-destructive",
129
+ variant === "compact" ? "h-7 px-2" : "h-8"
130
+ )}
122
131
  onClick={onClearAll}
123
132
  >
124
133
  Clear All
@@ -0,0 +1,74 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { ExternalLink } from "lucide-react"
5
+
6
+ import { cn } from "../lib/utils"
7
+
8
+ export interface LinkedEntityCellProps extends React.HTMLAttributes<HTMLDivElement> {
9
+ name: React.ReactNode
10
+ href?: string
11
+ subtitle?: React.ReactNode
12
+ meta?: React.ReactNode
13
+ icon?: React.ReactNode
14
+ external?: boolean
15
+ onNavigate?: () => void
16
+ }
17
+
18
+ export function LinkedEntityCell({
19
+ name,
20
+ href,
21
+ subtitle,
22
+ meta,
23
+ icon,
24
+ external = false,
25
+ onNavigate,
26
+ className,
27
+ ...props
28
+ }: LinkedEntityCellProps) {
29
+ const content = (
30
+ <>
31
+ <span className="truncate">{name}</span>
32
+ {external ? <ExternalLink className="h-3 w-3 shrink-0 opacity-60" aria-hidden="true" /> : null}
33
+ </>
34
+ )
35
+
36
+ return (
37
+ <div
38
+ data-slot="linked-entity-cell"
39
+ className={cn("flex min-w-0 items-center gap-2", className)}
40
+ {...props}
41
+ >
42
+ {icon ? (
43
+ <span data-slot="linked-entity-cell-icon" className="shrink-0 text-muted-foreground">
44
+ {icon}
45
+ </span>
46
+ ) : null}
47
+ <div className="min-w-0 flex-1">
48
+ {href ? (
49
+ <a
50
+ data-slot="linked-entity-cell-link"
51
+ href={href}
52
+ target={external ? "_blank" : undefined}
53
+ rel={external ? "noreferrer" : undefined}
54
+ onClick={onNavigate}
55
+ className="inline-flex max-w-full items-center gap-1 truncate font-medium text-foreground underline-offset-4 hover:text-primary hover:underline"
56
+ >
57
+ {content}
58
+ </a>
59
+ ) : (
60
+ <span data-slot="linked-entity-cell-name" className="block truncate font-medium text-foreground">
61
+ {name}
62
+ </span>
63
+ )}
64
+ {subtitle || meta ? (
65
+ <div data-slot="linked-entity-cell-meta" className="mt-0.5 truncate text-xs text-muted-foreground">
66
+ {subtitle}
67
+ {subtitle && meta ? <span className="px-1">·</span> : null}
68
+ {meta}
69
+ </div>
70
+ ) : null}
71
+ </div>
72
+ </div>
73
+ )
74
+ }
@@ -1,5 +1,6 @@
1
1
  import * as React from "react"
2
2
  import { ArrowUp, ArrowDown, Info, ExternalLink } from "lucide-react"
3
+ import type { LucideIcon } from "lucide-react"
3
4
  import { cn } from "../lib/utils"
4
5
 
5
6
  export interface MetricDataPoint {
@@ -24,6 +25,103 @@ export interface MetricCardProps {
24
25
  showInfo?: boolean
25
26
  }
26
27
 
28
+ export interface KpiStripItem {
29
+ id?: string
30
+ label: React.ReactNode
31
+ value: React.ReactNode
32
+ unit?: React.ReactNode
33
+ subtitle?: React.ReactNode
34
+ change?: MetricCardProps["change"]
35
+ }
36
+
37
+ export interface KpiStripProps extends React.HTMLAttributes<HTMLDivElement> {
38
+ items: KpiStripItem[]
39
+ columns?: 2 | 3 | 4
40
+ }
41
+
42
+ function getChangePresentation(change: MetricCardProps["change"]): {
43
+ icon: LucideIcon | null
44
+ className: string
45
+ } | null {
46
+ if (!change) return null
47
+ if (change.direction === "neutral") {
48
+ return { icon: null, className: "text-muted-foreground" }
49
+ }
50
+
51
+ const isGoodDirection = change.isGood !== undefined
52
+ ? change.isGood
53
+ : change.direction === "up"
54
+
55
+ return {
56
+ icon: change.direction === "down" ? ArrowDown : ArrowUp,
57
+ className: isGoodDirection ? "text-emerald-600" : "text-red-600",
58
+ }
59
+ }
60
+
61
+ export function KpiStrip({ items, columns = 4, className, ...props }: KpiStripProps) {
62
+ return (
63
+ <div
64
+ data-slot="kpi-strip"
65
+ className={cn(
66
+ "grid gap-3 rounded-xl border border-border bg-card p-3 shadow-sm",
67
+ columns === 2 && "sm:grid-cols-2",
68
+ columns === 3 && "sm:grid-cols-3",
69
+ columns === 4 && "sm:grid-cols-2 lg:grid-cols-4",
70
+ className
71
+ )}
72
+ {...props}
73
+ >
74
+ {items.map((item, index) => {
75
+ const changePresentation = getChangePresentation(item.change)
76
+ const ChangeIcon = changePresentation?.icon
77
+
78
+ return (
79
+ <div
80
+ key={item.id ?? index}
81
+ data-slot="kpi-strip-item"
82
+ className="min-w-0 rounded-lg bg-muted/40 px-3 py-2"
83
+ >
84
+ <div data-slot="kpi-strip-label" className="truncate text-xs font-medium text-muted-foreground">
85
+ {item.label}
86
+ </div>
87
+ <div className="mt-1 flex items-baseline gap-1">
88
+ <span data-slot="kpi-strip-value" className="truncate text-2xl font-bold tracking-tight text-foreground">
89
+ {item.value}
90
+ </span>
91
+ {item.unit ? (
92
+ <span data-slot="kpi-strip-unit" className="text-sm font-semibold text-muted-foreground">
93
+ {item.unit}
94
+ </span>
95
+ ) : null}
96
+ </div>
97
+ {item.subtitle || item.change ? (
98
+ <div className="mt-1 flex items-center gap-2 text-xs">
99
+ {item.change ? (
100
+ <span
101
+ data-slot="kpi-strip-change"
102
+ className={cn(
103
+ "inline-flex items-center gap-0.5 font-semibold",
104
+ changePresentation?.className
105
+ )}
106
+ >
107
+ {ChangeIcon ? <ChangeIcon className="h-3 w-3 stroke-[3]" /> : null}
108
+ {item.change.value}
109
+ </span>
110
+ ) : null}
111
+ {item.subtitle ? (
112
+ <span data-slot="kpi-strip-subtitle" className="truncate text-muted-foreground">
113
+ {item.subtitle}
114
+ </span>
115
+ ) : null}
116
+ </div>
117
+ ) : null}
118
+ </div>
119
+ )
120
+ })}
121
+ </div>
122
+ )
123
+ }
124
+
27
125
  export function MetricCard({
28
126
  title,
29
127
  value,
@@ -0,0 +1,67 @@
1
+ import * as React from "react"
2
+ import { cva, type VariantProps } from "class-variance-authority"
3
+
4
+ import { cn } from "../lib/utils"
5
+
6
+ /**
7
+ * Insights-friendly pill convenience wrappers.
8
+ *
9
+ * Pill and StatusPill are small, rounded wrappers for dense Insights surfaces
10
+ * such as tables, KPI strips, and filter summaries. They intentionally wrap the
11
+ * existing Badge/StatusBadge visual language and are not a replacement for all
12
+ * Badge usage across the design system.
13
+ */
14
+ export type PillStatus = "success" | "warning" | "error" | "neutral" | "info"
15
+
16
+ const pillVariants = cva(
17
+ "inline-flex w-fit shrink-0 items-center justify-center gap-1 whitespace-nowrap rounded-full border px-2.5 py-0.5 text-xs font-medium transition-colors [&>svg]:size-3",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "border-transparent bg-primary text-primary-foreground",
22
+ secondary: "border-transparent bg-secondary text-secondary-foreground",
23
+ destructive: "border-transparent bg-destructive text-white dark:bg-destructive/60",
24
+ outline: "border-border bg-background text-foreground",
25
+ ghost: "border-transparent bg-transparent text-muted-foreground",
26
+ success: "border-transparent bg-green-100 text-green-950 dark:bg-green-950 dark:text-green-100",
27
+ warning: "border-transparent bg-yellow-100 text-yellow-950 dark:bg-yellow-950 dark:text-yellow-100",
28
+ error: "border-transparent bg-red-100 text-red-950 dark:bg-red-950 dark:text-red-100",
29
+ neutral: "border-transparent bg-muted text-foreground",
30
+ info: "border-transparent bg-blue-100 text-blue-950 dark:bg-blue-950 dark:text-blue-100",
31
+ },
32
+ },
33
+ defaultVariants: {
34
+ variant: "neutral",
35
+ },
36
+ }
37
+ )
38
+
39
+ export interface PillProps
40
+ extends React.ComponentProps<"span">,
41
+ VariantProps<typeof pillVariants> {}
42
+
43
+ export function Pill({ className, variant = "neutral", ...props }: PillProps) {
44
+ return (
45
+ <span
46
+ data-slot="pill"
47
+ data-variant={variant}
48
+ className={cn(pillVariants({ variant }), className)}
49
+ {...props}
50
+ />
51
+ )
52
+ }
53
+
54
+ export interface StatusPillProps extends Omit<PillProps, "variant"> {
55
+ status: React.ReactNode
56
+ intent?: PillStatus
57
+ }
58
+
59
+ export function StatusPill({ status, intent = "neutral", children, ...props }: StatusPillProps) {
60
+ return (
61
+ <Pill data-slot="status-pill" variant={intent} {...props}>
62
+ {children ?? status}
63
+ </Pill>
64
+ )
65
+ }
66
+
67
+ export { pillVariants }
@@ -0,0 +1,68 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+
5
+ import { cn } from "../lib/utils"
6
+
7
+ export interface QuickSegmentProps
8
+ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "onSelect" | "value"> {
9
+ label: React.ReactNode
10
+ value: string
11
+ selected?: boolean
12
+ count?: number | string
13
+ description?: React.ReactNode
14
+ onSelect?: (value: string) => void
15
+ }
16
+
17
+ export function QuickSegment({
18
+ label,
19
+ value,
20
+ selected = false,
21
+ count,
22
+ description,
23
+ onSelect,
24
+ className,
25
+ type = "button",
26
+ ...props
27
+ }: QuickSegmentProps) {
28
+ return (
29
+ <button
30
+ data-slot="quick-segment"
31
+ data-selected={selected ? "true" : "false"}
32
+ type={type}
33
+ aria-pressed={selected}
34
+ className={cn(
35
+ "inline-flex min-h-8 items-center gap-2 rounded-full border px-3 py-1.5 text-sm font-medium transition-colors",
36
+ selected
37
+ ? "border-primary bg-primary text-primary-foreground shadow-sm"
38
+ : "border-border bg-background text-muted-foreground hover:bg-muted hover:text-foreground",
39
+ className
40
+ )}
41
+ onClick={(event) => {
42
+ props.onClick?.(event)
43
+ if (!event.defaultPrevented) onSelect?.(value)
44
+ }}
45
+ {...props}
46
+ >
47
+ <span data-slot="quick-segment-label">{label}</span>
48
+ {count !== undefined ? (
49
+ <span
50
+ data-slot="quick-segment-count"
51
+ className={cn(
52
+ "rounded-full px-1.5 py-0.5 text-[11px] leading-none",
53
+ selected
54
+ ? "bg-primary-foreground/20 text-primary-foreground"
55
+ : "bg-muted text-muted-foreground"
56
+ )}
57
+ >
58
+ {count}
59
+ </span>
60
+ ) : null}
61
+ {description ? (
62
+ <span data-slot="quick-segment-description" className="sr-only">
63
+ {description}
64
+ </span>
65
+ ) : null}
66
+ </button>
67
+ )
68
+ }
@@ -15,7 +15,7 @@ import {
15
15
  } from "lucide-react"
16
16
  import type { LucideIcon } from "lucide-react"
17
17
  import { FeedbackFooter } from "./feedback-primitives"
18
- import type { FeedbackChipTree, FeedbackSubmitData, PersistedFeedbackData } from "./feedback-primitives"
18
+ import type { FeedbackChipTree, FeedbackSubmitData } from "./feedback-primitives"
19
19
  import { cn } from "../lib/utils"
20
20
  import type {
21
21
  QueueItem,
@@ -266,7 +266,6 @@ function StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket
266
266
  const IconComponent = resolveIcon(signal.signalTypeName)
267
267
  const toneClass = tone ? (SIGNAL_TONE_CLASSES[tone] ?? DEFAULT_TONE_CLASS) : DEFAULT_TONE_CLASS
268
268
  const isCombined = signal.signalTypeName === "combined_signal" && signal.components && signal.components.length > 0
269
- const hasBalance = Boolean(signal.currentBalance || signal.balanceContext)
270
269
 
271
270
  const rowContent = (
272
271
  <>
@@ -305,26 +304,6 @@ function StructuredSignalRow({ item, bucketKey, signal, tone, onOpenSignalBucket
305
304
 
306
305
  {/* Slot 5: Chevron */}
307
306
  <ChevronRight className="h-3 w-3 shrink-0 text-muted-foreground/60 transition-transform group-hover:translate-x-0.5 group-hover:text-foreground/50" />
308
-
309
- {/* Balance context strip — spans full row below grid columns */}
310
- {hasBalance && (
311
- <div
312
- className="col-span-full mt-0.5 text-[10px] text-muted-foreground/70"
313
- data-testid="balance-context-strip"
314
- >
315
- {signal.currentBalance && (
316
- <span>
317
- Current balance <span className="font-medium text-muted-foreground">{signal.currentBalance}</span>
318
- </span>
319
- )}
320
- {signal.balanceContext && (
321
- <span>
322
- {signal.currentBalance ? " · " : ""}
323
- {signal.balanceContext}
324
- </span>
325
- )}
326
- </div>
327
- )}
328
307
  </>
329
308
  )
330
309
 
@@ -426,11 +405,9 @@ interface WhyCardProps {
426
405
  panelId: string
427
406
  onOpenSignalBucket?: ScoreWhyChipsProps["onOpenSignalBucket"]
428
407
  onBucketFeedback?: (bucketKey: string, data: FeedbackSubmitData) => void
429
- /** Persisted bucket-level feedback to hydrate from. */
430
- initialBucketFeedback?: PersistedFeedbackData | null
431
408
  }
432
409
 
433
- function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback, initialBucketFeedback }: WhyCardProps) {
410
+ function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketFeedback }: WhyCardProps) {
434
411
  const [showAll, setShowAll] = React.useState(false)
435
412
  const [bucketFeedback, setBucketFeedback] = React.useState<"positive" | "negative" | null>(null)
436
413
  const totalCount = bucket.signalCount ?? signals.length
@@ -511,8 +488,6 @@ function WhyCard({ bucket, signals, item, panelId, onOpenSignalBucket, onBucketF
511
488
  negativeChips={BUCKET_NEGATIVE_CHIPS}
512
489
  negativePrompt="Was this bucket useful?"
513
490
  positivePrompt="Thanks! What was useful about this bucket?"
514
- initialFeedback={initialBucketFeedback}
515
- feedbackKey={bucket.key}
516
491
  />
517
492
  </div>
518
493
  )}
@@ -586,7 +561,6 @@ export function ScoreWhyChips({
586
561
  panelId={selectedPanelId}
587
562
  onOpenSignalBucket={onOpenSignalBucket}
588
563
  onBucketFeedback={signalData.onBucketFeedback}
589
- initialBucketFeedback={signalData.initialBucketFeedback?.[selectedBucket.key]}
590
564
  />
591
565
  )}
592
566
  </div>
@@ -19,8 +19,8 @@ import {
19
19
  Info,
20
20
  } from "lucide-react"
21
21
  import { cn } from "../lib/utils"
22
- import { FeedbackFooter, InlineFeedbackControl } from "./feedback-primitives"
23
- import type { FeedbackChipTree, FeedbackSubmitData, PersistedFeedbackData } from "./feedback-primitives"
22
+ import { FeedbackFooter } from "./feedback-primitives"
23
+ import type { FeedbackChipTree, FeedbackSubmitData } from "./feedback-primitives"
24
24
  import type { SignalScoreUrgencyLabel } from "../prototype/prototype-config"
25
25
  import { getSignalScoreUrgencyLabel, scoreRangeForUrgency, SIGNAL_TONE_CLASSES } from "./score-why-chips"
26
26
 
@@ -58,12 +58,6 @@ export interface SignalPriorityPopoverProps {
58
58
  feedbackChips?: FeedbackChipTree[]
59
59
  onFeedbackSubmit?: (data: FeedbackSubmitData) => void
60
60
  className?: string
61
- /** Persisted factor-level feedback (keyed by factor key). */
62
- initialFactorFeedback?: Record<string, { type: "up" | "down"; detail: string; ownershipLabel?: string }>
63
- /** Callback when user submits factor-level feedback. */
64
- onFactorFeedback?: (factorKey: string, type: "up" | "down" | null, detail?: string) => void
65
- /** Persisted priority-level feedback for the footer. */
66
- initialPriorityFeedback?: PersistedFeedbackData | null
67
61
  }
68
62
 
69
63
  // ---------------------------------------------------------------------------
@@ -158,13 +152,7 @@ function DirectionIcon({ direction }: { direction: PriorityFactor["direction"] }
158
152
  // PriorityFactorRow
159
153
  // ---------------------------------------------------------------------------
160
154
 
161
- interface PriorityFactorRowProps {
162
- factor: PriorityFactor
163
- initialFeedback?: { type: "up" | "down"; detail: string; ownershipLabel?: string }
164
- onFactorFeedback?: (factorKey: string, type: "up" | "down" | null, detail?: string) => void
165
- }
166
-
167
- function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }: PriorityFactorRowProps) {
155
+ function PriorityFactorRow({ factor }: { factor: PriorityFactor }) {
168
156
  const IconComponent = FACTOR_ICONS[factor.icon] ?? Activity
169
157
  const toneClasses = TONE_ICON_CLASSES[factor.tone]
170
158
  const directionClasses = DIRECTION_CLASSES[factor.direction]
@@ -236,21 +224,6 @@ function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }: Priori
236
224
 
237
225
  {/* empty grid cell under score column */}
238
226
  <div />
239
-
240
- {/* Factor-level feedback row (spans icon + content columns) */}
241
- {onFactorFeedback && (
242
- <>
243
- <div />
244
- <div className="col-span-2 mt-1">
245
- <InlineFeedbackControl
246
- feedbackKey={factor.key}
247
- initialFeedback={initialFeedback}
248
- onFeedback={onFactorFeedback}
249
- testIdPrefix="factor"
250
- />
251
- </div>
252
- </>
253
- )}
254
227
  </div>
255
228
  )
256
229
  }
@@ -268,9 +241,6 @@ export function SignalPriorityPopover({
268
241
  feedbackChips,
269
242
  onFeedbackSubmit,
270
243
  className,
271
- initialFactorFeedback,
272
- onFactorFeedback,
273
- initialPriorityFeedback,
274
244
  }: SignalPriorityPopoverProps) {
275
245
  const urgencyLabel = getSignalScoreUrgencyLabel(score, providedLabel)
276
246
  const scoreRange = scoreRangeForUrgency(urgencyLabel)
@@ -282,9 +252,6 @@ export function SignalPriorityPopover({
282
252
  const triggerHover = URGENCY_TRIGGER_HOVER[urgencyLabel]
283
253
  const triggerOpen = URGENCY_TRIGGER_OPEN[urgencyLabel]
284
254
 
285
- // Derive a stable feedbackKey for the footer from score + urgencyLabel
286
- const footerFeedbackKey = `priority-${score}-${urgencyLabel}`
287
-
288
255
  return (
289
256
  <PopoverPrimitive.Root open={open} onOpenChange={setOpen}>
290
257
  <PopoverPrimitive.Trigger asChild>
@@ -365,12 +332,7 @@ export function SignalPriorityPopover({
365
332
  {/* Factor rows */}
366
333
  <div className="divide-y divide-border/40">
367
334
  {factors.map((factor) => (
368
- <PriorityFactorRow
369
- key={factor.key}
370
- factor={factor}
371
- initialFeedback={initialFactorFeedback?.[factor.key]}
372
- onFactorFeedback={onFactorFeedback}
373
- />
335
+ <PriorityFactorRow key={factor.key} factor={factor} />
374
336
  ))}
375
337
  </div>
376
338
  </>
@@ -387,8 +349,6 @@ export function SignalPriorityPopover({
387
349
  negativeChips={feedbackChips ?? DEFAULT_PRIORITY_FEEDBACK_CHIPS}
388
350
  positivePrompt="Thanks. Anything to keep about this score?"
389
351
  className="px-4 py-3"
390
- initialFeedback={initialPriorityFeedback}
391
- feedbackKey={footerFeedbackKey}
392
352
  />
393
353
  </div>
394
354
  )}
package/src/index.ts CHANGED
@@ -33,12 +33,13 @@ export * from "./components/data-table-filter"
33
33
  export * from "./components/data-table-quick-views"
34
34
  export * from "./components/data-table-toolbar"
35
35
  export * from "./components/detail-view"
36
+ export * from "./components/detail-drawer"
36
37
  export * from "./components/dialog"
37
38
  export * from "./components/dropdown-menu"
38
39
  export * from "./components/empty-state"
39
40
  export * from "./components/entity-panel"
40
- export { FeedbackFooter, FeedbackChipGroup, FeedbackInput, FeedbackActions, InlineFeedbackControl } from "./components/feedback-primitives"
41
- export type { FeedbackFooterProps, FeedbackChipTree, FeedbackChipGroupProps, FeedbackInputProps, FeedbackActionsProps, FeedbackSubmitData, PersistedFeedbackData, InlineFeedbackControlProps } from "./components/feedback-primitives"
41
+ export { FeedbackFooter, FeedbackChipGroup, FeedbackInput, FeedbackActions } from "./components/feedback-primitives"
42
+ export type { FeedbackFooterProps, FeedbackChipTree, FeedbackChipGroupProps, FeedbackInputProps, FeedbackActionsProps, FeedbackSubmitData } from "./components/feedback-primitives"
42
43
  export { SignalPriorityPopover } from "./components/signal-priority-popover"
43
44
  export type { SignalPriorityPopoverProps, PriorityFactor } from "./components/signal-priority-popover"
44
45
  export * from "./components/filter-chip"
@@ -47,6 +48,8 @@ export * from "./components/inbox-toolbar"
47
48
  export * from "./components/inline-banner"
48
49
  export * from "./components/input"
49
50
  export * from "./components/insights-filter-bar"
51
+ export * from "./components/days-open-cell"
52
+ export * from "./components/linked-entity-cell"
50
53
  export * from "./components/item-list"
51
54
  export * from "./components/item-list-display"
52
55
  export * from "./components/item-list-filter"
@@ -56,9 +59,11 @@ export * from "./components/label"
56
59
  export * from "./components/message"
57
60
  export * from "./components/metric-card"
58
61
  export * from "./components/performance-metrics-table"
62
+ export * from "./components/pill"
59
63
  export * from "./components/preview-list"
60
64
  export * from "./components/progress"
61
65
  export * from "./components/quick-action-chat-area"
66
+ export * from "./components/quick-segment"
62
67
  export {
63
68
  QuickActionModal,
64
69
  type QuickActionPriority,
@@ -16,7 +16,7 @@ import type { TimelineEvent } from "../components/timeline-activity"
16
16
  import type { ApprovalState } from "../components/signal-feedback-inline"
17
17
  import type { LucideIcon } from "lucide-react"
18
18
  import type { PriorityFactor } from "../components/signal-priority-popover"
19
- import type { FeedbackChipTree, FeedbackSubmitData, PersistedFeedbackData } from "../components/feedback-primitives"
19
+ import type { FeedbackChipTree, FeedbackSubmitData } from "../components/feedback-primitives"
20
20
 
21
21
  // ---------------------------------------------------------------------------
22
22
  // Shared
@@ -57,10 +57,6 @@ export interface SignalScoreExplanationSignal {
57
57
  counterparty?: string
58
58
  /** Component breakdown for combined signals. */
59
59
  components?: Array<{ type: string; count: number }>
60
- /** Current balance value (e.g., "$3.0M") for balance context strip. */
61
- currentBalance?: string
62
- /** Additional balance context text (e.g., "down from $23M"). */
63
- balanceContext?: string
64
60
  }
65
61
 
66
62
  export interface SignalScoreExplanationBucket {
@@ -101,12 +97,6 @@ export interface SignalScoreData {
101
97
  /** @deprecated The compact score UX no longer renders score-level thumbs by default. */
102
98
  initialScoreFeedback?: { type: "up" | "down"; pills: string[]; detail: string } | null
103
99
  initialFactorFeedback?: Record<string, { type: "up" | "down"; detail: string }>
104
- /** Factor-level feedback for the priority popover rows (keyed by factor key). */
105
- initialFactorPopoverFeedback?: Record<string, { type: "up" | "down"; detail: string; ownershipLabel?: string }>
106
- /** Persisted bucket-level feedback, keyed by bucket key. */
107
- initialBucketFeedback?: Record<string, PersistedFeedbackData>
108
- /** Persisted priority-level feedback for the popover footer. */
109
- initialPriorityFeedback?: PersistedFeedbackData | null
110
100
  /** Priority factors for the popover breakdown. */
111
101
  priorityFactors?: PriorityFactor[]
112
102
  /** Negative feedback chip tree for the priority popover. */
@@ -272,9 +272,6 @@ export function DetailView({
272
272
  metaText={undefined}
273
273
  feedbackChips={signalData.priorityFeedbackChips}
274
274
  onFeedbackSubmit={signalData.onPriorityFeedback}
275
- initialFactorFeedback={signalData.initialFactorPopoverFeedback}
276
- onFactorFeedback={signalData.onFactorFeedback}
277
- initialPriorityFeedback={signalData.initialPriorityFeedback}
278
275
  />
279
276
  {signalData.timeChipLabel && (
280
277
  <Badge variant="outline" title={signalData.timeChipDetail ?? undefined}>