@handled-ai/design-system 0.18.11 → 0.18.12

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 (40) hide show
  1. package/dist/components/account-contacts-popover.d.ts +5 -1
  2. package/dist/components/account-contacts-popover.js +25 -4
  3. package/dist/components/account-contacts-popover.js.map +1 -1
  4. package/dist/components/data-table-condition-filter.d.ts +2 -1
  5. package/dist/components/data-table-condition-filter.js +23 -41
  6. package/dist/components/data-table-condition-filter.js.map +1 -1
  7. package/dist/components/data-table-filter.js +8 -9
  8. package/dist/components/data-table-filter.js.map +1 -1
  9. package/dist/components/entity-panel.d.ts +2 -1
  10. package/dist/components/entity-panel.js +52 -45
  11. package/dist/components/entity-panel.js.map +1 -1
  12. package/dist/components/score-why-chips.d.ts +1 -1
  13. package/dist/components/signal-priority-popover.d.ts +1 -1
  14. package/dist/components/signal-priority-popover.js +4 -4
  15. package/dist/components/signal-priority-popover.js.map +1 -1
  16. package/dist/index.d.ts +2 -2
  17. package/dist/prototype/index.d.ts +1 -1
  18. package/dist/prototype/prototype-accounts-view.d.ts +1 -1
  19. package/dist/prototype/prototype-admin-view.d.ts +1 -1
  20. package/dist/prototype/prototype-config.d.ts +1 -1
  21. package/dist/prototype/prototype-inbox-view.d.ts +5 -3
  22. package/dist/prototype/prototype-inbox-view.js +11 -5
  23. package/dist/prototype/prototype-inbox-view.js.map +1 -1
  24. package/dist/prototype/prototype-insights-view.d.ts +1 -1
  25. package/dist/prototype/prototype-shell.d.ts +1 -1
  26. package/dist/{signal-priority-popover-BT6CPYNs.d.ts → signal-priority-popover-BEDoPsNE.d.ts} +6 -0
  27. package/package.json +1 -2
  28. package/src/components/__tests__/account-contacts-popover.test.tsx +79 -0
  29. package/src/components/__tests__/data-table-condition-filter.test.tsx +96 -0
  30. package/src/components/__tests__/data-table-filter.test.tsx +45 -0
  31. package/src/components/__tests__/entity-panel-header.test.tsx +44 -0
  32. package/src/components/__tests__/signal-priority-popover.test.tsx +30 -0
  33. package/src/components/account-contacts-popover.tsx +29 -1
  34. package/src/components/data-table-condition-filter.tsx +32 -47
  35. package/src/components/data-table-filter.tsx +7 -10
  36. package/src/components/entity-panel.tsx +56 -40
  37. package/src/components/signal-priority-popover.tsx +15 -4
  38. package/src/prototype/__tests__/detail-view-title-slots.test.tsx +15 -0
  39. package/src/prototype/prototype-config.ts +2 -0
  40. package/src/prototype/prototype-inbox-view.tsx +17 -5
