@handled-ai/design-system 0.18.24 → 0.18.25

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.
@@ -25,9 +25,11 @@ interface CasePanelIdentityLink {
25
25
  icon?: React.ReactNode;
26
26
  kind?: "icon" | "text";
27
27
  disabled?: boolean;
28
+ target?: React.HTMLAttributeAnchorTarget;
29
+ rel?: string;
28
30
  }
29
31
  interface CasePanelIdentitySublineProps {
30
- callsign: string;
32
+ callsign?: string | null;
31
33
  links?: CasePanelIdentityLink[];
32
34
  onCopyCallsign?: (callsign: string) => void;
33
35
  copyLabel?: string;
@@ -46,32 +46,36 @@ function CasePanelIdentitySubline({
46
46
  className
47
47
  }) {
48
48
  const [copied, setCopied] = React.useState(false);
49
- const normalizedCallsign = callsign.startsWith("@") ? callsign : `@${callsign}`;
49
+ const trimmedCallsign = callsign == null ? void 0 : callsign.trim();
50
+ const normalizedCallsign = trimmedCallsign ? trimmedCallsign.startsWith("@") ? trimmedCallsign : `@${trimmedCallsign}` : null;
50
51
  const handleCopy = React.useCallback(() => {
52
+ if (!normalizedCallsign) return;
51
53
  onCopyCallsign == null ? void 0 : onCopyCallsign(normalizedCallsign);
52
54
  setCopied(true);
53
55
  window.setTimeout(() => setCopied(false), 1400);
54
56
  }, [normalizedCallsign, onCopyCallsign]);
55
57
  return /* @__PURE__ */ jsxs("div", { className: cn("mt-[9px] inline-flex flex-wrap items-center gap-[7px] text-[13px] text-muted-foreground", className), children: [
56
- /* @__PURE__ */ jsx("span", { className: "font-mono font-medium tracking-[0.01em] text-gray-700", children: normalizedCallsign }),
57
- /* @__PURE__ */ jsx(
58
- "button",
59
- {
60
- type: "button",
61
- onClick: handleCopy,
62
- "aria-label": copied ? copiedLabel : copyLabel,
63
- className: "inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground",
64
- children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-[13px] w-[13px] text-emerald-700", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Copy, { className: "h-[13px] w-[13px]", "aria-hidden": "true" })
65
- }
66
- ),
58
+ normalizedCallsign ? /* @__PURE__ */ jsxs(Fragment, { children: [
59
+ /* @__PURE__ */ jsx("span", { className: "font-mono font-medium tracking-[0.01em] text-gray-700", children: normalizedCallsign }),
60
+ /* @__PURE__ */ jsx(
61
+ "button",
62
+ {
63
+ type: "button",
64
+ onClick: handleCopy,
65
+ "aria-label": copied ? copiedLabel : copyLabel,
66
+ className: "inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground",
67
+ children: copied ? /* @__PURE__ */ jsx(Check, { className: "h-[13px] w-[13px] text-emerald-700", "aria-hidden": "true" }) : /* @__PURE__ */ jsx(Copy, { className: "h-[13px] w-[13px]", "aria-hidden": "true" })
68
+ }
69
+ )
70
+ ] }) : null,
67
71
  links.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
68
- /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "mx-[3px] h-3.5 w-px bg-gray-200" }),
72
+ normalizedCallsign ? /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "mx-[3px] h-3.5 w-px bg-gray-200" }) : null,
69
73
  /* @__PURE__ */ jsx("span", { className: "inline-flex items-center gap-1.5", children: links.map((link) => /* @__PURE__ */ jsx(CasePanelIdentityLinkButton, { link }, link.id)) })
70
74
  ] }) : null
71
75
  ] });
72
76
  }
