@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
@@ -1,7 +1,7 @@
1
1
  "use client"
2
2
 
3
3
  import * as React from "react"
4
- import { ArrowRight, ChevronDown, Zap } from "lucide-react"
4
+ import { ChevronDown, Zap } from "lucide-react"
5
5
 
6
6
  import { cn } from "../lib/utils"
7
7
  import {
@@ -19,11 +19,15 @@ export interface ContextualQuickActionItem {
19
19
  icon?: React.ReactNode
20
20
  disabled?: boolean
21
21
  disabledReason?: string
22
+ meta?: React.ReactNode
22
23
  }
23
24
 
25
+ export type ContextualQuickActionLauncherVariant = "default" | "case-panel"
26
+
24
27
  export interface ContextualQuickActionContextLabelProps {
25
28
  contextLabel: string
26
29
  contextSecondary?: string
30
+ variant?: ContextualQuickActionLauncherVariant
27
31
  className?: string
28
32
  }
29
33
 
@@ -35,6 +39,7 @@ export interface ContextualQuickActionLauncherProps {
35
39
  onBrowseAll?: () => void
36
40
  showHint?: boolean
37
41
  align?: "start" | "end"
42
+ variant?: ContextualQuickActionLauncherVariant
38
43
  className?: string
39
44
  open?: boolean
40
45
  defaultOpen?: boolean
@@ -44,19 +49,35 @@ export interface ContextualQuickActionLauncherProps {
44
49
  function ContextualQuickActionContextLabel({
45
50
  contextLabel,
46
51
  contextSecondary,
52
+ variant = "default",
47
53
  className,
48
54
  }: ContextualQuickActionContextLabelProps) {
55
+ const isCasePanel = variant === "case-panel"
56
+
49
57
  return (
50
58
  <div
51
59
  data-slot="contextual-quick-action-context-label"
60
+ data-variant={variant}
52
61
  className={cn(
53
- "-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground",
62
+ isCasePanel
63
+ ? "-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"
64
+ : "-mx-1 -mt-1 mb-1 flex items-center gap-1.5 border-b px-3 py-2 text-[11px] text-muted-foreground",
54
65
  className
55
66
  )}
56
67
  >
57
- <Zap className="h-3 w-3 shrink-0" strokeWidth={2.25} aria-hidden="true" />
68
+ <Zap
69
+ className={cn(isCasePanel ? "h-3.5 w-3.5 shrink-0" : "h-3 w-3 shrink-0")}
70
+ strokeWidth={2.25}
71
+ aria-hidden="true"
72
+ />
58
73
  <span>Acting on</span>
59
- <strong className="max-w-[180px] truncate font-semibold text-foreground">
74
+ <strong
75
+ className={cn(
76
+ isCasePanel
77
+ ? "max-w-[260px] truncate font-semibold text-foreground"
78
+ : "max-w-[180px] truncate font-semibold text-foreground"
79
+ )}
80
+ >
60
81
  {contextLabel}
61
82
  </strong>
62
83
  {contextSecondary ? (
@@ -80,12 +101,14 @@ function ContextualQuickActionLauncher({
80
101
  onBrowseAll,
81
102
  showHint = false,
82
103
  align = "start",
104
+ variant = "default",
83
105
  className,
84
106
  open,
85
107
  defaultOpen,
86
108
  onOpenChange,
87
109
  }: ContextualQuickActionLauncherProps) {
88
110
  const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false)
111
+ const isCasePanel = variant === "case-panel"
89
112
  const isControlled = open !== undefined
90
113
  const isOpen = isControlled ? open : uncontrolledOpen
91
114
 
@@ -154,11 +177,16 @@ function ContextualQuickActionLauncher({
154
177
  align={align}
155
178
  side="bottom"
156
179
  sideOffset={6}
157
- 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)]"
180
+ className={cn(
181
+ isCasePanel
182
+ ? "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)]"
183
+ : "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)]"
184
+ )}
158
185
  >
159
186
  <ContextualQuickActionContextLabel
160
187
  contextLabel={contextLabel}
161
188
  contextSecondary={contextSecondary}
189
+ variant={variant}
162
190
  />
163
191
 
164
192
  {items.map((item) => (
@@ -167,48 +195,97 @@ function ContextualQuickActionLauncher({
167
195
  disabled={item.disabled}
168
196
  onSelect={(event) => handleSelect(item, event)}
169
197
  className={cn(
170
- "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",
198
+ isCasePanel
199
+ ? "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"
200
+ : "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",
171
201
  item.disabled && "text-muted-foreground"
172
202
  )}
173
203
  >
174
204
  <span
175
205
  data-slot="contextual-quick-action-item-icon"
176
206
  className={cn(
177
- "flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground",
207
+ isCasePanel
208
+ ? "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]"
209
+ : "flex h-[26px] w-[26px] shrink-0 items-center justify-center rounded-md bg-secondary text-foreground",
178
210
  item.disabled && "opacity-60"
179
211
  )}
180
212
  >
181
213
  {item.icon ?? <DefaultActionIcon />}
182
214
  </span>
183
215
  <span className="min-w-0 flex-1">
184
- <span className="block truncate text-[12.5px] font-medium leading-tight text-current">
216
+ <span
217
+ className={cn(
218
+ isCasePanel
219
+ ? "block truncate text-[13.5px] font-semibold leading-tight text-current"
220
+ : "block truncate text-[12.5px] font-medium leading-tight text-current"
221
+ )}
222
+ >
185
223
  {item.label}
186
224
  </span>
187
225
  {item.description ? (
188
- <span className="mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground">
226
+ <span
227
+ className={cn(
228
+ isCasePanel
229
+ ? "mt-1 block truncate text-[12px] leading-tight text-muted-foreground"
230
+ : "mt-0.5 block truncate text-[11px] leading-tight text-muted-foreground"
231
+ )}
232
+ >
189
233
  {item.description}
190
234
  </span>
191
235
  ) : null}
192
236
  </span>
193
237
  {item.disabled && item.disabledReason ? (
194
- <span className="ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80">
238
+ <span
239
+ data-slot="contextual-quick-action-item-disabled-meta"
240
+ className={cn(
241
+ isCasePanel
242
+ ? "ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70"
243
+ : "ml-auto shrink-0 text-[10.5px] italic text-muted-foreground/80"
244
+ )}
245
+ >
195
246
  {item.disabledReason}
196
247
  </span>
248
+ ) : item.meta ? (
249
+ <span
250
+ data-slot="contextual-quick-action-item-meta"
251
+ className={cn(
252
+ isCasePanel
253
+ ? "ml-auto shrink-0 whitespace-nowrap text-[12px] italic text-muted-foreground/70"
254
+ : "ml-auto shrink-0 text-[10.5px] text-muted-foreground/80"
255
+ )}
256
+ >
257
+ {item.meta}
258
+ </span>
197
259
  ) : null}
198
260
  </DropdownMenuItem>
199
261
  ))}
200
262
 
201
- <DropdownMenuSeparator className="-mx-1.5 my-1" />
202
- <div className="flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground">
263
+ <DropdownMenuSeparator className={cn(isCasePanel ? "-mx-2 mt-1 mb-1" : "-mx-1.5 my-1")} />
264
+ <div
265
+ className={cn(
266
+ isCasePanel
267
+ ? "flex items-center justify-between whitespace-nowrap px-2.5 py-2 text-[13px] text-muted-foreground"
268
+ : "flex items-center justify-between px-2 py-1.5 text-[11px] text-muted-foreground"
269
+ )}
270
+ >
203
271
  <button
204
272
  type="button"
205
- 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"
273
+ className={cn(
274
+ isCasePanel
275
+ ? "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"
276
+ : "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"
277
+ )}
206
278
  onClick={handleBrowseAll}
207
279
  >
208
280
  Browse all actions
209
- <ArrowRight className="h-3 w-3" strokeWidth={2} aria-hidden="true" />
210
281
  </button>
211
- <span className="inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground">
282
+ <span
283
+ className={cn(
284
+ isCasePanel
285
+ ? "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"
286
+ : "inline-flex items-center rounded border border-border px-1 py-0.5 text-[10px] font-medium leading-none text-muted-foreground"
287
+ )}
288
+ >
212
289
  ⌘K
213
290
  </span>
214
291
  </div>
package/src/index.ts CHANGED
@@ -20,6 +20,10 @@ export * from "./components/avatar"
20
20
  export * from "./components/badge"
21
21
  export * from "./components/button"
22
22
  export * from "./components/card"
23
+ export * from "./components/case-panel-email-composer"
24
+ export * from "./components/case-panel-activity-timeline"
25
+ export * from "./components/case-panel-detail"
26
+ export * from "./components/case-panel-why"
23
27
  export { CollapsibleSection, type CollapsibleSectionProps } from "./components/collapsible-section"
24
28
  export * from "./components/compliance-badge"
25
29
  export * from "./components/contact-chip"