@handled-ai/design-system 0.16.0 → 0.16.1

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 (33) hide show
  1. package/dist/components/badge.d.ts +1 -1
  2. package/dist/components/button.d.ts +1 -1
  3. package/dist/components/data-table-condition-filter.d.ts +37 -0
  4. package/dist/components/data-table-condition-filter.js +407 -0
  5. package/dist/components/data-table-condition-filter.js.map +1 -0
  6. package/dist/components/data-table-filter.d.ts +12 -1
  7. package/dist/components/data-table-filter.js +92 -10
  8. package/dist/components/data-table-filter.js.map +1 -1
  9. package/dist/components/data-table-toolbar.d.ts +1 -0
  10. package/dist/components/data-table.d.ts +1 -0
  11. package/dist/components/tabs.d.ts +1 -1
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.js +1 -0
  14. package/dist/index.js.map +1 -1
  15. package/dist/prototype/index.d.ts +1 -0
  16. package/dist/prototype/prototype-accounts-view.d.ts +1 -0
  17. package/dist/prototype/prototype-admin-view.d.ts +1 -0
  18. package/dist/prototype/prototype-config.d.ts +1 -0
  19. package/dist/prototype/prototype-inbox-view.d.ts +4 -1
  20. package/dist/prototype/prototype-inbox-view.js +6 -1
  21. package/dist/prototype/prototype-inbox-view.js.map +1 -1
  22. package/dist/prototype/prototype-insights-view.d.ts +1 -0
  23. package/dist/prototype/prototype-shell.d.ts +1 -0
  24. package/package.json +1 -1
  25. package/src/components/__tests__/contact-list.test.tsx +1 -1
  26. package/src/components/__tests__/data-table-condition-filter.test.tsx +397 -0
  27. package/src/components/__tests__/data-table-filter-presets.test.tsx +1 -1
  28. package/src/components/__tests__/data-table-filter.test.tsx +270 -3
  29. package/src/components/data-table-condition-filter.tsx +513 -0
  30. package/src/components/data-table-filter.tsx +102 -4
  31. package/src/index.ts +1 -0
  32. package/src/prototype/__tests__/detail-view-attention.test.tsx +101 -0
  33. package/src/prototype/prototype-inbox-view.tsx +8 -0