73
77
  function CasePanelIdentityLinkButton({ link }) {
74
- var _a;
78
+ var _a, _b, _c;
75
79
  const disabled = link.disabled || !link.href;
76
80
  const iconOnly = link.kind === "icon";
77
81
  const content = iconOnly ? /* @__PURE__ */ jsx(Fragment, { children: (_a = link.icon) != null ? _a : /* @__PURE__ */ jsx(ExternalLink, { className: "h-[13px] w-[13px]", "aria-hidden": "true" }) }) : /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -83,7 +87,17 @@ function CasePanelIdentityLinkButton({ link }) {
83
87
  if (disabled) {
84
88
  return /* @__PURE__ */ jsx("button", { type: "button", disabled: true, "aria-label": link.label, className, children: content });
85
89
  }
86
- return /* @__PURE__ */ jsx("a", { href: link.href, "aria-label": link.label, className, children: content });
90
+ return /* @__PURE__ */ jsx(
91
+ "a",
92
+ {
93
+ href: link.href,
94
+ "aria-label": link.label,
95
+ target: (_b = link.target) != null ? _b : "_blank",
96
+ rel: (_c = link.rel) != null ? _c : "noopener noreferrer",
97
+ className,
98
+ children: content
99
+ }
100
+ );
87
101
  }
88
102
  function CasePanelSignalBrief({
89
103
  children,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/case-panel-detail.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ArrowUpRight,\n Check,\n Copy,\n ExternalLink,\n} from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\nexport type CasePanelDetailWidth = \"comfortable\" | \"modest\" | \"full\"\n\nexport interface CasePanelDetailProps {\n children: React.ReactNode\n /** Reading measure for the detail content column. Defaults to the handoff's comfortable 880px measure. */\n width?: CasePanelDetailWidth\n /** Accessible label for the detail region. */\n \"aria-label\"?: string\n className?: string\n}\n\nconst detailWidthClasses: Record<CasePanelDetailWidth, string> = {\n comfortable: \"mx-auto w-full max-w-[880px] px-10 pb-[120px] pt-8\",\n modest: \"mx-auto w-full max-w-[720px] px-8 pb-[112px] pt-7\",\n full: \"w-full px-8 pb-[120px] pt-8\",\n}\n\nexport function CasePanelDetail({\n children,\n width = \"comfortable\",\n \"aria-label\": ariaLabel = \"Case detail\",\n className,\n}: CasePanelDetailProps) {\n return (\n <section aria-label={ariaLabel} className={cn(\"min-w-0 bg-background\", className)}>\n <div className={detailWidthClasses[width]}>{children}</div>\n </section>\n )\n}\n\nexport interface CasePanelHeaderProps {\n title: React.ReactNode\n /** Optional action, usually a Quick action trigger. */\n action?: React.ReactNode\n children?: React.ReactNode\n className?: string\n}\n\nexport function CasePanelHeader({\n title,\n action,\n children,\n className,\n}: CasePanelHeaderProps) {\n return (\n <header className={cn(\"mb-7\", className)}>\n <div className=\"flex items-start justify-between gap-5\">\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"m-0 text-[27px] font-bold leading-[1.18] tracking-[-0.02em] text-foreground [text-wrap:balance]\">\n {title}\n </h1>\n {children}\n </div>\n {action ? <div className=\"flex shrink-0 items-center gap-2\">{action}</div> : null}\n </div>\n </header>\n )\n}\n\nexport interface CasePanelIdentityLink {\n id: string\n label: string\n href?: string\n icon?: React.ReactNode\n kind?: \"icon\" | \"text\"\n disabled?: boolean\n}\n\nexport interface CasePanelIdentitySublineProps {\n callsign: string\n links?: CasePanelIdentityLink[]\n onCopyCallsign?: (callsign: string) => void\n copyLabel?: string\n copiedLabel?: string\n className?: string\n}\n\nexport function CasePanelIdentitySubline({\n callsign,\n links = [],\n onCopyCallsign,\n copyLabel = \"Copy call sign\",\n copiedLabel = \"Call sign copied\",\n className,\n}: CasePanelIdentitySublineProps) {\n const [copied, setCopied] = React.useState(false)\n const normalizedCallsign = callsign.startsWith(\"@\") ? callsign : `@${callsign}`\n\n const handleCopy = React.useCallback(() => {\n onCopyCallsign?.(normalizedCallsign)\n setCopied(true)\n window.setTimeout(() => setCopied(false), 1400)\n }, [normalizedCallsign, onCopyCallsign])\n\n return (\n <div className={cn(\"mt-[9px] inline-flex flex-wrap items-center gap-[7px] text-[13px] text-muted-foreground\", className)}>\n <span className=\"font-mono font-medium tracking-[0.01em] text-gray-700\">{normalizedCallsign}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={copied ? copiedLabel : copyLabel}\n className=\"inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground\"\n >\n {copied ? <Check className=\"h-[13px] w-[13px] text-emerald-700\" aria-hidden=\"true\" /> : <Copy className=\"h-[13px] w-[13px]\" aria-hidden=\"true\" />}\n </button>\n {links.length > 0 ? (\n <>\n <span aria-hidden=\"true\" className=\"mx-[3px] h-3.5 w-px bg-gray-200\" />\n <span className=\"inline-flex items-center gap-1.5\">\n {links.map((link) => (\n <CasePanelIdentityLinkButton key={link.id} link={link} />\n ))}\n </span>\n </>\n ) : null}\n </div>\n )\n}\n\nfunction CasePanelIdentityLinkButton({ link }: { link: CasePanelIdentityLink }) {\n const disabled = link.disabled || !link.href\n const iconOnly = link.kind === \"icon\"\n const content = iconOnly ? (\n <>{link.icon ?? <ExternalLink className=\"h-[13px] w-[13px]\" aria-hidden=\"true\" />}</>\n ) : (\n <>\n {link.icon ? <span className=\"inline-flex h-3.5 w-3.5 items-center justify-center\">{link.icon}</span> : null}\n <span>{link.label}</span>\n <ArrowUpRight className=\"h-[11px] w-[11px] text-gray-400\" aria-hidden=\"true\" />\n </>\n )\n\n const className = iconOnly\n ? \"inline-flex h-[26px] w-[26px] items-center justify-center rounded-[7px] border border-border bg-background text-foreground shadow-[0_1px_1.5px_rgba(0,0,0,0.03)] transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-45\"\n : \"inline-flex h-[26px] items-center gap-1.5 rounded-[7px] border border-border bg-background px-2 text-xs font-medium text-foreground shadow-[0_1px_1.5px_rgba(0,0,0,0.03)] transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-45\"\n\n if (disabled) {\n return (\n <button type=\"button\" disabled aria-label={link.label} className={className}>\n {content}\n </button>\n )\n }\n\n return (\n <a href={link.href} aria-label={link.label} className={className}>\n {content}\n </a>\n )\n}\n\nexport interface CasePanelSignalBriefProps {\n children: React.ReactNode\n label?: string\n className?: string\n}\n\nexport function CasePanelSignalBrief({\n children,\n label = \"Signal brief\",\n className,\n}: CasePanelSignalBriefProps) {\n return (\n <section className={cn(\"mt-7\", className)} aria-labelledby=\"case-panel-signal-brief-heading\">\n <div id=\"case-panel-signal-brief-heading\" className=\"mb-2.5 text-[11px] font-semibold uppercase tracking-[0.07em] text-muted-foreground\">\n {label}\n </div>\n <div className=\"text-base leading-[1.6] text-foreground [text-wrap:pretty]\">{children}</div>\n </section>\n )\n}\n\nexport interface CasePanelMetadataRowProps {\n children: React.ReactNode\n label?: string\n className?: string\n}\n\nexport function CasePanelMetadataRow({\n children,\n label = \"Case metadata\",\n className,\n}: CasePanelMetadataRowProps) {\n return (\n <div aria-label={label} className={cn(\"mt-[18px] flex flex-wrap items-center gap-2\", className)}>\n {children}\n </div>\n )\n}\n\nexport interface CasePanelDetailSlotsProps {\n why?: React.ReactNode\n actions?: React.ReactNode\n opportunity?: React.ReactNode\n timeline?: React.ReactNode\n playPanel?: React.ReactNode\n className?: string\n}\n\nexport function CasePanelDetailSlots({\n why,\n actions,\n opportunity,\n timeline,\n playPanel,\n className,\n}: CasePanelDetailSlotsProps) {\n return (\n <div className={cn(\"mt-7 space-y-6\", className)}>\n {why ? <div data-slot=\"why\">{why}</div> : null}\n {actions ? <div data-slot=\"actions\">{actions}</div> : null}\n {opportunity ? <div data-slot=\"opportunity\">{opportunity}</div> : null}\n {timeline ? <div data-slot=\"timeline\">{timeline}</div> : null}\n {playPanel ? <div data-slot=\"play-panel\">{playPanel}</div> : null}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/case-panel-detail.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport {\n ArrowUpRight,\n Check,\n Copy,\n ExternalLink,\n} from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\nexport type CasePanelDetailWidth = \"comfortable\" | \"modest\" | \"full\"\n\nexport interface CasePanelDetailProps {\n children: React.ReactNode\n /** Reading measure for the detail content column. Defaults to the handoff's comfortable 880px measure. */\n width?: CasePanelDetailWidth\n /** Accessible label for the detail region. */\n \"aria-label\"?: string\n className?: string\n}\n\nconst detailWidthClasses: Record<CasePanelDetailWidth, string> = {\n comfortable: \"mx-auto w-full max-w-[880px] px-10 pb-[120px] pt-8\",\n modest: \"mx-auto w-full max-w-[720px] px-8 pb-[112px] pt-7\",\n full: \"w-full px-8 pb-[120px] pt-8\",\n}\n\nexport function CasePanelDetail({\n children,\n width = \"comfortable\",\n \"aria-label\": ariaLabel = \"Case detail\",\n className,\n}: CasePanelDetailProps) {\n return (\n <section aria-label={ariaLabel} className={cn(\"min-w-0 bg-background\", className)}>\n <div className={detailWidthClasses[width]}>{children}</div>\n </section>\n )\n}\n\nexport interface CasePanelHeaderProps {\n title: React.ReactNode\n /** Optional action, usually a Quick action trigger. */\n action?: React.ReactNode\n children?: React.ReactNode\n className?: string\n}\n\nexport function CasePanelHeader({\n title,\n action,\n children,\n className,\n}: CasePanelHeaderProps) {\n return (\n <header className={cn(\"mb-7\", className)}>\n <div className=\"flex items-start justify-between gap-5\">\n <div className=\"min-w-0 flex-1\">\n <h1 className=\"m-0 text-[27px] font-bold leading-[1.18] tracking-[-0.02em] text-foreground [text-wrap:balance]\">\n {title}\n </h1>\n {children}\n </div>\n {action ? <div className=\"flex shrink-0 items-center gap-2\">{action}</div> : null}\n </div>\n </header>\n )\n}\n\nexport interface CasePanelIdentityLink {\n id: string\n label: string\n href?: string\n icon?: React.ReactNode\n kind?: \"icon\" | \"text\"\n disabled?: boolean\n target?: React.HTMLAttributeAnchorTarget\n rel?: string\n}\n\nexport interface CasePanelIdentitySublineProps {\n callsign?: string | null\n links?: CasePanelIdentityLink[]\n onCopyCallsign?: (callsign: string) => void\n copyLabel?: string\n copiedLabel?: string\n className?: string\n}\n\nexport function CasePanelIdentitySubline({\n callsign,\n links = [],\n onCopyCallsign,\n copyLabel = \"Copy call sign\",\n copiedLabel = \"Call sign copied\",\n className,\n}: CasePanelIdentitySublineProps) {\n const [copied, setCopied] = React.useState(false)\n const trimmedCallsign = callsign?.trim()\n const normalizedCallsign = trimmedCallsign\n ? trimmedCallsign.startsWith(\"@\")\n ? trimmedCallsign\n : `@${trimmedCallsign}`\n : null\n\n const handleCopy = React.useCallback(() => {\n if (!normalizedCallsign) return\n onCopyCallsign?.(normalizedCallsign)\n setCopied(true)\n window.setTimeout(() => setCopied(false), 1400)\n }, [normalizedCallsign, onCopyCallsign])\n\n return (\n <div className={cn(\"mt-[9px] inline-flex flex-wrap items-center gap-[7px] text-[13px] text-muted-foreground\", className)}>\n {normalizedCallsign ? (\n <>\n <span className=\"font-mono font-medium tracking-[0.01em] text-gray-700\">{normalizedCallsign}</span>\n <button\n type=\"button\"\n onClick={handleCopy}\n aria-label={copied ? copiedLabel : copyLabel}\n className=\"inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground\"\n >\n {copied ? <Check className=\"h-[13px] w-[13px] text-emerald-700\" aria-hidden=\"true\" /> : <Copy className=\"h-[13px] w-[13px]\" aria-hidden=\"true\" />}\n </button>\n </>\n ) : null}\n {links.length > 0 ? (\n <>\n {normalizedCallsign ? <span aria-hidden=\"true\" className=\"mx-[3px] h-3.5 w-px bg-gray-200\" /> : null}\n <span className=\"inline-flex items-center gap-1.5\">\n {links.map((link) => (\n <CasePanelIdentityLinkButton key={link.id} link={link} />\n ))}\n </span>\n </>\n ) : null}\n </div>\n )\n}\n\nfunction CasePanelIdentityLinkButton({ link }: { link: CasePanelIdentityLink }) {\n const disabled = link.disabled || !link.href\n const iconOnly = link.kind === \"icon\"\n const content = iconOnly ? (\n <>{link.icon ?? <ExternalLink className=\"h-[13px] w-[13px]\" aria-hidden=\"true\" />}</>\n ) : (\n <>\n {link.icon ? <span className=\"inline-flex h-3.5 w-3.5 items-center justify-center\">{link.icon}</span> : null}\n <span>{link.label}</span>\n <ArrowUpRight className=\"h-[11px] w-[11px] text-gray-400\" aria-hidden=\"true\" />\n </>\n )\n\n const className = iconOnly\n ? \"inline-flex h-[26px] w-[26px] items-center justify-center rounded-[7px] border border-border bg-background text-foreground shadow-[0_1px_1.5px_rgba(0,0,0,0.03)] transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-45\"\n : \"inline-flex h-[26px] items-center gap-1.5 rounded-[7px] border border-border bg-background px-2 text-xs font-medium text-foreground shadow-[0_1px_1.5px_rgba(0,0,0,0.03)] transition-colors hover:bg-gray-50 disabled:cursor-not-allowed disabled:opacity-45\"\n\n if (disabled) {\n return (\n <button type=\"button\" disabled aria-label={link.label} className={className}>\n {content}\n </button>\n )\n }\n\n return (\n <a\n href={link.href}\n aria-label={link.label}\n target={link.target ?? \"_blank\"}\n rel={link.rel ?? \"noopener noreferrer\"}\n className={className}\n >\n {content}\n </a>\n )\n}\n\nexport interface CasePanelSignalBriefProps {\n children: React.ReactNode\n label?: string\n className?: string\n}\n\nexport function CasePanelSignalBrief({\n children,\n label = \"Signal brief\",\n className,\n}: CasePanelSignalBriefProps) {\n return (\n <section className={cn(\"mt-7\", className)} aria-labelledby=\"case-panel-signal-brief-heading\">\n <div id=\"case-panel-signal-brief-heading\" className=\"mb-2.5 text-[11px] font-semibold uppercase tracking-[0.07em] text-muted-foreground\">\n {label}\n </div>\n <div className=\"text-base leading-[1.6] text-foreground [text-wrap:pretty]\">{children}</div>\n </section>\n )\n}\n\nexport interface CasePanelMetadataRowProps {\n children: React.ReactNode\n label?: string\n className?: string\n}\n\nexport function CasePanelMetadataRow({\n children,\n label = \"Case metadata\",\n className,\n}: CasePanelMetadataRowProps) {\n return (\n <div aria-label={label} className={cn(\"mt-[18px] flex flex-wrap items-center gap-2\", className)}>\n {children}\n </div>\n )\n}\n\nexport interface CasePanelDetailSlotsProps {\n why?: React.ReactNode\n actions?: React.ReactNode\n opportunity?: React.ReactNode\n timeline?: React.ReactNode\n playPanel?: React.ReactNode\n className?: string\n}\n\nexport function CasePanelDetailSlots({\n why,\n actions,\n opportunity,\n timeline,\n playPanel,\n className,\n}: CasePanelDetailSlotsProps) {\n return (\n <div className={cn(\"mt-7 space-y-6\", className)}>\n {why ? <div data-slot=\"why\">{why}</div> : null}\n {actions ? <div data-slot=\"actions\">{actions}</div> : null}\n {opportunity ? <div data-slot=\"opportunity\">{opportunity}</div> : null}\n {timeline ? <div data-slot=\"timeline\">{timeline}</div> : null}\n {playPanel ? <div data-slot=\"play-panel\">{playPanel}</div> : null}\n </div>\n )\n}\n"],"mappings":"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","names":[]}
