@handled-ai/design-system 0.18.22 → 0.18.24

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 (31) hide show
  1. package/dist/components/case-panel-activity-timeline.d.ts +100 -0
  2. package/dist/components/case-panel-activity-timeline.js +270 -0
  3. package/dist/components/case-panel-activity-timeline.js.map +1 -0
  4. package/dist/components/case-panel-detail.d.ts +60 -0
  5. package/dist/components/case-panel-detail.js +129 -0
  6. package/dist/components/case-panel-detail.js.map +1 -0
  7. package/dist/components/case-panel-email-composer.d.ts +61 -0
  8. package/dist/components/case-panel-email-composer.js +304 -0
  9. package/dist/components/case-panel-email-composer.js.map +1 -0
  10. package/dist/components/case-panel-why.d.ts +35 -0
  11. package/dist/components/case-panel-why.js +149 -0
  12. package/dist/components/case-panel-why.js.map +1 -0
  13. package/dist/components/contextual-quick-action-launcher.d.ts +7 -3
  14. package/dist/components/contextual-quick-action-launcher.js +99 -27
  15. package/dist/components/contextual-quick-action-launcher.js.map +1 -1
  16. package/dist/components/pill.d.ts +1 -1
  17. package/dist/index.d.ts +5 -1
  18. package/dist/index.js +4 -0
  19. package/dist/index.js.map +1 -1
  20. package/package.json +1 -1
  21. package/src/components/__tests__/case-panel-activity-timeline.test.tsx +152 -0
  22. package/src/components/__tests__/case-panel-detail.test.tsx +138 -0
  23. package/src/components/__tests__/case-panel-email-composer.test.tsx +171 -0
  24. package/src/components/__tests__/case-panel-why.test.tsx +152 -0
  25. package/src/components/__tests__/contextual-quick-action-launcher.test.tsx +90 -0
  26. package/src/components/case-panel-activity-timeline.tsx +414 -0
  27. package/src/components/case-panel-detail.tsx +228 -0
  28. package/src/components/case-panel-email-composer.tsx +341 -0
  29. package/src/components/case-panel-why.tsx +214 -0
  30. package/src/components/contextual-quick-action-launcher.tsx +92 -15
  31. package/src/index.ts +4 -0
@@ -7,10 +7,13 @@ interface ContextualQuickActionItem {
7
7
  icon?: React.ReactNode;
8
8
  disabled?: boolean;
9
9
  disabledReason?: string;
10
+ meta?: React.ReactNode;
10
11
  }
12
+ type ContextualQuickActionLauncherVariant = "default" | "case-panel";
11
13
  interface ContextualQuickActionContextLabelProps {
12
14
  contextLabel: string;
13
15
  contextSecondary?: string;
16
+ variant?: ContextualQuickActionLauncherVariant;
14
17
  className?: string;
15
18
  }
