@handled-ai/design-system 0.20.1 → 0.20.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/conversation-panel.d.ts +1 -1
- package/dist/components/conversation-panel.js +282 -15
- package/dist/components/conversation-panel.js.map +1 -1
- package/dist/components/owner-chips.d.ts +3 -4
- package/dist/components/owner-chips.js +77 -41
- package/dist/components/owner-chips.js.map +1 -1
- package/dist/components/timeline-activity.d.ts +4 -2
- package/dist/components/timeline-activity.js +366 -154
- package/dist/components/timeline-activity.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/prototype/prototype-inbox-view.js +10 -8
- package/dist/prototype/prototype-inbox-view.js.map +1 -1
- package/package.json +1 -1
- package/src/components/__tests__/conversation-panel.test.tsx +276 -0
- package/src/components/__tests__/owner-chips.test.tsx +137 -17
- package/src/components/__tests__/timeline-activity.test.tsx +92 -1
- package/src/components/conversation-panel.tsx +358 -21
- package/src/components/owner-chips.tsx +98 -63
- package/src/components/timeline-activity.tsx +452 -160
- package/src/prototype/__tests__/detail-view-case-panel-v2.test.tsx +6 -8
- package/src/prototype/__tests__/detail-view-timeline-system-events.test.tsx +16 -2
- package/src/prototype/prototype-inbox-view.tsx +14 -15
|
@@ -120,8 +120,6 @@ describe("DetailView case-panel-v2 section layout", () => {
|
|
|
120
120
|
screen.getByText("Signal brief copy: account activity needs review."),
|
|
121
121
|
screen.getByText("Metadata marker"),
|
|
122
122
|
screen.getByText("Before-score status marker"),
|
|
123
|
-
screen.getByText("The why"),
|
|
124
|
-
screen.getByText("The why copy: customer replied after the escalation window opened."),
|
|
125
123
|
screen.getByText("Cash movement"),
|
|
126
124
|
screen.getByText("Approve action"),
|
|
127
125
|
screen.getByText("Opportunity marker"),
|
|
@@ -154,14 +152,14 @@ describe("DetailView case-panel-v2 section layout", () => {
|
|
|
154
152
|
)
|
|
155
153
|
})
|
|
156
154
|
|
|
157
|
-
it("renders signal brief and
|
|
155
|
+
it("renders signal brief and chip-backed Why section without a separate The why block", () => {
|
|
158
156
|
renderDetailView({ sectionLayout: "case-panel-v2" })
|
|
159
157
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
)
|
|
158
|
+
expect(screen.getByText("Signal brief copy: account activity needs review.")).toBeTruthy()
|
|
159
|
+
expect(screen.queryByText("The why")).toBeNull()
|
|
160
|
+
expect(screen.queryByText("The why copy: customer replied after the escalation window opened.")).toBeNull()
|
|
161
|
+
expect(screen.getByText("Why")).toBeTruthy()
|
|
162
|
+
expect(screen.getByText("Cash movement")).toBeTruthy()
|
|
165
163
|
})
|
|
166
164
|
|
|
167
165
|
it("falls back to whyNow in the brief and suppresses the separate The why block when signalBrief is missing", () => {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/vitest"
|
|
1
2
|
import { describe, it, expect, vi, beforeEach } from "vitest"
|
|
2
3
|
import React from "react"
|
|
3
4
|
import { render, fireEvent } from "@testing-library/react"
|
|
@@ -181,14 +182,19 @@ describe("DetailView timeline system-events toggle", () => {
|
|
|
181
182
|
'[data-testid="system-events-toggle"]',
|
|
182
183
|
) as HTMLElement
|
|
183
184
|
fireEvent.click(toggle)
|
|
185
|
+
expect(toggle).toHaveAttribute("aria-pressed", "true")
|
|
184
186
|
expect(container.textContent).toContain("Score updated +3")
|
|
185
187
|
|
|
186
188
|
// Collapse the timeline
|
|
187
189
|
expandTimeline(container)
|
|
190
|
+
expect(toggle).toHaveAttribute("aria-pressed", "true")
|
|
191
|
+
expect(container.textContent).not.toContain("Score updated +3")
|
|
192
|
+
|
|
188
193
|
// Re-expand
|
|
189
194
|
expandTimeline(container)
|
|
190
195
|
|
|
191
196
|
// System events should still be visible (toggle didn't change)
|
|
197
|
+
expect(toggle).toHaveAttribute("aria-pressed", "true")
|
|
192
198
|
expect(container.textContent).toContain("Score updated +3")
|
|
193
199
|
})
|
|
194
200
|
|
|
@@ -203,15 +209,20 @@ describe("DetailView timeline system-events toggle", () => {
|
|
|
203
209
|
const badge = container.querySelector('[data-testid="hidden-count-badge"]')
|
|
204
210
|
expect(badge).not.toBeNull()
|
|
205
211
|
expect(badge?.textContent).toBe("2")
|
|
212
|
+
expect(badge).toHaveClass("min-w-[18px]")
|
|
206
213
|
})
|
|
207
214
|
|
|
208
|
-
it("calls localStorage.setItem when toggle changes", () => {
|
|
215
|
+
it("calls localStorage.setItem when toggle changes and shows a stronger pressed style", () => {
|
|
209
216
|
const { container } = render(<DetailView {...baseProps()} />)
|
|
210
217
|
expandTimeline(container)
|
|
211
218
|
const toggle = container.querySelector(
|
|
212
219
|
'[data-testid="system-events-toggle"]',
|
|
213
220
|
) as HTMLElement
|
|
221
|
+
expect(toggle).toHaveAttribute("aria-pressed", "false")
|
|
214
222
|
fireEvent.click(toggle)
|
|
223
|
+
expect(toggle).toHaveAttribute("aria-pressed", "true")
|
|
224
|
+
expect(toggle.className).toContain("border-primary/40")
|
|
225
|
+
expect(toggle.className).toContain("bg-primary/10")
|
|
215
226
|
expect(localStorageMock.setItem).toHaveBeenCalledWith(
|
|
216
227
|
"test-show-score-changes",
|
|
217
228
|
"true",
|
|
@@ -301,12 +312,15 @@ describe("DetailView timeline system-events toggle", () => {
|
|
|
301
312
|
expect(toggle).toBeNull()
|
|
302
313
|
})
|
|
303
314
|
|
|
304
|
-
it("shows footer hint when timeline is expanded and system events are hidden", () => {
|
|
315
|
+
it("shows footer hint below the case-panel timeline when timeline is expanded and system events are hidden", () => {
|
|
305
316
|
const { container } = render(<DetailView {...baseProps()} />)
|
|
306
317
|
expandTimeline(container)
|
|
318
|
+
const timeline = container.querySelector('[data-variant="case-panel"]')
|
|
307
319
|
const hint = container.querySelector('[data-testid="timeline-footer-hint"]')
|
|
320
|
+
expect(timeline).not.toBeNull()
|
|
308
321
|
expect(hint).not.toBeNull()
|
|
309
322
|
expect(hint?.textContent).toBe("Score changes are hidden.")
|
|
323
|
+
expect(timeline?.compareDocumentPosition(hint as Node)).toBe(Node.DOCUMENT_POSITION_FOLLOWING)
|
|
310
324
|
})
|
|
311
325
|
|
|
312
326
|
it("shows visible footer hint with count when system events are shown", () => {
|
|
@@ -48,6 +48,7 @@ import {
|
|
|
48
48
|
type SuggestedContact,
|
|
49
49
|
} from "../components/suggested-actions"
|
|
50
50
|
import { TimelineActivity, type TimelineEvent } from "../components/timeline-activity"
|
|
51
|
+
import { cn } from "../lib/utils"
|
|
51
52
|
import type {
|
|
52
53
|
QueueItem,
|
|
53
54
|
InboxViewConfig,
|
|
@@ -296,13 +297,23 @@ function TimelineSection({
|
|
|
296
297
|
<button
|
|
297
298
|
type="button"
|
|
298
299
|
onClick={() => setShowSystemEvents((prev) => !prev)}
|
|
299
|
-
className=
|
|
300
|
+
className={cn(
|
|
301
|
+
"flex shrink-0 cursor-pointer items-center gap-1.5 rounded-full border px-2.5 py-1 text-[11px] font-medium transition-colors hover:text-foreground",
|
|
302
|
+
showSystemEvents
|
|
303
|
+
? "border-primary/40 bg-primary/10 text-primary shadow-sm hover:bg-primary/15"
|
|
304
|
+
: "border-border bg-background text-muted-foreground hover:bg-muted/40"
|
|
305
|
+
)}
|
|
300
306
|
aria-pressed={showSystemEvents}
|
|
301
307
|
data-testid="system-events-toggle"
|
|
302
308
|
>
|
|
303
309
|
{toggleLabel}
|
|
304
310
|
<span
|
|
305
|
-
className=
|
|
311
|
+
className={cn(
|
|
312
|
+
"inline-flex min-w-[18px] items-center justify-center rounded-full px-1.5 text-[10px] font-semibold tabular-nums",
|
|
313
|
+
showSystemEvents
|
|
314
|
+
? "bg-primary/15 text-primary ring-1 ring-primary/30"
|
|
315
|
+
: "bg-muted text-muted-foreground ring-1 ring-border/70"
|
|
316
|
+
)}
|
|
306
317
|
data-testid="hidden-count-badge"
|
|
307
318
|
>
|
|
308
319
|
{hiddenCount}
|
|
@@ -314,7 +325,7 @@ function TimelineSection({
|
|
|
314
325
|
{/* Timeline body */}
|
|
315
326
|
{showTimeline && visibleEvents.length > 0 && (
|
|
316
327
|
<div className="mt-3">
|
|
317
|
-
<TimelineActivity events={visibleEvents} />
|
|
328
|
+
<TimelineActivity events={visibleEvents} variant="case-panel" />
|
|
318
329
|
</div>
|
|
319
330
|
)}
|
|
320
331
|
|
|
@@ -491,9 +502,6 @@ export function DetailView({
|
|
|
491
502
|
: "hover:bg-muted/50"
|
|
492
503
|
|
|
493
504
|
const isCasePanelV2 = sectionLayout === "case-panel-v2"
|
|
494
|
-
const v2WhyText = signalData.signalBrief
|
|
495
|
-
? signalData.whyNow || signalData.urgencyExplanation
|
|
496
|
-
: undefined
|
|
497
505
|
|
|
498
506
|
// The metadata chips row (priority · deadline · account · renderMetadataExtra). Rendered above
|
|
499
507
|
// the brief by default, or beneath it when `metadataLayout === "below-brief"` (case-panel redesign).
|
|
@@ -713,15 +721,6 @@ export function DetailView({
|
|
|
713
721
|
{/* Before-score content slot (e.g. status/attention pills) */}
|
|
714
722
|
{renderBeforeScore?.(item)}
|
|
715
723
|
|
|
716
|
-
{v2WhyText ? (
|
|
717
|
-
<div className="mb-8">
|
|
718
|
-
<h3 className="text-xs font-bold text-muted-foreground uppercase tracking-wider mb-3">The why</h3>
|
|
719
|
-
<p className="text-sm text-foreground/90 leading-relaxed mb-4">
|
|
720
|
-
{v2WhyText}
|
|
721
|
-
</p>
|
|
722
|
-
</div>
|
|
723
|
-
) : null}
|
|
724
|
-
|
|
725
724
|
<div className="mb-8">
|
|
726
725
|
<ScoreWhyChips
|
|
727
726
|
item={item}
|