@@ -41,6 +41,7 @@ interface CasePanelEmailComposerProps extends Omit<React.HTMLAttributes<HTMLDivE
41
41
  sendBarActions?: React.ReactNode;
42
42
  signatureControl?: React.ReactNode;
43
43
  disabledReason?: React.ReactNode;
44
+ showSendBar?: boolean;
44
45
  disabled?: boolean;
45
46
  sendDisabled?: boolean;
46
47
  sendLabel?: React.ReactNode;
@@ -56,6 +57,6 @@ interface CasePanelEmailComposerProps extends Omit<React.HTMLAttributes<HTMLDivE
56
57
  showRecipientActionChips?: boolean;
57
58
  onComposerKeyDown?: React.KeyboardEventHandler<HTMLDivElement>;
58
59
  }
59
- declare function CasePanelEmailComposer({ title, providerLabel, recipientRows, from, to, cc, bcc, subject, toState, draftEditor, toolbar, sendBarActions, signatureControl, disabledReason, disabled, sendDisabled, sendLabel, onSendIntent, onContactsIntent, onAccountDetailsIntent, onAddCcIntent, onAddBccIntent, contactsLabel, accountDetailsLabel, addCcLabel, addBccLabel, showRecipientActionChips, onComposerKeyDown, className, ...props }: CasePanelEmailComposerProps): React.JSX.Element;
60
+ declare function CasePanelEmailComposer({ title, providerLabel, recipientRows, from, to, cc, bcc, subject, toState, draftEditor, toolbar, sendBarActions, signatureControl, disabledReason, showSendBar, disabled, sendDisabled, sendLabel, onSendIntent, onContactsIntent, onAccountDetailsIntent, onAddCcIntent, onAddBccIntent, contactsLabel, accountDetailsLabel, addCcLabel, addBccLabel, showRecipientActionChips, onComposerKeyDown, className, ...props }: CasePanelEmailComposerProps): React.JSX.Element;
60
61
 