16
19
  interface ContextualQuickActionLauncherProps {
@@ -21,12 +24,13 @@ interface ContextualQuickActionLauncherProps {
21
24
  onBrowseAll?: () => void;
22
25
  showHint?: boolean;
23
26
  align?: "start" | "end";
27
+ variant?: ContextualQuickActionLauncherVariant;
24
28
  className?: string;
25
29
  open?: boolean;
26
30
  defaultOpen?: boolean;
27
31
  onOpenChange?: (open: boolean) => void;
28
32
  }
29
- declare function ContextualQuickActionContextLabel({ contextLabel, contextSecondary, className, }: ContextualQuickActionContextLabelProps): React.JSX.Element;
30
- declare function ContextualQuickActionLauncher({ contextLabel, contextSecondary, items, onSelect, onBrowseAll, showHint, align, className, open, defaultOpen, onOpenChange, }: ContextualQuickActionLauncherProps): React.JSX.Element;
33
+ declare function ContextualQuickActionContextLabel({ contextLabel, contextSecondary, variant, className, }: ContextualQuickActionContextLabelProps): React.JSX.Element;
34
+ declare function ContextualQuickActionLauncher({ contextLabel, contextSecondary, items, onSelect, onBrowseAll, showHint, align, variant, className, open, defaultOpen, onOpenChange, }: ContextualQuickActionLauncherProps): React.JSX.Element;
31
35
 
32
- export { ContextualQuickActionContextLabel, type ContextualQuickActionContextLabelProps, type ContextualQuickActionItem, ContextualQuickActionLauncher, type ContextualQuickActionLauncherProps };
36
+ export { ContextualQuickActionContextLabel, type ContextualQuickActionContextLabelProps, type ContextualQuickActionItem, ContextualQuickActionLauncher, type ContextualQuickActionLauncherProps, type ContextualQuickActionLauncherVariant };
@@ -3,7 +3,7 @@
3
3
  "use client";
4
4
  import { jsx, jsxs } from "react/jsx-runtime";
5
5
  import * as React from "react";
6
- import { ArrowRight, ChevronDown, Zap } from "lucide-react";
6
+ import { ChevronDown, Zap } from "lucide-react";
7
7
  import { cn } from "../lib/utils.js";
8
8
  import {
9
9
  DropdownMenu,
@@ -15,20 +15,38 @@ import {
15
15
  function ContextualQuickActionContextLabel({
16
16
  contextLabel,
17
17
  contextSecondary,
18
+ variant = "default",
18
19
  className
19
20
  }) {
21
+ const isCasePanel = variant === "case-panel";
20
22
  return /* @__PURE__ */ jsxs(
21
23
  "div",
22
24
  {
23
25
  "data-slot": "contextual-quick-action-context-label",
26
+ "data-variant": variant,
24
27
  className: cn(
25
- "-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground",
28
+ isCasePanel ? "-mx-2 -mt-2 mb-1 flex items-center gap-1.5 whitespace-nowrap border-b px-3 py-2.5 text-[13px] text-muted-foreground" : "-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground",
26
29
  className
27
30
  ),
28
31
  children: [
29
- /* @__PURE__ */ jsx(Zap, { className: "h-3 w-3 shrink-0", strokeWidth: 2.25, "aria-hidden": "true" }),
32
+ /* @__PURE__ */ jsx(
33
+ Zap,
34
+ {
35
+ className: cn(isCasePanel ? "h-3.5 w-3.5 shrink-0" : "h-3 w-3 shrink-0"),
36
+ strokeWidth: 2.25,
37
+ "aria-hidden": "true"
38
+ }
39
+ ),
30
40
  /* @__PURE__ */ jsx("span", { children: "Acting on" }),
31
- /* @__PURE__ */ jsx("strong", { className: "max-w-[180px] truncate font-semibold text-foreground", children: contextLabel }),
41
+ /* @__PURE__ */ jsx(
42
+ "strong",
43
+ {
44
+ className: cn(
45
+ isCasePanel ? "max-w-[260px] truncate font-semibold text-foreground" : "max-w-[180px] truncate font-semibold text-foreground"
46
+ ),
47
+ children: contextLabel
48
+ }
49
+ ),
32
50
  contextSecondary ? /* @__PURE__ */ jsxs("span", { className: "min-w-0 truncate text-muted-foreground", children: [
33
51
  "\xB7 ",
34
52
  contextSecondary
@@ -48,12 +66,14 @@ function ContextualQuickActionLauncher({
48
66
  onBrowseAll,
49
67
  showHint = false,
50
68
  align = "start",
69
+ variant = "default",
51
70
  className,
52
71
  open,
53
72
  defaultOpen,
54
73
  onOpenChange
55
74
  }) {
56
75
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen != null ? defaultOpen : false);
76
+ const isCasePanel = variant === "case-panel";
57
77
  const isControlled = open !== void 0;
58
78
  const isOpen = isControlled ? open : uncontrolledOpen;
59
79
  const handleOpenChange = React.useCallback(
@@ -122,13 +142,16 @@ function ContextualQuickActionLauncher({
122
142
  align,
123
143
  side: "bottom",
124
144
  sideOffset: 6,
125
- className: "pointer-events-auto w-[308px] rounded-[10px] p-1.5 text-[12.5px] shadow-[0_12px_28px_rgba(0,0,0,0.12),0_2px_6px_rgba(0,0,0,0.04)]",
145
+ className: cn(
146
+ isCasePanel ? "pointer-events-auto w-[432px] rounded-[13px] border border-border bg-popover p-2 text-[13px] shadow-[0_18px_44px_rgba(0,0,0,0.14),0_2px_10px_rgba(0,0,0,0.06)]" : "pointer-events-auto w-[308px] rounded-[10px] p-1.5 text-[12.5px] shadow-[0_12px_28px_rgba(0,0,0,0.12),0_2px_6px_rgba(0,0,0,0.04)]"
147
+ ),
126
148
  children: [
127
149
  /* @__PURE__ */ jsx(
128
150
  ContextualQuickActionContextLabel,
129
151
  {
130
152
  contextLabel,
131
- contextSecondary
153
+ contextSecondary,
154
+ variant
132
155
  }
133
156
  ),
134
157
  items.map((item) => {
@@ -139,7 +162,7 @@ function ContextualQuickActionLauncher({
139
162
  disabled: item.disabled,
140
163
  onSelect: (event) => handleSelect(item, event),
141
164
  className: cn(
142
- "flex cursor-pointer items-center gap-2.5 rounded-md px-2 py-2 text-left outline-none focus:bg-accent data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100",
165
+ isCasePanel ? "grid cursor-pointer grid-cols-[34px_minmax(0,1fr)_auto] items-center gap-3 rounded-[9px] px-2.5 py-[9px] text-left outline-none focus:bg-muted/60 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100" : "flex cursor-pointer items-center gap-2.5 rounded-md px-2 py-2 text-left outline-none focus:bg-accent data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100",
143
166
  item.disabled && "text-muted-foreground"
144
167
  ),
145
168
  children: [
@@ -148,38 +171,87 @@ function ContextualQuickActionLauncher({
148
171
  {
149
172
  "data-slot": "contextual-quick-action-item-icon",
150
173
  className: cn(
151
- "flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground",
174
+ isCasePanel ? "flex h-[34px] w-[34px] shrink-0 items-center justify-center rounded-[9px] border border-border/70 bg-muted/60 text-foreground [&_svg]:h-[18px] [&_svg]:w-[18px]" : "flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground",
152
175
  item.disabled && "opacity-60"
153
176
  ),
154
177
  children: (_a = item.icon) != null ? _a : /* @__PURE__ */ jsx(DefaultActionIcon, {})
155
178
  }
156
179
  ),
157
180
  /* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
158
- /* @__PURE__ */ jsx("span", { className: "block truncate text-[12.5px] font-medium leading-tight text-current", children: item.label }),
159
- item.description ? /* @__PURE__ */ jsx("span", { className: "mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground", children: item.description }) : null
181
+ /* @__PURE__ */ jsx(
182
+ "span",
183
+ {
184
+ className: cn(
185
+ isCasePanel ? "block truncate text-[13.5px] font-semibold leading-tight text-current" : "block truncate text-[12.5px] font-medium leading-tight text-current"
186
+ ),
187
+ children: item.label
188
+ }
189
+ ),
190
+ item.description ? /* @__PURE__ */ jsx(
191
+ "span",
192
+ {
193
+ className: cn(
194
+ isCasePanel ? "mt-1 block truncate text-[12px] leading-tight text-muted-foreground" : "mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground"
195
+ ),
196
+ children: item.description
197
+ }
198
+ ) : null
160
199
  ] }),
161
- item.disabled && item.disabledReason ? /* @__PURE__ */ jsx("span", { className: "ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80", children: item.disabledReason }) : null
200
+ item.disabled && item.disabledReason ? /* @__PURE__ */ jsx(
201
+ "span",
202
+ {
203
+ "data-slot": "contextual-quick-action-item-disabled-meta",
204
+ className: cn(
205
+ isCasePanel ? "ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70" : "ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80"
206
+ ),
207
+ children: item.disabledReason
208
+ }
209
+ ) : item.meta ? /* @__PURE__ */ jsx(
210
+ "span",
211
+ {
212
+ "data-slot": "contextual-quick-action-item-meta",
213
+ className: cn(
214
+ isCasePanel ? "ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70" : "ml-auto shrink-0 text-[10.5px] text-muted-foreground/80"
215
+ ),
216
+ children: item.meta
217
+ }
218
+ ) : null
162
219
  ]
163
220
  },
164
221
  item.id
165
222
  );
166
223
  }),
167
- /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: "-mx-1.5 my-1" }),
168
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground", children: [
169
- /* @__PURE__ */ jsxs(
170
- "button",
171
- {
172
- type: "button",
173
- className: "inline-flex items-center gap-1 font-medium text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
174
- onClick: handleBrowseAll,
175
- children: [
176
- "Browse all actions",
177
- /* @__PURE__ */ jsx(ArrowRight, { className: "h-3 w-3", strokeWidth: 2, "aria-hidden": "true" })
178
- ]
179
- }
180
- ),
181
- /* @__PURE__ */ jsx("span", { className: "inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground", children: "\u2318K" })
182
- ] })
224
+ /* @__PURE__ */ jsx(DropdownMenuSeparator, { className: cn(isCasePanel ? "-mx-2 mt-1 mb-1" : "-mx-1.5 my-1") }),
225
+ /* @__PURE__ */ jsxs(
226
+ "div",
227
+ {
228
+ className: cn(
229
+ isCasePanel ? "flex items-center justify-between whitespace-nowrap px-2.5 py-2 text-[13px] text-muted-foreground" : "flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground"
230
+ ),
231
+ children: [
232
+ /* @__PURE__ */ jsx(
233
+ "button",
234
+ {
235
+ type: "button",
236
+ className: cn(
237
+ isCasePanel ? "inline-flex items-center gap-1 font-semibold text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2" : "inline-flex items-center gap-1 font-medium text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
238
+ ),
239
+ onClick: handleBrowseAll,
240
+ children: "Browse all actions"
241
+ }
242
+ ),
243
+ /* @__PURE__ */ jsx(
244
+ "span",
245
+ {
246
+ className: cn(
247
+ isCasePanel ? "inline-flex items-center rounded-[5px] border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] font-medium leading-none text-muted-foreground" : "inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground"
248
+ ),
249
+ children: "\u2318K"
250
+ }
251
+ )
252
+ ]
253
+ }
254
+ )
183
255
  ]
184
256
  }
185
257
  )
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/contextual-quick-action-launcher.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ArrowRight, ChevronDown, Zap } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"./dropdown-menu\"\n\nexport interface ContextualQuickActionItem {\n id: string\n label: string\n description?: string\n icon?: React.ReactNode\n disabled?: boolean\n disabledReason?: string\n}\n\nexport interface ContextualQuickActionContextLabelProps {\n contextLabel: string\n contextSecondary?: string\n className?: string\n}\n\nexport interface ContextualQuickActionLauncherProps {\n contextLabel: string\n contextSecondary?: string\n items: ContextualQuickActionItem[]\n onSelect: (item: ContextualQuickActionItem) => void\n onBrowseAll?: () => void\n showHint?: boolean\n align?: \"start\" | \"end\"\n className?: string\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n}\n\nfunction ContextualQuickActionContextLabel({\n contextLabel,\n contextSecondary,\n className,\n}: ContextualQuickActionContextLabelProps) {\n return (\n <div\n data-slot=\"contextual-quick-action-context-label\"\n className={cn(\n \"-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground\",\n className\n )}\n >\n <Zap className=\"h-3 w-3 shrink-0\" strokeWidth={2.25} aria-hidden=\"true\" />\n <span>Acting on</span>\n <strong className=\"max-w-[180px] truncate font-semibold text-foreground\">\n {contextLabel}\n </strong>\n {contextSecondary ? (\n <span className=\"min-w-0 truncate text-muted-foreground\">\n · {contextSecondary}\n </span>\n ) : null}\n </div>\n )\n}\n\nfunction DefaultActionIcon() {\n return <Zap className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n}\n\nfunction ContextualQuickActionLauncher({\n contextLabel,\n contextSecondary,\n items,\n onSelect,\n onBrowseAll,\n showHint = false,\n align = \"start\",\n className,\n open,\n defaultOpen,\n onOpenChange,\n}: ContextualQuickActionLauncherProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false)\n const isControlled = open !== undefined\n const isOpen = isControlled ? open : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(nextOpen)\n }\n onOpenChange?.(nextOpen)\n },\n [isControlled, onOpenChange]\n )\n\n const closeMenu = React.useCallback(() => {\n handleOpenChange(false)\n }, [handleOpenChange])\n\n const handleSelect = React.useCallback(\n (item: ContextualQuickActionItem, event?: Event) => {\n if (item.disabled) {\n event?.preventDefault()\n return\n }\n\n onSelect(item)\n closeMenu()\n },\n [closeMenu, onSelect]\n )\n\n const handleBrowseAll = React.useCallback(() => {\n onBrowseAll?.()\n closeMenu()\n }, [closeMenu, onBrowseAll])\n\n return (\n <div\n data-slot=\"contextual-quick-action-launcher\"\n className={cn(\"inline-flex items-center gap-2\", className)}\n >\n <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"contextual-quick-action-trigger\"\n data-state={isOpen ? \"open\" : \"closed\"}\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-lg border border-border bg-background py-1.5 pr-2.5 pl-2 text-xs font-medium text-foreground shadow-sm transition-colors hover:border-muted-foreground/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n \"data-[state=open]:border-foreground data-[state=open]:bg-foreground data-[state=open]:text-background data-[state=open]:hover:bg-foreground\"\n )}\n >\n <span\n className={cn(\n \"inline-flex h-[18px] w-[18px] items-center justify-center rounded bg-foreground/[0.04]\",\n isOpen && \"bg-background/15\"\n )}\n >\n <Zap className=\"h-3 w-3\" strokeWidth={2} aria-hidden=\"true\" />\n </span>\n <span className=\"tracking-[-0.005em]\">Quick action</span>\n <ChevronDown className=\"h-3 w-3 opacity-60\" strokeWidth={2} aria-hidden=\"true\" />\n </button>\n </DropdownMenuTrigger>\n\n <DropdownMenuContent\n align={align}\n side=\"bottom\"\n sideOffset={6}\n className=\"pointer-events-auto w-[308px] rounded-[10px] p-1.5 text-[12.5px] shadow-[0_12px_28px_rgba(0,0,0,0.12),0_2px_6px_rgba(0,0,0,0.04)]\"\n >\n <ContextualQuickActionContextLabel\n contextLabel={contextLabel}\n contextSecondary={contextSecondary}\n />\n\n {items.map((item) => (\n <DropdownMenuItem\n key={item.id}\n disabled={item.disabled}\n onSelect={(event) => handleSelect(item, event)}\n className={cn(\n \"flex cursor-pointer items-center gap-2.5 rounded-md px-2 py-2 text-left outline-none focus:bg-accent data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100\",\n item.disabled && \"text-muted-foreground\"\n )}\n >\n <span\n data-slot=\"contextual-quick-action-item-icon\"\n className={cn(\n \"flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground\",\n item.disabled && \"opacity-60\"\n )}\n >\n {item.icon ?? <DefaultActionIcon />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span className=\"block truncate text-[12.5px] font-medium leading-tight text-current\">\n {item.label}\n </span>\n {item.description ? (\n <span className=\"mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground\">\n {item.description}\n </span>\n ) : null}\n </span>\n {item.disabled && item.disabledReason ? (\n <span className=\"ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80\">\n {item.disabledReason}\n </span>\n ) : null}\n </DropdownMenuItem>\n ))}\n\n <DropdownMenuSeparator className=\"-mx-1.5 my-1\" />\n <div className=\"flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground\">\n <button\n type=\"button\"\n className=\"inline-flex items-center gap-1 font-medium text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n onClick={handleBrowseAll}\n >\n Browse all actions\n <ArrowRight className=\"h-3 w-3\" strokeWidth={2} aria-hidden=\"true\" />\n </button>\n <span className=\"inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground\">\n ⌘K\n </span>\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n\n {showHint ? (\n <span className=\"text-[11px] text-muted-foreground\">\n Or press{\" \"}\n <span className=\"inline-flex items-center rounded border border-border bg-muted/40 px-1 py-0.5 text-[10px] font-medium leading-none\">\n ⌘K\n </span>{\" \"}\n for all actions\n </span>\n ) : null}\n </div>\n )\n}\n\nexport { ContextualQuickActionContextLabel, ContextualQuickActionLauncher }\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/contextual-quick-action-launcher.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronDown, Zap } from \"lucide-react\"\n\nimport { cn } from \"../lib/utils\"\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"./dropdown-menu\"\n\nexport interface ContextualQuickActionItem {\n id: string\n label: string\n description?: string\n icon?: React.ReactNode\n disabled?: boolean\n disabledReason?: string\n meta?: React.ReactNode\n}\n\nexport type ContextualQuickActionLauncherVariant = \"default\" | \"case-panel\"\n\nexport interface ContextualQuickActionContextLabelProps {\n contextLabel: string\n contextSecondary?: string\n variant?: ContextualQuickActionLauncherVariant\n className?: string\n}\n\nexport interface ContextualQuickActionLauncherProps {\n contextLabel: string\n contextSecondary?: string\n items: ContextualQuickActionItem[]\n onSelect: (item: ContextualQuickActionItem) => void\n onBrowseAll?: () => void\n showHint?: boolean\n align?: \"start\" | \"end\"\n variant?: ContextualQuickActionLauncherVariant\n className?: string\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n}\n\nfunction ContextualQuickActionContextLabel({\n contextLabel,\n contextSecondary,\n variant = \"default\",\n className,\n}: ContextualQuickActionContextLabelProps) {\n const isCasePanel = variant === \"case-panel\"\n\n return (\n <div\n data-slot=\"contextual-quick-action-context-label\"\n data-variant={variant}\n className={cn(\n isCasePanel\n ? \"-mx-2 -mt-2 mb-1 flex items-center gap-1.5 whitespace-nowrap border-b px-3 py-2.5 text-[13px] text-muted-foreground\"\n : \"-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground\",\n className\n )}\n >\n <Zap\n className={cn(isCasePanel ? \"h-3.5 w-3.5 shrink-0\" : \"h-3 w-3 shrink-0\")}\n strokeWidth={2.25}\n aria-hidden=\"true\"\n />\n <span>Acting on</span>\n <strong\n className={cn(\n isCasePanel\n ? \"max-w-[260px] truncate font-semibold text-foreground\"\n : \"max-w-[180px] truncate font-semibold text-foreground\"\n )}\n >\n {contextLabel}\n </strong>\n {contextSecondary ? (\n <span className=\"min-w-0 truncate text-muted-foreground\">\n · {contextSecondary}\n </span>\n ) : null}\n </div>\n )\n}\n\nfunction DefaultActionIcon() {\n return <Zap className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n}\n\nfunction ContextualQuickActionLauncher({\n contextLabel,\n contextSecondary,\n items,\n onSelect,\n onBrowseAll,\n showHint = false,\n align = \"start\",\n variant = \"default\",\n className,\n open,\n defaultOpen,\n onOpenChange,\n}: ContextualQuickActionLauncherProps) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false)\n const isCasePanel = variant === \"case-panel\"\n const isControlled = open !== undefined\n const isOpen = isControlled ? open : uncontrolledOpen\n\n const handleOpenChange = React.useCallback(\n (nextOpen: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(nextOpen)\n }\n onOpenChange?.(nextOpen)\n },\n [isControlled, onOpenChange]\n )\n\n const closeMenu = React.useCallback(() => {\n handleOpenChange(false)\n }, [handleOpenChange])\n\n const handleSelect = React.useCallback(\n (item: ContextualQuickActionItem, event?: Event) => {\n if (item.disabled) {\n event?.preventDefault()\n return\n }\n\n onSelect(item)\n closeMenu()\n },\n [closeMenu, onSelect]\n )\n\n const handleBrowseAll = React.useCallback(() => {\n onBrowseAll?.()\n closeMenu()\n }, [closeMenu, onBrowseAll])\n\n return (\n <div\n data-slot=\"contextual-quick-action-launcher\"\n className={cn(\"inline-flex items-center gap-2\", className)}\n >\n <DropdownMenu open={isOpen} onOpenChange={handleOpenChange}>\n <DropdownMenuTrigger asChild>\n <button\n type=\"button\"\n data-slot=\"contextual-quick-action-trigger\"\n data-state={isOpen ? \"open\" : \"closed\"}\n className={cn(\n \"inline-flex h-8 items-center gap-2 rounded-lg border border-border bg-background py-1.5 pr-2.5 pl-2 text-xs font-medium text-foreground shadow-sm transition-colors hover:border-muted-foreground/40 hover:bg-muted/40 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\",\n \"data-[state=open]:border-foreground data-[state=open]:bg-foreground data-[state=open]:text-background data-[state=open]:hover:bg-foreground\"\n )}\n >\n <span\n className={cn(\n \"inline-flex h-[18px] w-[18px] items-center justify-center rounded bg-foreground/[0.04]\",\n isOpen && \"bg-background/15\"\n )}\n >\n <Zap className=\"h-3 w-3\" strokeWidth={2} aria-hidden=\"true\" />\n </span>\n <span className=\"tracking-[-0.005em]\">Quick action</span>\n <ChevronDown className=\"h-3 w-3 opacity-60\" strokeWidth={2} aria-hidden=\"true\" />\n </button>\n </DropdownMenuTrigger>\n\n <DropdownMenuContent\n align={align}\n side=\"bottom\"\n sideOffset={6}\n className={cn(\n isCasePanel\n ? \"pointer-events-auto w-[432px] rounded-[13px] border border-border bg-popover p-2 text-[13px] shadow-[0_18px_44px_rgba(0,0,0,0.14),0_2px_10px_rgba(0,0,0,0.06)]\"\n : \"pointer-events-auto w-[308px] rounded-[10px] p-1.5 text-[12.5px] shadow-[0_12px_28px_rgba(0,0,0,0.12),0_2px_6px_rgba(0,0,0,0.04)]\"\n )}\n >\n <ContextualQuickActionContextLabel\n contextLabel={contextLabel}\n contextSecondary={contextSecondary}\n variant={variant}\n />\n\n {items.map((item) => (\n <DropdownMenuItem\n key={item.id}\n disabled={item.disabled}\n onSelect={(event) => handleSelect(item, event)}\n className={cn(\n isCasePanel\n ? \"grid cursor-pointer grid-cols-[34px_minmax(0,1fr)_auto] items-center gap-3 rounded-[9px] px-2.5 py-[9px] text-left outline-none focus:bg-muted/60 data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100\"\n : \"flex cursor-pointer items-center gap-2.5 rounded-md px-2 py-2 text-left outline-none focus:bg-accent data-[disabled]:cursor-not-allowed data-[disabled]:opacity-100\",\n item.disabled && \"text-muted-foreground\"\n )}\n >\n <span\n data-slot=\"contextual-quick-action-item-icon\"\n className={cn(\n isCasePanel\n ? \"flex h-[34px] w-[34px] shrink-0 items-center justify-center rounded-[9px] border border-border/70 bg-muted/60 text-foreground [&_svg]:h-[18px] [&_svg]:w-[18px]\"\n : \"flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground\",\n item.disabled && \"opacity-60\"\n )}\n >\n {item.icon ?? <DefaultActionIcon />}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span\n className={cn(\n isCasePanel\n ? \"block truncate text-[13.5px] font-semibold leading-tight text-current\"\n : \"block truncate text-[12.5px] font-medium leading-tight text-current\"\n )}\n >\n {item.label}\n </span>\n {item.description ? (\n <span\n className={cn(\n isCasePanel\n ? \"mt-1 block truncate text-[12px] leading-tight text-muted-foreground\"\n : \"mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground\"\n )}\n >\n {item.description}\n </span>\n ) : null}\n </span>\n {item.disabled && item.disabledReason ? (\n <span\n data-slot=\"contextual-quick-action-item-disabled-meta\"\n className={cn(\n isCasePanel\n ? \"ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70\"\n : \"ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80\"\n )}\n >\n {item.disabledReason}\n </span>\n ) : item.meta ? (\n <span\n data-slot=\"contextual-quick-action-item-meta\"\n className={cn(\n isCasePanel\n ? \"ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70\"\n : \"ml-auto shrink-0 text-[10.5px] text-muted-foreground/80\"\n )}\n >\n {item.meta}\n </span>\n ) : null}\n </DropdownMenuItem>\n ))}\n\n <DropdownMenuSeparator className={cn(isCasePanel ? \"-mx-2 mt-1 mb-1\" : \"-mx-1.5 my-1\")} />\n <div\n className={cn(\n isCasePanel\n ? \"flex items-center justify-between whitespace-nowrap px-2.5 py-2 text-[13px] text-muted-foreground\"\n : \"flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground\"\n )}\n >\n <button\n type=\"button\"\n className={cn(\n isCasePanel\n ? \"inline-flex items-center gap-1 font-semibold text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n : \"inline-flex items-center gap-1 font-medium text-foreground hover:underline focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2\"\n )}\n onClick={handleBrowseAll}\n >\n Browse all actions\n </button>\n <span\n className={cn(\n isCasePanel\n ? \"inline-flex items-center rounded-[5px] border border-border bg-muted/50 px-1.5 py-0.5 font-mono text-[11px] font-medium leading-none text-muted-foreground\"\n : \"inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground\"\n )}\n >\n ⌘K\n </span>\n </div>\n </DropdownMenuContent>\n </DropdownMenu>\n\n {showHint ? (\n <span className=\"text-[11px] text-muted-foreground\">\n Or press{\" \"}\n <span className=\"inline-flex items-center rounded border border-border bg-muted/40 px-1 py-0.5 text-[10px] font-medium leading-none\">\n ⌘K\n </span>{\" \"}\n for all actions\n </span>\n ) : null}\n </div>\n )\n}\n\nexport { ContextualQuickActionContextLabel, ContextualQuickActionLauncher }\n"],"mappings":"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","names":[]}
@@ -12,7 +12,7 @@ import { VariantProps } from 'class-variance-authority';
12
12
  */
13
13
  type PillStatus = "success" | "warning" | "error" | "neutral" | "info";
14
14
  declare const pillVariants: (props?: ({
15
- variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "error" | "info" | "neutral" | "warning" | "success" | null | undefined;
15
+ variant?: "default" | "secondary" | "destructive" | "outline" | "ghost" | "error" | "neutral" | "info" | "success" | "warning" | null | undefined;
16
16
  } & class_variance_authority_types.ClassProp) | undefined) => string;
17
17
  interface PillProps extends React.ComponentProps<"span">, VariantProps<typeof pillVariants> {
18
18
  }
package/dist/index.d.ts CHANGED
@@ -10,11 +10,15 @@ export { Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, Ava
10
10
  export { Badge, badgeVariants } from './components/badge.js';
11
11
  export { Button, buttonVariants } from './components/button.js';
12
12
  export { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from './components/card.js';
13
+ export { CasePanelEmailComposer, CasePanelEmailComposerChip, CasePanelEmailComposerChipProps, CasePanelEmailComposerProps, CasePanelEmailComposerRow, CasePanelEmailComposerRowProps, CasePanelEmailComposerRowState, CasePanelEmailComposerSignatureRow, CasePanelEmailComposerSignatureRowProps, CasePanelEmailComposerSlotHelpers } from './components/case-panel-email-composer.js';
14
+ export { CasePanelActivityActor, CasePanelActivityEvent, CasePanelActivityPayload, CasePanelActivityTimeline, CasePanelActivityTimelineProps, CasePanelActivityTone, CasePanelPayloadAction } from './components/case-panel-activity-timeline.js';
15
+ export { CasePanelDetail, CasePanelDetailProps, CasePanelDetailSlots, CasePanelDetailSlotsProps, CasePanelDetailWidth, CasePanelHeader, CasePanelHeaderProps, CasePanelIdentityLink, CasePanelIdentitySubline, CasePanelIdentitySublineProps, CasePanelMetadataRow, CasePanelMetadataRowProps, CasePanelSignalBrief, CasePanelSignalBriefProps } from './components/case-panel-detail.js';
16
+ export { CasePanelSignalApprovalActions, CasePanelSignalApprovalActionsProps, CasePanelWhy, CasePanelWhyItem, CasePanelWhyProps, CasePanelWhyRow, CasePanelWhyTone } from './components/case-panel-why.js';
13
17
  export { CollapsibleSection, CollapsibleSectionProps } from './components/collapsible-section.js';
14
18
  export { ComplianceBadge, ComplianceBadgeProps, ComplianceStatus } from './components/compliance-badge.js';
15
19
  export { ContactChip, ContactChipProps } from './components/contact-chip.js';
16
20
  export { ContactChannel, ContactItem, ContactList, ContactListProps } from './components/contact-list.js';
17
- export { ContextualQuickActionContextLabel, ContextualQuickActionContextLabelProps, ContextualQuickActionItem, ContextualQuickActionLauncher, ContextualQuickActionLauncherProps } from './components/contextual-quick-action-launcher.js';
21
+ export { ContextualQuickActionContextLabel, ContextualQuickActionContextLabelProps, ContextualQuickActionItem, ContextualQuickActionLauncher, ContextualQuickActionLauncherProps, ContextualQuickActionLauncherVariant } from './components/contextual-quick-action-launcher.js';
18
22
  export { CheckInsCard, RecentlyCompletedCard, TopTasksCard, UpcomingMeetingsCard } from './components/dashboard-cards.js';
19
23
  export { DataRow, DataTable, DataTableProps } from './components/data-table.js';
20
24
  export { ConditionFieldDef, ConditionFieldOption, ConditionFilterValue, ConditionOperator, ConditionOptionObject, DEFAULT_OPERATORS, DataTableConditionFilter, DataTableConditionFilterProps, OPERATOR_LABELS, generateConditionId, getOperators, shouldShowOptionSearch } from './components/data-table-condition-filter.js';
package/dist/index.js CHANGED
@@ -10,6 +10,10 @@ export * from "./components/avatar.js";
10
10
  export * from "./components/badge.js";
11
11
  export * from "./components/button.js";
12
12
  export * from "./components/card.js";
13
+ export * from "./components/case-panel-email-composer.js";
14
+ export * from "./components/case-panel-activity-timeline.js";
15
+ export * from "./components/case-panel-detail.js";
16
+ export * from "./components/case-panel-why.js";
13
17
  import { CollapsibleSection } from "./components/collapsible-section.js";
14
18
  export * from "./components/compliance-badge.js";
15
19
  export * from "./components/contact-chip.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @handled-ai/design-system\n * UI components and utilities (shadcn-style, New York)\n */\n\n// Utilities\nexport { cn } from \"./lib/utils\"\nexport { BRAND_ICONS, BRAND_GRAPHICS } from \"./lib/icons\"\nexport { displayName, getInitials, shortName, type ProfileLike } from \"./lib/user-display\"\n\n// Hooks\nexport { useIsMobile } from \"./hooks/use-mobile\"\n\n// Components (light — no recharts/nivo/three transitive deps)\nexport * from \"./components/activity-detail\"\nexport * from \"./components/activity-log\"\nexport * from \"./components/agent-popover\"\nexport * from \"./components/agent-widget\"\nexport * from \"./components/avatar\"\nexport * from \"./components/badge\"\nexport * from \"./components/button\"\nexport * from \"./components/card\"\nexport { CollapsibleSection, type CollapsibleSectionProps } from \"./components/collapsible-section\"\nexport * from \"./components/compliance-badge\"\nexport * from \"./components/contact-chip\"\nexport * from \"./components/contact-list\"\nexport * from \"./components/contextual-quick-action-launcher\"\nexport * from \"./components/dashboard-cards\"\nexport * from \"./components/data-table\"\nexport * from \"./components/data-table-condition-filter\"\nexport * from \"./components/data-table-display\"\nexport * from \"./components/data-table-filter\"\nexport * from \"./components/data-table-quick-views\"\nexport * from \"./components/data-table-toolbar\"\nexport * from \"./components/detail-view\"\nexport * from \"./components/detail-drawer\"\nexport * from \"./components/dialog\"\nexport * from \"./components/dropdown-menu\"\nexport * from \"./components/empty-state\"\nexport * from \"./components/entity-panel\"\nexport { FeedbackFooter, FeedbackChipGroup, FeedbackInput, FeedbackActions, InlineFeedbackControl } from \"./components/feedback-primitives\"\nexport type { FeedbackFooterProps, FeedbackChipTree, FeedbackChipGroupProps, FeedbackInputProps, FeedbackActionsProps, FeedbackSubmitData, PersistedFeedbackData, InlineFeedbackControlProps } from \"./components/feedback-primitives\"\nexport { SignalPriorityPopover } from \"./components/signal-priority-popover\"\nexport type { SignalPriorityPopoverProps, PriorityFactor } from \"./components/signal-priority-popover\"\nexport * from \"./components/filter-chip\"\nexport * from \"./components/inbox-row\"\nexport * from \"./components/inbox-toolbar\"\nexport * from \"./components/inline-banner\"\nexport * from \"./components/input\"\nexport * from \"./components/insights-filter-bar\"\nexport * from \"./components/days-open-cell\"\nexport * from \"./components/linked-entity-cell\"\nexport * from \"./components/item-list\"\nexport * from \"./components/item-list-display\"\nexport * from \"./components/item-list-filter\"\nexport * from \"./components/item-list-toolbar\"\nexport * from \"./components/kbd-hint\"\nexport * from \"./components/label\"\nexport * from \"./components/message\"\nexport * from \"./components/metric-card\"\nexport * from \"./components/performance-metrics-table\"\nexport * from \"./components/pill\"\nexport * from \"./components/preview-list\"\nexport * from \"./components/progress\"\nexport * from \"./components/quick-action-chat-area\"\nexport * from \"./components/quick-segment\"\nexport {\n QuickActionModal,\n type QuickActionPriority,\n type QuickActionTaskDraft,\n type QuickActionTemplate,\n} from \"./components/quick-action-modal\"\nexport * from \"./components/quick-action-sidebar-nav\"\nexport * from \"./components/recommended-actions-section\"\nexport * from \"./components/report-card\"\nexport * from \"./components/rich-text-toolbar\"\nexport * from \"./components/score-analysis-modal\"\nexport * from \"./components/score-breakdown\"\nexport * from \"./components/score-feedback\"\nexport * from \"./components/score-semantics\"\nexport * from \"./components/score-why-chips\"\nexport * from \"./components/score-ring\"\nexport * from \"./components/scroll-area\"\nexport * from \"./components/select\"\nexport * from \"./components/separator\"\nexport * from \"./components/sheet\"\nexport * from \"./components/sidebar\"\nexport * from \"./components/signal-feedback-inline\"\nexport * from \"./components/simple-data-table\"\nexport * from \"./components/skeleton\"\nexport * from \"./components/status-badge\"\nexport * from \"./components/step-timeline\"\nexport * from \"./components/sticky-action-bar\"\nexport * from \"./components/styled-bar-list\"\nexport { DraftFeedbackInline } from \"./components/draft-feedback-inline\"\nexport type { DraftFeedbackInlineProps } from \"./components/draft-feedback-inline\"\nexport { AccountContactsPopover, BrandIcon } from \"./components/account-contacts-popover\"\nexport type { AccountContactsPopoverProps } from \"./components/account-contacts-popover\"\nexport * from \"./components/suggested-actions\"\nexport * from \"./components/switch\"\nexport * from \"./components/table\"\nexport * from \"./components/tabs\"\nexport * from \"./components/textarea\"\nexport * from \"./components/timeline-activity\"\nexport * from \"./components/tooltip\"\nexport * from \"./components/user-display\"\nexport * from \"./components/variable-autocomplete\"\nexport * from \"./components/view-mode-toggle\"\nexport * from \"./components/virtualized-data-table\"\nexport type { ColumnSizingState } from \"@tanstack/react-table\"\n\n// Charts (re-exported for backward compatibility with root imports)\nexport * from \"./charts/index\"\n\n// Prototype template system (re-exported for backward compatibility)\nexport * from \"./prototype/prototype-config\"\nexport * from \"./prototype/prototype-shell\"\nexport * from \"./prototype/prototype-inbox-view\"\nexport * from \"./prototype/prototype-insights-view\"\nexport * from \"./prototype/prototype-accounts-view\"\nexport * from \"./prototype/prototype-admin-view\"\nexport * from \"./prototype/prototype-work-queue-view\"\n"],"mappings":"AAMA,SAAS,UAAU;AACnB,SAAS,aAAa,sBAAsB;AAC5C,SAAS,aAAa,aAAa,iBAAmC;AAGtE,SAAS,mBAAmB;AAG5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,0BAAwD;AACjE,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,gBAAgB,mBAAmB,eAAe,iBAAiB,6BAA6B;AAEzG,SAAS,6BAA6B;AAEtC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd;AAAA,EACE;AAAA,OAIK;AACP,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,2BAA2B;AAEpC,SAAS,wBAAwB,iBAAiB;AAElD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @handled-ai/design-system\n * UI components and utilities (shadcn-style, New York)\n */\n\n// Utilities\nexport { cn } from \"./lib/utils\"\nexport { BRAND_ICONS, BRAND_GRAPHICS } from \"./lib/icons\"\nexport { displayName, getInitials, shortName, type ProfileLike } from \"./lib/user-display\"\n\n// Hooks\nexport { useIsMobile } from \"./hooks/use-mobile\"\n\n// Components (light — no recharts/nivo/three transitive deps)\nexport * from \"./components/activity-detail\"\nexport * from \"./components/activity-log\"\nexport * from \"./components/agent-popover\"\nexport * from \"./components/agent-widget\"\nexport * from \"./components/avatar\"\nexport * from \"./components/badge\"\nexport * from \"./components/button\"\nexport * from \"./components/card\"\nexport * from \"./components/case-panel-email-composer\"\nexport * from \"./components/case-panel-activity-timeline\"\nexport * from \"./components/case-panel-detail\"\nexport * from \"./components/case-panel-why\"\nexport { CollapsibleSection, type CollapsibleSectionProps } from \"./components/collapsible-section\"\nexport * from \"./components/compliance-badge\"\nexport * from \"./components/contact-chip\"\nexport * from \"./components/contact-list\"\nexport * from \"./components/contextual-quick-action-launcher\"\nexport * from \"./components/dashboard-cards\"\nexport * from \"./components/data-table\"\nexport * from \"./components/data-table-condition-filter\"\nexport * from \"./components/data-table-display\"\nexport * from \"./components/data-table-filter\"\nexport * from \"./components/data-table-quick-views\"\nexport * from \"./components/data-table-toolbar\"\nexport * from \"./components/detail-view\"\nexport * from \"./components/detail-drawer\"\nexport * from \"./components/dialog\"\nexport * from \"./components/dropdown-menu\"\nexport * from \"./components/empty-state\"\nexport * from \"./components/entity-panel\"\nexport { FeedbackFooter, FeedbackChipGroup, FeedbackInput, FeedbackActions, InlineFeedbackControl } from \"./components/feedback-primitives\"\nexport type { FeedbackFooterProps, FeedbackChipTree, FeedbackChipGroupProps, FeedbackInputProps, FeedbackActionsProps, FeedbackSubmitData, PersistedFeedbackData, InlineFeedbackControlProps } from \"./components/feedback-primitives\"\nexport { SignalPriorityPopover } from \"./components/signal-priority-popover\"\nexport type { SignalPriorityPopoverProps, PriorityFactor } from \"./components/signal-priority-popover\"\nexport * from \"./components/filter-chip\"\nexport * from \"./components/inbox-row\"\nexport * from \"./components/inbox-toolbar\"\nexport * from \"./components/inline-banner\"\nexport * from \"./components/input\"\nexport * from \"./components/insights-filter-bar\"\nexport * from \"./components/days-open-cell\"\nexport * from \"./components/linked-entity-cell\"\nexport * from \"./components/item-list\"\nexport * from \"./components/item-list-display\"\nexport * from \"./components/item-list-filter\"\nexport * from \"./components/item-list-toolbar\"\nexport * from \"./components/kbd-hint\"\nexport * from \"./components/label\"\nexport * from \"./components/message\"\nexport * from \"./components/metric-card\"\nexport * from \"./components/performance-metrics-table\"\nexport * from \"./components/pill\"\nexport * from \"./components/preview-list\"\nexport * from \"./components/progress\"\nexport * from \"./components/quick-action-chat-area\"\nexport * from \"./components/quick-segment\"\nexport {\n QuickActionModal,\n type QuickActionPriority,\n type QuickActionTaskDraft,\n type QuickActionTemplate,\n} from \"./components/quick-action-modal\"\nexport * from \"./components/quick-action-sidebar-nav\"\nexport * from \"./components/recommended-actions-section\"\nexport * from \"./components/report-card\"\nexport * from \"./components/rich-text-toolbar\"\nexport * from \"./components/score-analysis-modal\"\nexport * from \"./components/score-breakdown\"\nexport * from \"./components/score-feedback\"\nexport * from \"./components/score-semantics\"\nexport * from \"./components/score-why-chips\"\nexport * from \"./components/score-ring\"\nexport * from \"./components/scroll-area\"\nexport * from \"./components/select\"\nexport * from \"./components/separator\"\nexport * from \"./components/sheet\"\nexport * from \"./components/sidebar\"\nexport * from \"./components/signal-feedback-inline\"\nexport * from \"./components/simple-data-table\"\nexport * from \"./components/skeleton\"\nexport * from \"./components/status-badge\"\nexport * from \"./components/step-timeline\"\nexport * from \"./components/sticky-action-bar\"\nexport * from \"./components/styled-bar-list\"\nexport { DraftFeedbackInline } from \"./components/draft-feedback-inline\"\nexport type { DraftFeedbackInlineProps } from \"./components/draft-feedback-inline\"\nexport { AccountContactsPopover, BrandIcon } from \"./components/account-contacts-popover\"\nexport type { AccountContactsPopoverProps } from \"./components/account-contacts-popover\"\nexport * from \"./components/suggested-actions\"\nexport * from \"./components/switch\"\nexport * from \"./components/table\"\nexport * from \"./components/tabs\"\nexport * from \"./components/textarea\"\nexport * from \"./components/timeline-activity\"\nexport * from \"./components/tooltip\"\nexport * from \"./components/user-display\"\nexport * from \"./components/variable-autocomplete\"\nexport * from \"./components/view-mode-toggle\"\nexport * from \"./components/virtualized-data-table\"\nexport type { ColumnSizingState } from \"@tanstack/react-table\"\n\n// Charts (re-exported for backward compatibility with root imports)\nexport * from \"./charts/index\"\n\n// Prototype template system (re-exported for backward compatibility)\nexport * from \"./prototype/prototype-config\"\nexport * from \"./prototype/prototype-shell\"\nexport * from \"./prototype/prototype-inbox-view\"\nexport * from \"./prototype/prototype-insights-view\"\nexport * from \"./prototype/prototype-accounts-view\"\nexport * from \"./prototype/prototype-admin-view\"\nexport * from \"./prototype/prototype-work-queue-view\"\n"],"mappings":"AAMA,SAAS,UAAU;AACnB,SAAS,aAAa,sBAAsB;AAC5C,SAAS,aAAa,aAAa,iBAAmC;AAGtE,SAAS,mBAAmB;AAG5B,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,0BAAwD;AACjE,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,gBAAgB,mBAAmB,eAAe,iBAAiB,6BAA6B;AAEzG,SAAS,6BAA6B;AAEtC,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd;AAAA,EACE;AAAA,OAIK;AACP,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,SAAS,2BAA2B;AAEpC,SAAS,wBAAwB,iBAAiB;AAElD,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AAId,cAAc;AAGd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;AACd,cAAc;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@handled-ai/design-system",
3
- "version": "0.18.22",
3
+ "version": "0.18.24",
4
4
  "description": "Handled UI component library (shadcn-style, New York)",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@9.12.0",
@@ -0,0 +1,152 @@
1
+ import React from "react"
2
+ import { describe, expect, it, vi } from "vitest"
3
+ import { fireEvent, render, screen, within } from "@testing-library/react"
4
+ import {
5
+ CasePanelActivityTimeline,
6
+ type CasePanelActivityEvent,
7
+ } from "../case-panel-activity-timeline"
8
+
9
+ function event(overrides: Partial<CasePanelActivityEvent> = {}): CasePanelActivityEvent {
10
+ return {
11
+ id: "event-1",
12
+ title: "Signal detected",
13
+ timeLabel: "2h ago",
14
+ tone: "blue",
15
+ payload: { kind: "generic", description: "A case update happened" },
16
+ ...overrides,
17
+ }
18
+ }
19
+
20
+ const visibleEvent = event()
21
+ const systemNoiseEvent = event({
22
+ id: "system-1",
23
+ title: "System recalculated routing state",
24
+ timeLabel: "1h ago",
25
+ tone: "slate",
26
+ actor: { kind: "system" },
27
+ isSystemNoise: true,
28
+ payload: { kind: "generic", description: "Internal routing snapshot refreshed" },
29
+ })
30
+
31
+ describe("CasePanelActivityTimeline", () => {
32
+ it("renders collapsed by default with non-system count and last activity text", () => {
33
+ render(<CasePanelActivityTimeline events={[visibleEvent, systemNoiseEvent]} />)
34
+
35
+ expect(screen.getByRole("button", { name: /activity/i }).getAttribute("aria-expanded")).toBe("false")
36
+ expect(screen.getByText("1 event")).not.toBeNull()
37
+ expect(screen.getByText("Last activity 2h ago")).not.toBeNull()
38
+ expect(screen.queryByText("Signal detected")).toBeNull()
39
+ })
40
+
41
+ it("expands and renders visible timeline events", () => {
42
+ render(<CasePanelActivityTimeline events={[visibleEvent]} />)
43
+
44
+ fireEvent.click(screen.getByRole("button", { name: /activity/i }))
45
+
46
+ expect(screen.getByText("Signal detected")).not.toBeNull()
47
+ expect(screen.getByText("A case update happened")).not.toBeNull()
48
+ expect(screen.getByTestId("case-panel-activity-dot").className).toContain("bg-blue-50")
49
+ })
50
+
51
+ it("hides system noise until the Show system events toggle is enabled", () => {
52
+ render(<CasePanelActivityTimeline events={[visibleEvent, systemNoiseEvent]} defaultExpanded />)
53
+
54
+ expect((screen.getByLabelText("Show system events") as HTMLInputElement).checked).toBe(false)
55
+ expect(screen.getByText("Signal detected")).not.toBeNull()
56
+ expect(screen.queryByText("System recalculated routing state")).toBeNull()
57
+
58
+ fireEvent.click(screen.getByLabelText("Show system events"))
59
+
60
+ expect(screen.getByText("System recalculated routing state")).not.toBeNull()
61
+ })
62
+
63
+ it("applies actor byline rules without implying system when actor is missing", () => {
64
+ render(
65
+ <CasePanelActivityTimeline
66
+ defaultExpanded
67
+ events={[
68
+ event({ id: "missing-actor", title: "No actor event" }),
69
+ event({ id: "system-actor", title: "System actor event", actor: { kind: "system" } }),
70
+ event({ id: "integration-actor", title: "Integration actor event", actor: { kind: "integration", name: "Salesforce" } }),
71
+ event({ id: "user-actor", title: "User actor event", actor: { kind: "user", name: "Maya", verb: "approved this" } }),
72
+ ]}
73
+ />
74
+ )
75
+
76
+ const bylines = screen.getAllByTestId("case-panel-activity-byline")
77
+ expect(bylines).toHaveLength(2)
78
+ expect(bylines[0].textContent).toContain("Salesforce")
79
+ expect(bylines[0].textContent).toContain("synced this update")
80
+ expect(bylines[0].textContent).toContain("2h ago")
81
+ expect(bylines[1].textContent).toContain("Maya")
82
+ expect(bylines[1].textContent).toContain("approved this")
83
+ expect(bylines[1].textContent).toContain("2h ago")
84
+ expect(screen.queryByText("System")).toBeNull()
85
+ })
86
+
87
+ it("renders typed payload variants and dispatches typed signal actions", () => {
88
+ const onPayloadAction = vi.fn()
89
+ render(
90
+ <CasePanelActivityTimeline
91
+ defaultExpanded
92
+ onPayloadAction={onPayloadAction}
93
+ events={[
94
+ event({ id: "signal", title: "Signal", payload: { kind: "signal", key: "sig-1", summary: "Churn risk rose", detail: "Usage fell 30%." } }),
95
+ event({ id: "score", title: "Score", payload: { kind: "scoreUpdate", previousScore: 62, nextScore: 81, reason: "Executive engagement improved." } }),
96
+ event({ id: "rec", title: "Recommendation", payload: { kind: "recommendation", recommendation: "Send renewal brief", rationale: "Close date is within 14 days." } }),
97
+ event({ id: "email", title: "Email", payload: { kind: "email", from: "rep@example.com", to: "buyer@example.com", subject: "Renewal plan", preview: "Can we meet tomorrow?" } }),
98
+ event({ id: "deadline", title: "Deadline", payload: { kind: "deadline", dueLabel: "Due tomorrow", status: "due", description: "SLA response window." } }),
99
+ event({ id: "note", title: "Note", payload: { kind: "operatorNote", note: "Customer asked for legal review." } }),
100
+ event({ id: "assignment", title: "Assignment", payload: { kind: "assignment", assignee: "Jordan", from: "Maya", role: "Owner" } }),
101
+ event({ id: "opened", title: "Opened", payload: { kind: "caseOpened", source: "Gmail", openedBy: "Ari", description: "Inbound renewal request." } }),
102
+ ]}
103
+ />
104
+ )
105
+
106
+ expect(screen.getByTestId("case-panel-payload-signal").textContent).toContain("Churn risk rose")
107
+ expect(screen.getByTestId("case-panel-payload-scoreUpdate").textContent).toContain("62 → 81")
108
+ expect(screen.getByTestId("case-panel-payload-recommendation").textContent).toContain("Send renewal brief")
109
+ expect(screen.getByTestId("case-panel-payload-email").textContent).toContain("Renewal plan")
110
+ expect(screen.getByTestId("case-panel-payload-deadline").textContent).toContain("Due tomorrow")
111
+ expect(screen.getByTestId("case-panel-payload-operatorNote").textContent).toContain("Customer asked for legal review.")
112
+ expect(screen.getByTestId("case-panel-payload-assignment").textContent).toContain("Assigned to Jordan as Owner from Maya")
113
+ expect(screen.getByTestId("case-panel-payload-caseOpened").textContent).toContain("Case opened by Ari from Gmail")
114
+
115
+ fireEvent.click(screen.getByRole("button", { name: "Open signal" }))
116
+ expect(onPayloadAction).toHaveBeenCalledWith({ kind: "openSignal", key: "sig-1", eventId: "signal" })
117
+ })
118
+
119
+ it("renders the Salesforce deep-link slot", () => {
120
+ render(
121
+ <CasePanelActivityTimeline
122
+ defaultExpanded
123
+ events={[
124
+ event({
125
+ tone: "salesforce",
126
+ title: "Salesforce opportunity updated",
127
+ payload: {
128
+ kind: "salesforce",
129
+ objectLabel: "Opportunity",
130
+ recordLabel: "ACME Renewal",
131
+ changeSummary: "Stage moved to Negotiation.",
132
+ deepLink: { href: "https://salesforce.example.com/opp/123", label: "View opportunity" },
133
+ },
134
+ }),
135
+ ]}
136
+ />
137
+ )
138
+
139
+ const card = screen.getByTestId("case-panel-payload-salesforce")
140
+ expect(card.textContent).toContain("Opportunity")
141
+ expect(card.textContent).toContain("ACME Renewal")
142
+ const link = within(card).getByRole("link", { name: /view opportunity/i })
143
+ expect(link.getAttribute("href")).toBe("https://salesforce.example.com/opp/123")
144
+ expect(screen.getByTestId("case-panel-activity-dot").className).toContain("border-[#00A1E0]/25")
145
+ })
146
+
147
+ it("does not render a Detailed system log section", () => {
148
+ render(<CasePanelActivityTimeline events={[visibleEvent, systemNoiseEvent]} defaultExpanded defaultShowSystemEvents />)
149
+
150
+ expect(screen.queryByText(/detailed system log/i)).toBeNull()
151
+ })
152
+ })