@@ -0,0 +1,101 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import React from "react";
3
+ import { render, fireEvent } from "@testing-library/react";
4
+ import { DetailView, type DetailViewProps } from "../prototype-inbox-view";
5
+ import type { QueueItem, SignalScoreData } from "../prototype-config";
6
+ import type { TimelineEvent } from "../../components/timeline-activity";
7
+
8
+ // ---------------------------------------------------------------------------
9
+ // Helpers
10
+ // ---------------------------------------------------------------------------
11
+
12
+ const baseItem: QueueItem = {
13
+ id: "1",
14
+ title: "Test Signal",
15
+ details: "Some details",
16
+ statusColor: "green",
17
+ time: "2h ago",
18
+ company: "Acme Inc",
19
+ tag1: "renewal",
20
+ };
21
+
22
+ function makeSignalScore(): SignalScoreData {
23
+ return {
24
+ score: 75,
25
+ factors: [
26
+ { key: "trigger", label: "Trigger strength", score: 70, why: "Strong signal" },
27
+ ],
28
+ whyNow: "Strong signals detected.",
29
+ evidence: ["Evidence line 1"],
30
+ confidence: 80,
31
+ };
32
+ }
33
+
34
+ const sampleTimelineEvents: TimelineEvent[] = [
35
+ { id: "t1", icon: React.createElement("span", null, "📧"), title: "Email sent", time: "1h ago" },
36
+ { id: "t2", icon: React.createElement("span", null, "📞"), title: "Call logged", time: "3h ago" },
37
+ ];
38
+
39
+ function baseProps(overrides: Partial<DetailViewProps> = {}): DetailViewProps {
40
+ return {
41
+ item: baseItem,
42
+ sections: { signalBrief: true, suggestedActions: false, timeline: true },
43
+ getSignalScore: () => makeSignalScore(),
44
+ buildSuggestedActions: () => [],
45
+ buildSourceItems: () => [],
46
+ getTimelineEvents: () => sampleTimelineEvents,
47
+ accountContacts: [],
48
+ emailSignature: "",
49
+ iconMap: {},
50
+ ...overrides,
51
+ };
52
+ }
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Tests
56
+ // ---------------------------------------------------------------------------
57
+
58
+ describe("DetailView attentionCount", () => {
59
+ it("renders attention pill with count when attentionCount > 0 and timeline collapsed", () => {
60
+ const props = baseProps({ attentionCount: 3 });
61
+ const { container } = render(<DetailView {...props} />);
62
+ const pill = container.querySelector("span.inline-flex");
63
+ expect(pill).not.toBeNull();
64
+ expect(pill!.textContent).toContain("3");
65
+ expect(pill!.textContent).toContain("new");
66
+ expect(pill!.className).toContain("bg-destructive/10");
67
+ });
68
+
69
+ it("does NOT render pill when attentionCount is 0", () => {
70
+ const props = baseProps({ attentionCount: 0 });
71
+ const { container } = render(<DetailView {...props} />);
72
+ const pill = container.querySelector("span.inline-flex");
73
+ expect(pill).toBeNull();
74
+ });
75
+
76
+ it("does NOT render pill when attentionCount is undefined", () => {
77
+ const props = baseProps({ attentionCount: undefined });
78
+ const { container } = render(<DetailView {...props} />);
79
+ const pill = container.querySelector("span.inline-flex");
80
+ expect(pill).toBeNull();
81
+ });
82
+
83
+ it("does NOT render pill when timeline is expanded", () => {
84
+ const props = baseProps({ attentionCount: 5 });
85
+ const { container } = render(<DetailView {...props} />);
86
+
87
+ // Pill should be visible while collapsed
88
+ let pill = container.querySelector("span.inline-flex");
89
+ expect(pill).not.toBeNull();
90
+ expect(pill!.textContent).toContain("5");
91
+
92
+ // Click the timeline header button to expand
93
+ const timelineButton = container.querySelector("button.group\\/timeline") as HTMLElement;
94
+ expect(timelineButton).not.toBeNull();
95
+ fireEvent.click(timelineButton);
96
+
97
+ // After expanding, pill should be gone
98
+ pill = container.querySelector("span.inline-flex");
99
+ expect(pill).toBeNull();
100
+ });
101
+ });
@@ -142,6 +142,8 @@ export interface DetailViewProps {
142
142
  approveButtonIconUrl?: string
143
143
  opportunityPreview?: OpportunityPreview
144
144
  onRequestApproval?: () => Promise<void>
145
+ /** Number of important/attention-worthy events to highlight on the collapsed timeline header. */
146
+ attentionCount?: number
145
147
  }
146
148
 
147
149
  export function DetailView({
@@ -172,6 +174,7 @@ export function DetailView({
172
174
  approveButtonIconUrl,
173
175
  opportunityPreview,
174
176
  onRequestApproval,
177
+ attentionCount,
175
178
  }: DetailViewProps) {
176
179
  const [evidenceExpanded, setEvidenceExpanded] = React.useState(false)
177
180
  const [showTimeline, setShowTimeline] = React.useState(false)
@@ -422,6 +425,11 @@ export function DetailView({
422
425
  >
423
426
  <div className="flex items-center gap-2">
424
427
  <h3 className="text-xs font-bold text-muted-foreground uppercase tracking-wider group-hover/timeline:text-foreground transition-colors">Activity timeline</h3>
428
+ {!showTimeline && attentionCount != null && attentionCount > 0 && (
429
+ <span className="inline-flex items-center gap-1 rounded-full bg-destructive/10 px-1.5 py-0.5 text-[10px] font-semibold text-destructive border border-destructive/20">
430
+ {attentionCount} new
431
+ </span>
432
+ )}
425
433
  {!showTimeline && (lastActivityTime || (timelineEvents.length > 0 && timelineEvents[0].time)) && (
426
434
  <span className="text-[11px] text-muted-foreground/60">
427
435
  &middot; Last activity {lastActivityTime ?? timelineEvents[0]?.time ?? ''}