61
62
  export { CasePanelEmailComposer, CasePanelEmailComposerChip, type CasePanelEmailComposerChipProps, type CasePanelEmailComposerProps, CasePanelEmailComposerRow, type CasePanelEmailComposerRowProps, type CasePanelEmailComposerRowState, CasePanelEmailComposerSignatureRow, type CasePanelEmailComposerSignatureRowProps, type CasePanelEmailComposerSlotHelpers };
@@ -163,6 +163,7 @@ function CasePanelEmailComposer(_g) {
163
163
  sendBarActions,
164
164
  signatureControl,
165
165
  disabledReason,
166
+ showSendBar = true,
166
167
  disabled = false,
167
168
  sendDisabled = false,
168
169
  sendLabel = "Send",
@@ -193,6 +194,7 @@ function CasePanelEmailComposer(_g) {
193
194
  "sendBarActions",
194
195
  "signatureControl",
195
196
  "disabledReason",
197
+ "showSendBar",
196
198
  "disabled",
197
199
  "sendDisabled",
198
200
  "sendLabel",
@@ -272,7 +274,7 @@ function CasePanelEmailComposer(_g) {
272
274
  /* @__PURE__ */ jsx("div", { "data-slot": "case-panel-email-composer-editor", className: "min-h-40 px-4 py-4 text-sm text-foreground", children: draftEditor != null ? draftEditor : /* @__PURE__ */ jsx("div", { className: "text-muted-foreground", children: "Draft editor slot" }) }),
273
275
  signatureControl ? /* @__PURE__ */ jsx("div", { "data-slot": "case-panel-email-composer-signature-control", children: signatureControl }) : /* @__PURE__ */ jsx(CasePanelEmailComposerSignatureRow, { disabled }),
274
276
  /* @__PURE__ */ jsx("div", { "data-slot": "case-panel-email-composer-toolbar", className: "flex min-h-11 items-center gap-2 border-t border-border/70 bg-muted/10 px-3 py-2", children: toolbar != null ? toolbar : /* @__PURE__ */ jsx("div", { className: "text-xs font-medium text-muted-foreground", children: "Toolbar" }) }),
275
- /* @__PURE__ */ jsxs("div", { "data-slot": "case-panel-email-composer-send-bar", className: "flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3", children: [
277
+ showSendBar ? /* @__PURE__ */ jsxs("div", { "data-slot": "case-panel-email-composer-send-bar", className: "flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3", children: [
276
278
  /* @__PURE__ */ jsx("div", { className: "min-w-0 flex-1", children: disabledReason ? /* @__PURE__ */ jsx("div", { id: disabledReasonId, "data-slot": "case-panel-email-composer-disabled-reason", className: "truncate text-xs text-muted-foreground", children: disabledReason }) : null }),
277
279
  /* @__PURE__ */ jsxs("div", { className: "flex shrink-0 items-center gap-2", children: [
278
280
  sendBarActions,
@@ -289,7 +291,7 @@ function CasePanelEmailComposer(_g) {
289
291
  }
290
292
  )
291
293
  ] })
292
- ] })
294
+ ] }) : null
293
295
  ] })
294
296
  ]