@@ -135,14 +135,16 @@ export function EntityPanelHeader({
135
135
  icon,
136
136
  title,
137
137
  badgeLabel,
138
- subtitle: _subtitle,
138
+ subtitle,
139
139
  headerAction,
140
+ headerSecondaryAction,
140
141
  }: {
141
142
  icon?: React.ReactNode
142
143
  title: string
143
144
  badgeLabel?: string
144
145
  subtitle?: string
145
146
  headerAction?: React.ReactNode
147
+ headerSecondaryAction?: React.ReactNode
146
148
  }) {
147
149
  const { panelMode, cyclePanelMode, onClose } = useEntityPanel()
148
150
 
@@ -150,49 +152,63 @@ export function EntityPanelHeader({
150
152
  panelMode === 'default' ? 'Wide' : panelMode === 'wide' ? 'Fullscreen' : 'Exit fullscreen'
151
153
 
152
154
  return (
153
- <div className="flex items-center justify-between mb-3">
154
- <div className="flex items-center gap-2 min-w-0">
155
- {icon ?? <CalendarDays className="w-5 h-5 text-muted-foreground shrink-0" />}
156
- <h2 className="text-[16px] font-semibold text-foreground truncate">{title}</h2>
157
- {badgeLabel && (
158
- <Badge
159
- variant="outline"
160
- className="text-blue-600 border-blue-300 dark:border-blue-700 dark:text-blue-400 shadow-none px-2 py-0.5 text-[11px] font-medium shrink-0"
155
+ <div className="mb-3 space-y-2">
156
+ <div className="flex items-center justify-between">
157
+ <div className="flex items-center gap-2 min-w-0">
158
+ {icon ?? <CalendarDays className="w-5 h-5 text-muted-foreground shrink-0" />}
159
+ <h2 className="text-[16px] font-semibold text-foreground truncate">{title}</h2>
160
+ {badgeLabel && (
161
+ <Badge
162
+ variant="outline"
163
+ className="text-blue-600 border-blue-300 dark:border-blue-700 dark:text-blue-400 shadow-none px-2 py-0.5 text-[11px] font-medium shrink-0"
164
+ >
165
+ {badgeLabel}
166
+ </Badge>
167
+ )}
168
+ </div>
169
+ <div className="flex items-center gap-1 shrink-0 ml-4 text-muted-foreground">
170
+ {headerAction}
171
+ <button
172
+ type="button"
173
+ className="p-1.5 rounded-md hover:bg-secondary transition-colors"
174
+ title="Copy Link"
175
+ >
176
+ <LinkIcon className="w-4 h-4" />
177
+ </button>
178
+ <button
179
+ type="button"
180
+ onClick={cyclePanelMode}
181
+ className="p-1.5 rounded-md hover:bg-secondary transition-colors"
182
+ title={sizeButtonTitle}
161
183
  >
162
- {badgeLabel}
163
- </Badge>
164
- )}
184
+ {panelMode === 'fullscreen' ? (
185
+ <Minimize2 className="w-4 h-4" />
186
+ ) : (
187
+ <Maximize2 className="w-4 h-4" />
188
+ )}
189
+ </button>
190
+ <button
191
+ type="button"
192
+ onClick={onClose}
193
+ className="p-1.5 rounded-md hover:bg-secondary transition-colors"
194
+ title="Close"
195
+ >
196
+ <X className="w-4 h-4" />
197
+ </button>
198
+ </div>
165
199
  </div>
166
- <div className="flex items-center gap-1 shrink-0 ml-4 text-muted-foreground">
167
- {headerAction}
168
- <button
169
- type="button"
170
- className="p-1.5 rounded-md hover:bg-secondary transition-colors"
171
- title="Copy Link"
172
- >
173
- <LinkIcon className="w-4 h-4" />
174
- </button>
175
- <button
176
- type="button"
177
- onClick={cyclePanelMode}
178
- className="p-1.5 rounded-md hover:bg-secondary transition-colors"
179
- title={sizeButtonTitle}
180
- >
181
- {panelMode === 'fullscreen' ? (
182
- <Minimize2 className="w-4 h-4" />
200
+ {(subtitle || headerSecondaryAction) && (
201
+ <div className="flex flex-wrap items-center justify-between gap-x-3 gap-y-2">
202
+ {subtitle ? (
203
+ <p className="min-w-0 flex-1 text-xs text-muted-foreground">{subtitle}</p>
183
204
  ) : (
184
- <Maximize2 className="w-4 h-4" />
205
+ <div className="min-w-0 flex-1" />
185
206
  )}
186
- </button>
187
- <button
188
- type="button"
189
- onClick={onClose}
190
- className="p-1.5 rounded-md hover:bg-secondary transition-colors"
191
- title="Close"
192
- >
193
- <X className="w-4 h-4" />
194
- </button>
195
- </div>
207
+ {headerSecondaryAction ? (
208
+ <div className="flex shrink-0 items-center gap-2">{headerSecondaryAction}</div>
209
+ ) : null}
210
+ </div>
211
+ )}
196
212
  </div>
197
213
  )
198
214
  }
@@ -40,8 +40,12 @@ export interface PriorityFactor {
40
40
  tone: "alert" | "warn" | "info"
41
41
  /** Explicit semantic label - NOT inferred from score+weight. */
42
42
  direction: "raises" | "lowers" | "neutral"
43
+ /** Optional display label for the direction text. Keeps semantic direction icon/color unchanged. */
44
+ directionLabel?: string
43
45
  /** 0-100 */
44
46
  score: number
47
+ /** Optional display label rendered instead of the numeric score cell. */
48
+ displayValueLabel?: string
45
49
  /** Evidence text (e.g. "$3.4M moved in 8h - current treasury balance $0.00"). */
46
50
  rationale: string
47
51
  }
@@ -168,12 +172,13 @@ function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }: Priori
168
172
  const IconComponent = FACTOR_ICONS[factor.icon] ?? Activity
169
173
  const toneClasses = TONE_ICON_CLASSES[factor.tone]
170
174
  const directionClasses = DIRECTION_CLASSES[factor.direction]
171
- const directionLabel =
175
+ const directionLabel = factor.directionLabel ?? (
172
176
  factor.direction === "raises"
173
177
  ? "Raises"
174
178
  : factor.direction === "lowers"
175
179
  ? "Lowers"
176
180
  : "Neutral"
181
+ )
177
182
 
178
183
  return (
179
184
  <div
@@ -206,10 +211,16 @@ function PriorityFactorRow({ factor, initialFeedback, onFactorFeedback }: Priori
206
211
  </span>
207
212
  </div>
208
213
 
209
- {/* Score number */}
214
+ {/* Score number / display label */}
210
215
  <div className="flex items-center text-right">
211
- <span className="text-sm font-bold tabular-nums">{factor.score}</span>
212
- <span className="text-xs font-normal text-muted-foreground">/100</span>
216
+ {factor.displayValueLabel ? (
217
+ <span className="text-xs font-semibold text-foreground">{factor.displayValueLabel}</span>
218
+ ) : (
219
+ <>
220
+ <span className="text-sm font-bold tabular-nums">{factor.score}</span>
221
+ <span className="text-xs font-normal text-muted-foreground">/100</span>
222
+ </>
223
+ )}
213
224
  </div>
214
225
 
215
226
  {/* empty grid cell under icon column */}
@@ -62,4 +62,19 @@ describe("DetailView title slots", () => {
62
62
 
63
63
  expect(screen.getByRole("button", { name: "Quick action" })).toBeTruthy()
64
64
  })
65
+ it("renders a full-width title action row without replacing title extra or metadata", () => {
66
+ renderDetailView({
67
+ renderTitleExtra: () => <span data-testid="title-extra">Compact extra</span>,
68
+ renderTitleActionRow: () => (
69
+ <button type="button">Full-width quick action</button>
70
+ ),
71
+ renderMetadataExtra: () => <span data-testid="metadata-extra">Owner: Lee</span>,
72
+ })
73
+
74
+ expect(screen.getByTestId("title-extra").textContent).toBe("Compact extra")
75
+ expect(screen.getByRole("button", { name: "Full-width quick action" })).toBeTruthy()
76
+ expect(screen.getByTestId("metadata-extra").textContent).toBe("Owner: Lee")
77
+ expect(screen.getByTestId("priority-popover-trigger")).toBeTruthy()
78
+ })
79
+
65
80
  })
@@ -229,6 +229,8 @@ export interface InboxViewConfig {
229
229
  attentionCount?: number
230
230
  /** Render extra content inline with the detail title. */
231
231
  renderTitleExtra?: (item: QueueItem) => React.ReactNode
232
+ /** Render a full-width action row below the detail title row. */
233
+ renderTitleActionRow?: (item: QueueItem) => React.ReactNode
232
234
  /** Render supporting content below the detail title. */
233
235
  renderTitleSubtext?: (item: QueueItem) => React.ReactNode
234
236
  /** Sort options for the inbox. When provided, a sort dropdown is rendered in the split view toolbar. */
@@ -141,6 +141,8 @@ export interface DetailViewProps {
141
141
  lastActivityTime?: string
142
142
  /** Render extra content inline with the detail title. */
143
143
  renderTitleExtra?: (item: QueueItem) => React.ReactNode
144
+ /** Render a full-width action row below the detail title row. */
145
+ renderTitleActionRow?: (item: QueueItem) => React.ReactNode
144
146
  /** Render supporting content below the detail title. */
145
147
  renderTitleSubtext?: (item: QueueItem) => React.ReactNode
146
148
  /** Render extra metadata chips (e.g. assignee) inside the chips row below the title. */
@@ -321,6 +323,7 @@ export function DetailView({
321
323
  renderAfterScore,
322
324
  lastActivityTime,
323
325
  renderTitleExtra,
326
+ renderTitleActionRow,
324
327
  renderTitleSubtext,
325
328
  renderMetadataExtra,
326
329
  onOpenSignalBucket,
@@ -468,12 +471,19 @@ export function DetailView({
468
471
  <span className="text-xs text-muted-foreground">{item.company}</span>
469
472
  </div>
470
473
 
471
- <div className="mb-3 flex flex-wrap items-start gap-x-3 gap-y-2">
472
- <div className="min-w-0 flex-1">
473
- <h1 className="text-2xl font-bold tracking-tight text-foreground">{item.title}</h1>
474
- {renderTitleSubtext?.(item)}
474
+ <div className="mb-3 space-y-3">
475
+ <div className="flex flex-wrap items-start gap-x-3 gap-y-2">
476
+ <div className="min-w-0 flex-1">
477
+ <h1 className="text-2xl font-bold tracking-tight text-foreground">{item.title}</h1>
478
+ {renderTitleSubtext?.(item)}
479
+ </div>
480
+ {renderTitleExtra?.(item)}
475
481
  </div>
476
- {renderTitleExtra?.(item)}
482
+ {renderTitleActionRow ? (
483
+ <div className="flex w-full flex-wrap items-center gap-2">
484
+ {renderTitleActionRow(item)}
485
+ </div>
486
+ ) : null}
477
487
  </div>
478
488
 
479
489
  <div className="mb-6 flex flex-wrap items-center gap-2">
@@ -649,6 +659,7 @@ export function PrototypeInboxView({
649
659
  timelineSystemEventsConfig,
650
660
  attentionCount,
651
661
  renderTitleExtra,
662
+ renderTitleActionRow,
652
663
  renderTitleSubtext,
653
664
  sortOptions,
654
665
  activeSortId,
@@ -891,6 +902,7 @@ export function PrototypeInboxView({
891
902
  timelineSystemEventsConfig,
892
903
  attentionCount,
893
904
  renderTitleExtra,
905
+ renderTitleActionRow,
894
906
  renderTitleSubtext,
895
907
  onOpenSignalBucket,
896
908
  }