295
297
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/case-panel-email-composer.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"../lib/utils\"\nimport { BRAND_ICONS } from \"../lib/icons\"\n\nexport type CasePanelEmailComposerRowState = \"default\" | \"confirmed\" | \"unconfirmed\"\n\nexport interface CasePanelEmailComposerRowProps extends React.HTMLAttributes<HTMLDivElement> {\n label: React.ReactNode\n children?: React.ReactNode\n value?: React.ReactNode\n placeholder?: React.ReactNode\n actions?: React.ReactNode\n state?: CasePanelEmailComposerRowState\n}\n\nexport function CasePanelEmailComposerRow({\n label,\n children,\n value,\n placeholder,\n actions,\n state = \"default\",\n className,\n ...props\n}: CasePanelEmailComposerRowProps) {\n const content = children ?? value ?? placeholder\n const rowClassName =\n state === \"unconfirmed\"\n ? \"flex min-h-11 items-stretch border-b border-amber-200/80 bg-amber-50/75 text-sm dark:border-amber-900/50 dark:bg-amber-950/20\"\n : \"flex min-h-11 items-stretch border-b border-border/70 bg-background text-sm\"\n const labelClassName =\n state === \"unconfirmed\"\n ? \"flex w-[60px] shrink-0 items-center border-r border-amber-200/80 px-3 text-[11px] font-semibold uppercase tracking-wide text-amber-700 dark:border-amber-900/50 dark:text-amber-300\"\n : \"flex w-[60px] shrink-0 items-center border-r border-border/70 px-3 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\"\n const contentClassName =\n state === \"unconfirmed\"\n ? \"flex min-w-0 flex-1 items-center gap-2 px-3 py-2 text-amber-950 dark:text-amber-100\"\n : \"flex min-w-0 flex-1 items-center gap-2 px-3 py-2 text-foreground\"\n const placeholderClassName =\n state === \"unconfirmed\"\n ? \"min-w-0 truncate text-amber-700/80 dark:text-amber-200/80\"\n : \"min-w-0 truncate text-muted-foreground\"\n\n return (\n <div\n data-slot=\"case-panel-email-composer-row\"\n data-state={state}\n className={cn(rowClassName, className)}\n {...props}\n >\n <div data-slot=\"case-panel-email-composer-row-label\" className={labelClassName}>\n {label}\n </div>\n <div data-slot=\"case-panel-email-composer-row-content\" className={contentClassName}>\n {content ? (\n <div className=\"min-w-0 flex-1 truncate\">{content}</div>\n ) : (\n <div className={placeholderClassName}>Add {label}</div>\n )}\n {actions ? <div className=\"flex shrink-0 items-center gap-1.5\">{actions}</div> : null}\n </div>\n </div>\n )\n}\n\nexport interface CasePanelEmailComposerChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n children: React.ReactNode\n}\n\nexport function CasePanelEmailComposerChip({\n children,\n className,\n type = \"button\",\n ...props\n}: CasePanelEmailComposerChipProps) {\n return (\n <button\n data-slot=\"case-panel-email-composer-chip\"\n type={type}\n className={cn(\n \"inline-flex h-6 items-center justify-center rounded-full border border-border bg-background px-2.5 text-[11px] font-medium text-muted-foreground shadow-xs transition-colors hover:bg-muted/60 hover:text-foreground disabled:pointer-events-none disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n )\n}\n\nexport interface CasePanelEmailComposerSignatureRowProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode\n label?: React.ReactNode\n checked?: boolean\n disabled?: boolean\n}\n\nexport function CasePanelEmailComposerSignatureRow({\n children,\n label = \"Include signature\",\n checked = true,\n disabled,\n className,\n ...props\n}: CasePanelEmailComposerSignatureRowProps) {\n return (\n <div\n data-slot=\"case-panel-email-composer-signature-row\"\n className={cn(\n \"flex items-center justify-between border-t border-border/70 bg-muted/20 px-4 py-2.5 text-xs text-muted-foreground\",\n className,\n )}\n {...props}\n >\n {children ?? (\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden=\"true\"\n data-checked={checked ? \"true\" : \"false\"}\n className={\n checked\n ? \"flex size-4 items-center justify-center rounded border border-foreground bg-foreground text-[10px] leading-none text-background\"\n : \"flex size-4 items-center justify-center rounded border border-border bg-background text-[10px] leading-none text-background\"\n }\n >\n {checked ? \"✓\" : \"\"}\n </span>\n <span className={disabled ? \"text-muted-foreground/60\" : \"text-muted-foreground\"}>{label}</span>\n </div>\n )}\n </div>\n )\n}\n\nexport interface CasePanelEmailComposerSlotHelpers {\n Row: typeof CasePanelEmailComposerRow\n Chip: typeof CasePanelEmailComposerChip\n SignatureRow: typeof CasePanelEmailComposerSignatureRow\n}\n\nexport interface CasePanelEmailComposerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onKeyDown\" | \"title\"> {\n title?: React.ReactNode\n providerLabel?: React.ReactNode\n recipientRows?: React.ReactNode | ((helpers: CasePanelEmailComposerSlotHelpers) => React.ReactNode)\n from?: React.ReactNode\n to?: React.ReactNode\n cc?: React.ReactNode\n bcc?: React.ReactNode\n subject?: React.ReactNode\n toState?: CasePanelEmailComposerRowState\n draftEditor?: React.ReactNode\n toolbar?: React.ReactNode\n sendBarActions?: React.ReactNode\n signatureControl?: React.ReactNode\n disabledReason?: React.ReactNode\n disabled?: boolean\n sendDisabled?: boolean\n sendLabel?: React.ReactNode\n onSendIntent?: () => void\n onContactsIntent?: () => void\n onAccountDetailsIntent?: () => void\n onAddCcIntent?: () => void\n onAddBccIntent?: () => void\n contactsLabel?: React.ReactNode\n accountDetailsLabel?: React.ReactNode\n addCcLabel?: React.ReactNode\n addBccLabel?: React.ReactNode\n showRecipientActionChips?: boolean\n onComposerKeyDown?: React.KeyboardEventHandler<HTMLDivElement>\n}\n\nconst slotHelpers: CasePanelEmailComposerSlotHelpers = {\n Row: CasePanelEmailComposerRow,\n Chip: CasePanelEmailComposerChip,\n SignatureRow: CasePanelEmailComposerSignatureRow,\n}\n\nexport function CasePanelEmailComposer({\n title = \"Draft\",\n providerLabel = \"Gmail\",\n recipientRows,\n from,\n to,\n cc,\n bcc,\n subject,\n toState = \"default\",\n draftEditor,\n toolbar,\n sendBarActions,\n signatureControl,\n disabledReason,\n disabled = false,\n sendDisabled = false,\n sendLabel = \"Send\",\n onSendIntent,\n onContactsIntent,\n onAccountDetailsIntent,\n onAddCcIntent,\n onAddBccIntent,\n contactsLabel = \"Contacts\",\n accountDetailsLabel = \"Account details\",\n addCcLabel = \"Add Cc\",\n addBccLabel = \"Add Bcc\",\n showRecipientActionChips = true,\n onComposerKeyDown,\n className,\n ...props\n}: CasePanelEmailComposerProps) {\n const disabledReasonId = React.useId()\n const sendIsDisabled = disabled || sendDisabled || Boolean(disabledReason)\n\n const handleSendIntent = React.useCallback(() => {\n if (sendIsDisabled) return\n onSendIntent?.()\n }, [onSendIntent, sendIsDisabled])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n onComposerKeyDown?.(event)\n if (event.defaultPrevented) return\n if (event.key === \"Enter\" && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleSendIntent()\n }\n },\n [handleSendIntent, onComposerKeyDown],\n )\n\n const renderedRecipientRows =\n typeof recipientRows === \"function\"\n ? recipientRows(slotHelpers)\n : recipientRows ?? (\n <>\n <CasePanelEmailComposerRow label=\"From\" value={from} placeholder=\"Sender\" />\n <CasePanelEmailComposerRow label=\"To\" value={to} placeholder=\"Recipient\" state={toState} />\n {cc ? <CasePanelEmailComposerRow label=\"Cc\" value={cc} /> : null}\n {bcc ? <CasePanelEmailComposerRow label=\"Bcc\" value={bcc} /> : null}\n <CasePanelEmailComposerRow label=\"Subject\" value={subject} placeholder=\"Subject\" />\n </>\n )\n\n const showActionChips =\n showRecipientActionChips &&\n (onContactsIntent || onAccountDetailsIntent || onAddCcIntent || onAddBccIntent)\n\n return (\n <div\n data-slot=\"case-panel-email-composer\"\n aria-disabled={disabled ? \"true\" : undefined}\n className={cn(\n \"overflow-hidden rounded-xl border border-border bg-background shadow-sm\",\n className,\n )}\n onKeyDown={handleKeyDown}\n {...props}\n >\n <div data-slot=\"case-panel-email-composer-header\" className=\"flex items-center justify-between border-b border-border/70 bg-muted/20 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <img\n src={BRAND_ICONS.gmail.icon}\n alt=\"Gmail\"\n className=\"size-4 shrink-0 object-contain\"\n draggable={false}\n />\n <div className=\"min-w-0 truncate text-sm font-semibold text-foreground\">{title}</div>\n </div>\n <div className=\"shrink-0 text-[11px] font-medium text-muted-foreground\">{providerLabel}</div>\n </div>\n\n <div data-slot=\"case-panel-email-composer-card\" className=\"bg-background\">\n <div data-slot=\"case-panel-email-composer-recipient-rows\">{renderedRecipientRows}</div>\n\n {showActionChips ? (\n <div data-slot=\"case-panel-email-composer-chip-row\" className=\"flex flex-wrap items-center gap-1.5 border-b border-border/70 bg-muted/10 px-3 py-2\">\n {onContactsIntent ? (\n <CasePanelEmailComposerChip onClick={onContactsIntent} disabled={disabled}>\n {contactsLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAccountDetailsIntent ? (\n <CasePanelEmailComposerChip onClick={onAccountDetailsIntent} disabled={disabled}>\n {accountDetailsLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAddCcIntent ? (\n <CasePanelEmailComposerChip onClick={onAddCcIntent} disabled={disabled}>\n {addCcLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAddBccIntent ? (\n <CasePanelEmailComposerChip onClick={onAddBccIntent} disabled={disabled}>\n {addBccLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n </div>\n ) : null}\n\n <div data-slot=\"case-panel-email-composer-editor\" className=\"min-h-40 px-4 py-4 text-sm text-foreground\">\n {draftEditor ?? <div className=\"text-muted-foreground\">Draft editor slot</div>}\n </div>\n\n {signatureControl ? (\n <div data-slot=\"case-panel-email-composer-signature-control\">{signatureControl}</div>\n ) : (\n <CasePanelEmailComposerSignatureRow disabled={disabled} />\n )}\n\n <div data-slot=\"case-panel-email-composer-toolbar\" className=\"flex min-h-11 items-center gap-2 border-t border-border/70 bg-muted/10 px-3 py-2\">\n {toolbar ?? <div className=\"text-xs font-medium text-muted-foreground\">Toolbar</div>}\n </div>\n\n <div data-slot=\"case-panel-email-composer-send-bar\" className=\"flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3\">\n <div className=\"min-w-0 flex-1\">\n {disabledReason ? (\n <div id={disabledReasonId} data-slot=\"case-panel-email-composer-disabled-reason\" className=\"truncate text-xs text-muted-foreground\">\n {disabledReason}\n </div>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {sendBarActions}\n <button\n type=\"button\"\n data-slot=\"case-panel-email-composer-send-button\"\n aria-describedby={disabledReason ? disabledReasonId : undefined}\n disabled={sendIsDisabled}\n onClick={handleSendIntent}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-foreground px-3 text-xs font-semibold text-background shadow-xs transition-colors hover:bg-foreground/90 disabled:pointer-events-none disabled:bg-muted disabled:text-muted-foreground\"\n >\n {sendLabel}\n </button>\n </div>\n </div>\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
1
+ {"version":3,"sources":["../../src/components/case-panel-email-composer.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\n\nimport { cn } from \"../lib/utils\"\nimport { BRAND_ICONS } from \"../lib/icons\"\n\nexport type CasePanelEmailComposerRowState = \"default\" | \"confirmed\" | \"unconfirmed\"\n\nexport interface CasePanelEmailComposerRowProps extends React.HTMLAttributes<HTMLDivElement> {\n label: React.ReactNode\n children?: React.ReactNode\n value?: React.ReactNode\n placeholder?: React.ReactNode\n actions?: React.ReactNode\n state?: CasePanelEmailComposerRowState\n}\n\nexport function CasePanelEmailComposerRow({\n label,\n children,\n value,\n placeholder,\n actions,\n state = \"default\",\n className,\n ...props\n}: CasePanelEmailComposerRowProps) {\n const content = children ?? value ?? placeholder\n const rowClassName =\n state === \"unconfirmed\"\n ? \"flex min-h-11 items-stretch border-b border-amber-200/80 bg-amber-50/75 text-sm dark:border-amber-900/50 dark:bg-amber-950/20\"\n : \"flex min-h-11 items-stretch border-b border-border/70 bg-background text-sm\"\n const labelClassName =\n state === \"unconfirmed\"\n ? \"flex w-[60px] shrink-0 items-center border-r border-amber-200/80 px-3 text-[11px] font-semibold uppercase tracking-wide text-amber-700 dark:border-amber-900/50 dark:text-amber-300\"\n : \"flex w-[60px] shrink-0 items-center border-r border-border/70 px-3 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground\"\n const contentClassName =\n state === \"unconfirmed\"\n ? \"flex min-w-0 flex-1 items-center gap-2 px-3 py-2 text-amber-950 dark:text-amber-100\"\n : \"flex min-w-0 flex-1 items-center gap-2 px-3 py-2 text-foreground\"\n const placeholderClassName =\n state === \"unconfirmed\"\n ? \"min-w-0 truncate text-amber-700/80 dark:text-amber-200/80\"\n : \"min-w-0 truncate text-muted-foreground\"\n\n return (\n <div\n data-slot=\"case-panel-email-composer-row\"\n data-state={state}\n className={cn(rowClassName, className)}\n {...props}\n >\n <div data-slot=\"case-panel-email-composer-row-label\" className={labelClassName}>\n {label}\n </div>\n <div data-slot=\"case-panel-email-composer-row-content\" className={contentClassName}>\n {content ? (\n <div className=\"min-w-0 flex-1 truncate\">{content}</div>\n ) : (\n <div className={placeholderClassName}>Add {label}</div>\n )}\n {actions ? <div className=\"flex shrink-0 items-center gap-1.5\">{actions}</div> : null}\n </div>\n </div>\n )\n}\n\nexport interface CasePanelEmailComposerChipProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {\n children: React.ReactNode\n}\n\nexport function CasePanelEmailComposerChip({\n children,\n className,\n type = \"button\",\n ...props\n}: CasePanelEmailComposerChipProps) {\n return (\n <button\n data-slot=\"case-panel-email-composer-chip\"\n type={type}\n className={cn(\n \"inline-flex h-6 items-center justify-center rounded-full border border-border bg-background px-2.5 text-[11px] font-medium text-muted-foreground shadow-xs transition-colors hover:bg-muted/60 hover:text-foreground disabled:pointer-events-none disabled:opacity-50\",\n className,\n )}\n {...props}\n >\n {children}\n </button>\n )\n}\n\nexport interface CasePanelEmailComposerSignatureRowProps extends React.HTMLAttributes<HTMLDivElement> {\n children?: React.ReactNode\n label?: React.ReactNode\n checked?: boolean\n disabled?: boolean\n}\n\nexport function CasePanelEmailComposerSignatureRow({\n children,\n label = \"Include signature\",\n checked = true,\n disabled,\n className,\n ...props\n}: CasePanelEmailComposerSignatureRowProps) {\n return (\n <div\n data-slot=\"case-panel-email-composer-signature-row\"\n className={cn(\n \"flex items-center justify-between border-t border-border/70 bg-muted/20 px-4 py-2.5 text-xs text-muted-foreground\",\n className,\n )}\n {...props}\n >\n {children ?? (\n <div className=\"flex items-center gap-2\">\n <span\n aria-hidden=\"true\"\n data-checked={checked ? \"true\" : \"false\"}\n className={\n checked\n ? \"flex size-4 items-center justify-center rounded border border-foreground bg-foreground text-[10px] leading-none text-background\"\n : \"flex size-4 items-center justify-center rounded border border-border bg-background text-[10px] leading-none text-background\"\n }\n >\n {checked ? \"✓\" : \"\"}\n </span>\n <span className={disabled ? \"text-muted-foreground/60\" : \"text-muted-foreground\"}>{label}</span>\n </div>\n )}\n </div>\n )\n}\n\nexport interface CasePanelEmailComposerSlotHelpers {\n Row: typeof CasePanelEmailComposerRow\n Chip: typeof CasePanelEmailComposerChip\n SignatureRow: typeof CasePanelEmailComposerSignatureRow\n}\n\nexport interface CasePanelEmailComposerProps extends Omit<React.HTMLAttributes<HTMLDivElement>, \"onKeyDown\" | \"title\"> {\n title?: React.ReactNode\n providerLabel?: React.ReactNode\n recipientRows?: React.ReactNode | ((helpers: CasePanelEmailComposerSlotHelpers) => React.ReactNode)\n from?: React.ReactNode\n to?: React.ReactNode\n cc?: React.ReactNode\n bcc?: React.ReactNode\n subject?: React.ReactNode\n toState?: CasePanelEmailComposerRowState\n draftEditor?: React.ReactNode\n toolbar?: React.ReactNode\n sendBarActions?: React.ReactNode\n signatureControl?: React.ReactNode\n disabledReason?: React.ReactNode\n showSendBar?: boolean\n disabled?: boolean\n sendDisabled?: boolean\n sendLabel?: React.ReactNode\n onSendIntent?: () => void\n onContactsIntent?: () => void\n onAccountDetailsIntent?: () => void\n onAddCcIntent?: () => void\n onAddBccIntent?: () => void\n contactsLabel?: React.ReactNode\n accountDetailsLabel?: React.ReactNode\n addCcLabel?: React.ReactNode\n addBccLabel?: React.ReactNode\n showRecipientActionChips?: boolean\n onComposerKeyDown?: React.KeyboardEventHandler<HTMLDivElement>\n}\n\nconst slotHelpers: CasePanelEmailComposerSlotHelpers = {\n Row: CasePanelEmailComposerRow,\n Chip: CasePanelEmailComposerChip,\n SignatureRow: CasePanelEmailComposerSignatureRow,\n}\n\nexport function CasePanelEmailComposer({\n title = \"Draft\",\n providerLabel = \"Gmail\",\n recipientRows,\n from,\n to,\n cc,\n bcc,\n subject,\n toState = \"default\",\n draftEditor,\n toolbar,\n sendBarActions,\n signatureControl,\n disabledReason,\n showSendBar = true,\n disabled = false,\n sendDisabled = false,\n sendLabel = \"Send\",\n onSendIntent,\n onContactsIntent,\n onAccountDetailsIntent,\n onAddCcIntent,\n onAddBccIntent,\n contactsLabel = \"Contacts\",\n accountDetailsLabel = \"Account details\",\n addCcLabel = \"Add Cc\",\n addBccLabel = \"Add Bcc\",\n showRecipientActionChips = true,\n onComposerKeyDown,\n className,\n ...props\n}: CasePanelEmailComposerProps) {\n const disabledReasonId = React.useId()\n const sendIsDisabled = disabled || sendDisabled || Boolean(disabledReason)\n\n const handleSendIntent = React.useCallback(() => {\n if (sendIsDisabled) return\n onSendIntent?.()\n }, [onSendIntent, sendIsDisabled])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n onComposerKeyDown?.(event)\n if (event.defaultPrevented) return\n if (event.key === \"Enter\" && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n handleSendIntent()\n }\n },\n [handleSendIntent, onComposerKeyDown],\n )\n\n const renderedRecipientRows =\n typeof recipientRows === \"function\"\n ? recipientRows(slotHelpers)\n : recipientRows ?? (\n <>\n <CasePanelEmailComposerRow label=\"From\" value={from} placeholder=\"Sender\" />\n <CasePanelEmailComposerRow label=\"To\" value={to} placeholder=\"Recipient\" state={toState} />\n {cc ? <CasePanelEmailComposerRow label=\"Cc\" value={cc} /> : null}\n {bcc ? <CasePanelEmailComposerRow label=\"Bcc\" value={bcc} /> : null}\n <CasePanelEmailComposerRow label=\"Subject\" value={subject} placeholder=\"Subject\" />\n </>\n )\n\n const showActionChips =\n showRecipientActionChips &&\n (onContactsIntent || onAccountDetailsIntent || onAddCcIntent || onAddBccIntent)\n\n return (\n <div\n data-slot=\"case-panel-email-composer\"\n aria-disabled={disabled ? \"true\" : undefined}\n className={cn(\n \"overflow-hidden rounded-xl border border-border bg-background shadow-sm\",\n className,\n )}\n onKeyDown={handleKeyDown}\n {...props}\n >\n <div data-slot=\"case-panel-email-composer-header\" className=\"flex items-center justify-between border-b border-border/70 bg-muted/20 px-4 py-3\">\n <div className=\"flex min-w-0 items-center gap-2\">\n <img\n src={BRAND_ICONS.gmail.icon}\n alt=\"Gmail\"\n className=\"size-4 shrink-0 object-contain\"\n draggable={false}\n />\n <div className=\"min-w-0 truncate text-sm font-semibold text-foreground\">{title}</div>\n </div>\n <div className=\"shrink-0 text-[11px] font-medium text-muted-foreground\">{providerLabel}</div>\n </div>\n\n <div data-slot=\"case-panel-email-composer-card\" className=\"bg-background\">\n <div data-slot=\"case-panel-email-composer-recipient-rows\">{renderedRecipientRows}</div>\n\n {showActionChips ? (\n <div data-slot=\"case-panel-email-composer-chip-row\" className=\"flex flex-wrap items-center gap-1.5 border-b border-border/70 bg-muted/10 px-3 py-2\">\n {onContactsIntent ? (\n <CasePanelEmailComposerChip onClick={onContactsIntent} disabled={disabled}>\n {contactsLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAccountDetailsIntent ? (\n <CasePanelEmailComposerChip onClick={onAccountDetailsIntent} disabled={disabled}>\n {accountDetailsLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAddCcIntent ? (\n <CasePanelEmailComposerChip onClick={onAddCcIntent} disabled={disabled}>\n {addCcLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n {onAddBccIntent ? (\n <CasePanelEmailComposerChip onClick={onAddBccIntent} disabled={disabled}>\n {addBccLabel}\n </CasePanelEmailComposerChip>\n ) : null}\n </div>\n ) : null}\n\n <div data-slot=\"case-panel-email-composer-editor\" className=\"min-h-40 px-4 py-4 text-sm text-foreground\">\n {draftEditor ?? <div className=\"text-muted-foreground\">Draft editor slot</div>}\n </div>\n\n {signatureControl ? (\n <div data-slot=\"case-panel-email-composer-signature-control\">{signatureControl}</div>\n ) : (\n <CasePanelEmailComposerSignatureRow disabled={disabled} />\n )}\n\n <div data-slot=\"case-panel-email-composer-toolbar\" className=\"flex min-h-11 items-center gap-2 border-t border-border/70 bg-muted/10 px-3 py-2\">\n {toolbar ?? <div className=\"text-xs font-medium text-muted-foreground\">Toolbar</div>}\n </div>\n\n {showSendBar ? (\n <div data-slot=\"case-panel-email-composer-send-bar\" className=\"flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3\">\n <div className=\"min-w-0 flex-1\">\n {disabledReason ? (\n <div id={disabledReasonId} data-slot=\"case-panel-email-composer-disabled-reason\" className=\"truncate text-xs text-muted-foreground\">\n {disabledReason}\n </div>\n ) : null}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {sendBarActions}\n <button\n type=\"button\"\n data-slot=\"case-panel-email-composer-send-button\"\n aria-describedby={disabledReason ? disabledReasonId : undefined}\n disabled={sendIsDisabled}\n onClick={handleSendIntent}\n className=\"inline-flex h-8 items-center justify-center rounded-md bg-foreground px-3 text-xs font-semibold text-background shadow-xs transition-colors hover:bg-foreground/90 disabled:pointer-events-none disabled:bg-muted disabled:text-muted-foreground\"\n >\n {sendLabel}\n </button>\n </div>\n </div>\n ) : null}\n </div>\n </div>\n )\n}\n"],"mappings":"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","names":["_a"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@handled-ai/design-system",
3
- "version": "0.18.24",
3
+ "version": "0.18.25",
4
4
  "description": "Handled UI component library (shadcn-style, New York)",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@9.12.0",
@@ -58,7 +58,10 @@ describe("CasePanelDetail structure", () => {
58
58
  )
59
59
 
60
60
  expect(screen.getByText("@acme")).toBeTruthy()
61
- expect(screen.getByRole("link", { name: "Open in Salesforce" }).getAttribute("href")).toBe("https://example.com/sf")
61
+ const salesforceLink = screen.getByRole("link", { name: "Open in Salesforce" })
62
+ expect(salesforceLink.getAttribute("href")).toBe("https://example.com/sf")
63
+ expect(salesforceLink.getAttribute("target")).toBe("_blank")
64
+ expect(salesforceLink.getAttribute("rel")).toBe("noopener noreferrer")
62
65
  expect(screen.getByRole("link", { name: "Open in Admin" }).getAttribute("href")).toBe("https://example.com/admin")
63
66
  })
64
67
 
@@ -72,6 +75,19 @@ describe("CasePanelDetail structure", () => {
72
75
  expect(screen.getByRole("button", { name: "Call sign copied" })).toBeTruthy()
73
76
  })
74
77
 
78
+ it("omits copyable callsign chrome when callsign is missing", () => {
79
+ render(
80
+ <CasePanelIdentitySubline
81
+ callsign={null}
82
+ links={[{ id: "admin", label: "Open in Admin", href: "https://example.com/admin", kind: "text" }]}
83
+ />,
84
+ )
85
+
86
+ expect(screen.queryByText(/^@/)).toBeNull()
87
+ expect(screen.queryByRole("button", { name: "Copy call sign" })).toBeNull()
88
+ expect(screen.getByRole("link", { name: "Open in Admin" })).toBeTruthy()
89
+ })
90
+
75
91
  it("renders missing identity links as disabled buttons instead of active links", () => {
76
92
  render(
77
93
  <CasePanelIdentitySubline
@@ -115,6 +115,13 @@ describe("CasePanelEmailComposer", () => {
115
115
  expect(screen.getByRole("button", { name: "Send" })).not.toBeNull()
116
116
  })
117
117
 
118
+ it("can hide the default send bar when the consumer owns send controls", () => {
119
+ const { container } = render(<CasePanelEmailComposer showSendBar={false} />)
120
+
121
+ expect(container.querySelector('[data-slot="case-panel-email-composer-send-bar"]')).toBeNull()
122
+ expect(screen.queryByRole("button", { name: "Send" })).toBeNull()
123
+ })
124
+
118
125
  it("disables send when disabledReason is provided", () => {
119
126
  render(<CasePanelEmailComposer disabledReason="Confirm recipient before sending" />)
120
127
 
@@ -75,10 +75,12 @@ export interface CasePanelIdentityLink {
75
75
  icon?: React.ReactNode
76
76
  kind?: "icon" | "text"
77
77
  disabled?: boolean
78
+ target?: React.HTMLAttributeAnchorTarget
79
+ rel?: string
78
80
  }
79
81
 
80
82
  export interface CasePanelIdentitySublineProps {
81
- callsign: string
83
+ callsign?: string | null
82
84
  links?: CasePanelIdentityLink[]
83
85
  onCopyCallsign?: (callsign: string) => void
84
86
  copyLabel?: string
@@ -95,9 +97,15 @@ export function CasePanelIdentitySubline({
95
97
  className,
96
98
  }: CasePanelIdentitySublineProps) {
97
99
  const [copied, setCopied] = React.useState(false)
98
- const normalizedCallsign = callsign.startsWith("@") ? callsign : `@${callsign}`
100
+ const trimmedCallsign = callsign?.trim()
101
+ const normalizedCallsign = trimmedCallsign
102
+ ? trimmedCallsign.startsWith("@")
103
+ ? trimmedCallsign
104
+ : `@${trimmedCallsign}`
105
+ : null
99
106
 
100
107
  const handleCopy = React.useCallback(() => {
108
+ if (!normalizedCallsign) return
101
109
  onCopyCallsign?.(normalizedCallsign)
102
110
  setCopied(true)
103
111
  window.setTimeout(() => setCopied(false), 1400)
@@ -105,18 +113,22 @@ export function CasePanelIdentitySubline({
105
113
 
106
114
  return (
107
115
  <div className={cn("mt-[9px] inline-flex flex-wrap items-center gap-[7px] text-[13px] text-muted-foreground", className)}>
108
- <span className="font-mono font-medium tracking-[0.01em] text-gray-700">{normalizedCallsign}</span>
109
- <button
110
- type="button"
111
- onClick={handleCopy}
112
- aria-label={copied ? copiedLabel : copyLabel}
113
- className="inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground"
114
- >
115
- {copied ? <Check className="h-[13px] w-[13px] text-emerald-700" aria-hidden="true" /> : <Copy className="h-[13px] w-[13px]" aria-hidden="true" />}
116
- </button>
116
+ {normalizedCallsign ? (
117
+ <>
118
+ <span className="font-mono font-medium tracking-[0.01em] text-gray-700">{normalizedCallsign}</span>
119
+ <button
120
+ type="button"
121
+ onClick={handleCopy}
122
+ aria-label={copied ? copiedLabel : copyLabel}
123
+ className="inline-flex h-[22px] w-[22px] items-center justify-center rounded-md text-gray-400 transition-colors hover:bg-accent hover:text-foreground"
124
+ >
125
+ {copied ? <Check className="h-[13px] w-[13px] text-emerald-700" aria-hidden="true" /> : <Copy className="h-[13px] w-[13px]" aria-hidden="true" />}
126
+ </button>
127
+ </>
128
+ ) : null}
117
129
  {links.length > 0 ? (
118
130
  <>
119
- <span aria-hidden="true" className="mx-[3px] h-3.5 w-px bg-gray-200" />
131
+ {normalizedCallsign ? <span aria-hidden="true" className="mx-[3px] h-3.5 w-px bg-gray-200" /> : null}
120
132
  <span className="inline-flex items-center gap-1.5">
121
133
  {links.map((link) => (
122
134
  <CasePanelIdentityLinkButton key={link.id} link={link} />
@@ -154,7 +166,13 @@ function CasePanelIdentityLinkButton({ link }: { link: CasePanelIdentityLink })
154
166
  }
155
167
 
156
168
  return (
157
- <a href={link.href} aria-label={link.label} className={className}>
169
+ <a
170
+ href={link.href}
171
+ aria-label={link.label}
172
+ target={link.target ?? "_blank"}
173
+ rel={link.rel ?? "noopener noreferrer"}
174
+ className={className}
175
+ >
158
176
  {content}
159
177
  </a>
160
178
  )
@@ -156,6 +156,7 @@ export interface CasePanelEmailComposerProps extends Omit<React.HTMLAttributes<H
156
156
  sendBarActions?: React.ReactNode
157
157
  signatureControl?: React.ReactNode
158
158
  disabledReason?: React.ReactNode
159
+ showSendBar?: boolean
159
160
  disabled?: boolean
160
161
  sendDisabled?: boolean
161
162
  sendLabel?: React.ReactNode
@@ -193,6 +194,7 @@ export function CasePanelEmailComposer({
193
194
  sendBarActions,
194
195
  signatureControl,
195
196
  disabledReason,
197
+ showSendBar = true,
196
198
  disabled = false,
197
199
  sendDisabled = false,
198
200
  sendLabel = "Send",
@@ -313,28 +315,30 @@ export function CasePanelEmailComposer({
313
315
  {toolbar ?? <div className="text-xs font-medium text-muted-foreground">Toolbar</div>}
314
316
  </div>
315
317
 
316
- <div data-slot="case-panel-email-composer-send-bar" className="flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3">
317
- <div className="min-w-0 flex-1">
318
- {disabledReason ? (
319
- <div id={disabledReasonId} data-slot="case-panel-email-composer-disabled-reason" className="truncate text-xs text-muted-foreground">
320
- {disabledReason}
321
- </div>
322
- ) : null}
323
- </div>
324
- <div className="flex shrink-0 items-center gap-2">
325
- {sendBarActions}
326
- <button
327
- type="button"
328
- data-slot="case-panel-email-composer-send-button"
329
- aria-describedby={disabledReason ? disabledReasonId : undefined}
330
- disabled={sendIsDisabled}
331
- onClick={handleSendIntent}
332
- className="inline-flex h-8 items-center justify-center rounded-md bg-foreground px-3 text-xs font-semibold text-background shadow-xs transition-colors hover:bg-foreground/90 disabled:pointer-events-none disabled:bg-muted disabled:text-muted-foreground"
333
- >
334
- {sendLabel}
335
- </button>
318
+ {showSendBar ? (
319
+ <div data-slot="case-panel-email-composer-send-bar" className="flex items-center justify-between gap-3 border-t border-border/70 bg-background px-3 py-3">
320
+ <div className="min-w-0 flex-1">
321
+ {disabledReason ? (
322
+ <div id={disabledReasonId} data-slot="case-panel-email-composer-disabled-reason" className="truncate text-xs text-muted-foreground">
323
+ {disabledReason}
324
+ </div>
325
+ ) : null}
326
+ </div>
327
+ <div className="flex shrink-0 items-center gap-2">
328
+ {sendBarActions}
329
+ <button
330
+ type="button"
331
+ data-slot="case-panel-email-composer-send-button"
332
+ aria-describedby={disabledReason ? disabledReasonId : undefined}
333
+ disabled={sendIsDisabled}
334
+ onClick={handleSendIntent}
335
+ className="inline-flex h-8 items-center justify-center rounded-md bg-foreground px-3 text-xs font-semibold text-background shadow-xs transition-colors hover:bg-foreground/90 disabled:pointer-events-none disabled:bg-muted disabled:text-muted-foreground"
336
+ >
337
+ {sendLabel}
338
+ </button>
339
+ </div>
336
340
  </div>
337
- </div>
341
+ ) : null}
338
342
  </div>
339
343
  </div>
340
344
  )