@handled-ai/design-system 0.18.30 → 0.18.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/related-record-action-card.d.ts +19 -0
- package/dist/components/related-record-action-card.js +147 -0
- package/dist/components/related-record-action-card.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/__tests__/related-record-action-card.test.tsx +122 -0
- package/src/components/related-record-action-card.tsx +166 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type RelatedRecordActionCardKind = "case" | "account" | "opportunity" | "salesforce" | "generic";
|
|
4
|
+
type RelatedRecordActionIcon = "salesforce" | React.ReactNode;
|
|
5
|
+
interface RelatedRecordActionCardProps {
|
|
6
|
+
kind: RelatedRecordActionCardKind;
|
|
7
|
+
label: string;
|
|
8
|
+
subtitle?: string;
|
|
9
|
+
disabledReason?: string;
|
|
10
|
+
href?: string;
|
|
11
|
+
external?: boolean;
|
|
12
|
+
icon?: RelatedRecordActionIcon;
|
|
13
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>;
|
|
14
|
+
className?: string;
|
|
15
|
+
testId?: string;
|
|
16
|
+
}
|
|
17
|
+
declare function RelatedRecordActionCard({ kind, label, subtitle, disabledReason, href, external, icon, onClick, className, testId, }: RelatedRecordActionCardProps): React.JSX.Element;
|
|
18
|
+
|
|
19
|
+
export { RelatedRecordActionCard, type RelatedRecordActionCardKind, type RelatedRecordActionCardProps, type RelatedRecordActionIcon };
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
"use client";
|
|
4
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { ExternalLink } from "lucide-react";
|
|
6
|
+
import { BRAND_ICONS } from "../lib/icons.js";
|
|
7
|
+
import { cn } from "../lib/utils.js";
|
|
8
|
+
function renderActionIcon(icon, kind) {
|
|
9
|
+
if (icon === "salesforce" || kind === "salesforce") {
|
|
10
|
+
return /* @__PURE__ */ jsx(
|
|
11
|
+
"img",
|
|
12
|
+
{
|
|
13
|
+
src: BRAND_ICONS.salesforce,
|
|
14
|
+
alt: "Salesforce",
|
|
15
|
+
className: "h-4 w-4 object-contain",
|
|
16
|
+
draggable: false
|
|
17
|
+
}
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
if (icon) {
|
|
21
|
+
return icon;
|
|
22
|
+
}
|
|
23
|
+
return /* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: kind.slice(0, 1).toUpperCase() });
|
|
24
|
+
}
|
|
25
|
+
function RelatedRecordActionCard({
|
|
26
|
+
kind,
|
|
27
|
+
label,
|
|
28
|
+
subtitle,
|
|
29
|
+
disabledReason,
|
|
30
|
+
href,
|
|
31
|
+
external,
|
|
32
|
+
icon,
|
|
33
|
+
onClick,
|
|
34
|
+
className,
|
|
35
|
+
testId
|
|
36
|
+
}) {
|
|
37
|
+
const isDisabled = Boolean(disabledReason) || !href && !onClick;
|
|
38
|
+
const content = /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
39
|
+
/* @__PURE__ */ jsx(
|
|
40
|
+
"span",
|
|
41
|
+
{
|
|
42
|
+
"data-slot": "related-record-action-card-icon",
|
|
43
|
+
className: cn(
|
|
44
|
+
"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border text-xs font-semibold transition-colors",
|
|
45
|
+
isDisabled ? "border-border/60 bg-muted/40 text-muted-foreground" : "border-border bg-muted/30 text-muted-foreground group-hover:bg-muted/60 group-active:text-primary"
|
|
46
|
+
),
|
|
47
|
+
children: renderActionIcon(icon, kind)
|
|
48
|
+
}
|
|
49
|
+
),
|
|
50
|
+
/* @__PURE__ */ jsxs("span", { className: "min-w-0 flex-1", children: [
|
|
51
|
+
/* @__PURE__ */ jsx(
|
|
52
|
+
"span",
|
|
53
|
+
{
|
|
54
|
+
"data-slot": "related-record-action-card-label",
|
|
55
|
+
className: cn(
|
|
56
|
+
"block truncate text-sm font-medium transition-colors",
|
|
57
|
+
isDisabled ? "text-muted-foreground" : "text-foreground group-active:text-primary"
|
|
58
|
+
),
|
|
59
|
+
children: label
|
|
60
|
+
}
|
|
61
|
+
),
|
|
62
|
+
subtitle && /* @__PURE__ */ jsx(
|
|
63
|
+
"span",
|
|
64
|
+
{
|
|
65
|
+
"data-slot": "related-record-action-card-subtitle",
|
|
66
|
+
className: "mt-0.5 block truncate text-xs text-muted-foreground",
|
|
67
|
+
children: subtitle
|
|
68
|
+
}
|
|
69
|
+
),
|
|
70
|
+
disabledReason && /* @__PURE__ */ jsx(
|
|
71
|
+
"span",
|
|
72
|
+
{
|
|
73
|
+
"data-slot": "related-record-action-card-disabled-reason",
|
|
74
|
+
className: "mt-1 block text-xs text-muted-foreground",
|
|
75
|
+
children: disabledReason
|
|
76
|
+
}
|
|
77
|
+
)
|
|
78
|
+
] }),
|
|
79
|
+
external && /* @__PURE__ */ jsx(
|
|
80
|
+
ExternalLink,
|
|
81
|
+
{
|
|
82
|
+
"aria-hidden": "true",
|
|
83
|
+
"data-slot": "related-record-action-card-external-icon",
|
|
84
|
+
className: cn(
|
|
85
|
+
"h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors",
|
|
86
|
+
isDisabled ? "" : "group-active:text-primary"
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
] });
|
|
91
|
+
if (isDisabled) {
|
|
92
|
+
return /* @__PURE__ */ jsx(
|
|
93
|
+
"div",
|
|
94
|
+
{
|
|
95
|
+
"aria-disabled": "true",
|
|
96
|
+
"data-kind": kind,
|
|
97
|
+
"data-slot": "related-record-action-card",
|
|
98
|
+
"data-testid": testId,
|
|
99
|
+
className: cn(
|
|
100
|
+
"group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors",
|
|
101
|
+
"cursor-not-allowed border-border/60 bg-muted/20 text-muted-foreground opacity-70",
|
|
102
|
+
className
|
|
103
|
+
),
|
|
104
|
+
children: content
|
|
105
|
+
}
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
if (href) {
|
|
109
|
+
return /* @__PURE__ */ jsx(
|
|
110
|
+
"a",
|
|
111
|
+
{
|
|
112
|
+
href,
|
|
113
|
+
target: external ? "_blank" : void 0,
|
|
114
|
+
rel: external ? "noopener noreferrer" : void 0,
|
|
115
|
+
"data-kind": kind,
|
|
116
|
+
"data-slot": "related-record-action-card",
|
|
117
|
+
"data-testid": testId,
|
|
118
|
+
className: cn(
|
|
119
|
+
"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
|
|
120
|
+
"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary",
|
|
121
|
+
className
|
|
122
|
+
),
|
|
123
|
+
children: content
|
|
124
|
+
}
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
return /* @__PURE__ */ jsx(
|
|
128
|
+
"button",
|
|
129
|
+
{
|
|
130
|
+
type: "button",
|
|
131
|
+
onClick,
|
|
132
|
+
"data-kind": kind,
|
|
133
|
+
"data-slot": "related-record-action-card",
|
|
134
|
+
"data-testid": testId,
|
|
135
|
+
className: cn(
|
|
136
|
+
"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
|
|
137
|
+
"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary",
|
|
138
|
+
className
|
|
139
|
+
),
|
|
140
|
+
children: content
|
|
141
|
+
}
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
export {
|
|
145
|
+
RelatedRecordActionCard
|
|
146
|
+
};
|
|
147
|
+
//# sourceMappingURL=related-record-action-card.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/components/related-record-action-card.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ExternalLink } from \"lucide-react\"\n\nimport { BRAND_ICONS } from \"../lib/icons\"\nimport { cn } from \"../lib/utils\"\n\nexport type RelatedRecordActionCardKind = \"case\" | \"account\" | \"opportunity\" | \"salesforce\" | \"generic\"\n\nexport type RelatedRecordActionIcon = \"salesforce\" | React.ReactNode\n\nexport interface RelatedRecordActionCardProps {\n kind: RelatedRecordActionCardKind\n label: string\n subtitle?: string\n disabledReason?: string\n href?: string\n external?: boolean\n icon?: RelatedRecordActionIcon\n onClick?: React.MouseEventHandler<HTMLButtonElement>\n className?: string\n testId?: string\n}\n\nfunction renderActionIcon(icon: RelatedRecordActionIcon | undefined, kind: RelatedRecordActionCardKind) {\n if (icon === \"salesforce\" || kind === \"salesforce\") {\n return (\n <img\n src={BRAND_ICONS.salesforce}\n alt=\"Salesforce\"\n className=\"h-4 w-4 object-contain\"\n draggable={false}\n />\n )\n }\n\n if (icon) {\n return icon\n }\n\n return <span aria-hidden=\"true\">{kind.slice(0, 1).toUpperCase()}</span>\n}\n\nexport function RelatedRecordActionCard({\n kind,\n label,\n subtitle,\n disabledReason,\n href,\n external,\n icon,\n onClick,\n className,\n testId,\n}: RelatedRecordActionCardProps) {\n const isDisabled = Boolean(disabledReason) || (!href && !onClick)\n\n const content = (\n <>\n <span\n data-slot=\"related-record-action-card-icon\"\n className={cn(\n \"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border text-xs font-semibold transition-colors\",\n isDisabled\n ? \"border-border/60 bg-muted/40 text-muted-foreground\"\n : \"border-border bg-muted/30 text-muted-foreground group-hover:bg-muted/60 group-active:text-primary\"\n )}\n >\n {renderActionIcon(icon, kind)}\n </span>\n <span className=\"min-w-0 flex-1\">\n <span\n data-slot=\"related-record-action-card-label\"\n className={cn(\n \"block truncate text-sm font-medium transition-colors\",\n isDisabled ? \"text-muted-foreground\" : \"text-foreground group-active:text-primary\"\n )}\n >\n {label}\n </span>\n {subtitle && (\n <span\n data-slot=\"related-record-action-card-subtitle\"\n className=\"mt-0.5 block truncate text-xs text-muted-foreground\"\n >\n {subtitle}\n </span>\n )}\n {disabledReason && (\n <span\n data-slot=\"related-record-action-card-disabled-reason\"\n className=\"mt-1 block text-xs text-muted-foreground\"\n >\n {disabledReason}\n </span>\n )}\n </span>\n {external && (\n <ExternalLink\n aria-hidden=\"true\"\n data-slot=\"related-record-action-card-external-icon\"\n className={cn(\n \"h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors\",\n isDisabled ? \"\" : \"group-active:text-primary\"\n )}\n />\n )}\n </>\n )\n\n if (isDisabled) {\n return (\n <div\n aria-disabled=\"true\"\n data-kind={kind}\n data-slot=\"related-record-action-card\"\n data-testid={testId}\n className={cn(\n \"group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors\",\n \"cursor-not-allowed border-border/60 bg-muted/20 text-muted-foreground opacity-70\",\n className\n )}\n >\n {content}\n </div>\n )\n }\n\n if (href) {\n return (\n <a\n href={href}\n target={external ? \"_blank\" : undefined}\n rel={external ? \"noopener noreferrer\" : undefined}\n data-kind={kind}\n data-slot=\"related-record-action-card\"\n data-testid={testId}\n className={cn(\n \"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors\",\n \"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary\",\n className\n )}\n >\n {content}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={onClick}\n data-kind={kind}\n data-slot=\"related-record-action-card\"\n data-testid={testId}\n className={cn(\n \"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors\",\n \"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary\",\n className\n )}\n >\n {content}\n </button>\n )\n}\n"],"mappings":";AA4BM,SA+BF,UA/BE,KA2CA,YA3CA;AAzBN,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;AAC5B,SAAS,UAAU;AAmBnB,SAAS,iBAAiB,MAA2C,MAAmC;AACtG,MAAI,SAAS,gBAAgB,SAAS,cAAc;AAClD,WACE;AAAA,MAAC;AAAA;AAAA,QACC,KAAK,YAAY;AAAA,QACjB,KAAI;AAAA,QACJ,WAAU;AAAA,QACV,WAAW;AAAA;AAAA,IACb;AAAA,EAEJ;AAEA,MAAI,MAAM;AACR,WAAO;AAAA,EACT;AAEA,SAAO,oBAAC,UAAK,eAAY,QAAQ,eAAK,MAAM,GAAG,CAAC,EAAE,YAAY,GAAE;AAClE;AAEO,SAAS,wBAAwB;AAAA,EACtC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAiC;AAC/B,QAAM,aAAa,QAAQ,cAAc,KAAM,CAAC,QAAQ,CAAC;AAEzD,QAAM,UACJ,iCACE;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA,aACI,uDACA;AAAA,QACN;AAAA,QAEC,2BAAiB,MAAM,IAAI;AAAA;AAAA,IAC9B;AAAA,IACA,qBAAC,UAAK,WAAU,kBACd;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,aAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA,YACA,aAAa,0BAA0B;AAAA,UACzC;AAAA,UAEC;AAAA;AAAA,MACH;AAAA,MACC,YACC;AAAA,QAAC;AAAA;AAAA,UACC,aAAU;AAAA,UACV,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,MAED,kBACC;AAAA,QAAC;AAAA;AAAA,UACC,aAAU;AAAA,UACV,WAAU;AAAA,UAET;AAAA;AAAA,MACH;AAAA,OAEJ;AAAA,IACC,YACC;AAAA,MAAC;AAAA;AAAA,QACC,eAAY;AAAA,QACZ,aAAU;AAAA,QACV,WAAW;AAAA,UACT;AAAA,UACA,aAAa,KAAK;AAAA,QACpB;AAAA;AAAA,IACF;AAAA,KAEJ;AAGF,MAAI,YAAY;AACd,WACE;AAAA,MAAC;AAAA;AAAA,QACC,iBAAc;AAAA,QACd,aAAW;AAAA,QACX,aAAU;AAAA,QACV,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,MAAI,MAAM;AACR,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,QAAQ,WAAW,WAAW;AAAA,QAC9B,KAAK,WAAW,wBAAwB;AAAA,QACxC,aAAW;AAAA,QACX,aAAU;AAAA,QACV,eAAa;AAAA,QACb,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA;AAAA,QACF;AAAA,QAEC;AAAA;AAAA,IACH;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,aAAW;AAAA,MACX,aAAU;AAAA,MACV,eAAa;AAAA,MACb,WAAW;AAAA,QACT;AAAA,QACA;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ export { QuickSegment, QuickSegmentProps } from './components/quick-segment.js';
|
|
|
59
59
|
export { QuickActionModal, QuickActionPriority, QuickActionTaskDraft, QuickActionTemplate } from './components/quick-action-modal.js';
|
|
60
60
|
export { ActiveVariant, QuickActionSidebarNav, SidebarNavItem, SidebarNavSection, SidebarUserProfile, UserMenuItem } from './components/quick-action-sidebar-nav.js';
|
|
61
61
|
export { RecommendedAction, RecommendedActionsSection } from './components/recommended-actions-section.js';
|
|
62
|
+
export { RelatedRecordActionCard, RelatedRecordActionCardKind, RelatedRecordActionCardProps, RelatedRecordActionIcon } from './components/related-record-action-card.js';
|
|
62
63
|
export { ReportCard, ReportCardProps } from './components/report-card.js';
|
|
63
64
|
export { RichTextAction, RichTextToolbar, RichTextToolbarProps } from './components/rich-text-toolbar.js';
|
|
64
65
|
export { ScoreAnalysisModal, ScoreAnalysisModalProps, ScoreAnalysisPanel, getScoreLabel } from './components/score-analysis-modal.js';
|
package/dist/index.js
CHANGED
|
@@ -61,6 +61,7 @@ import {
|
|
|
61
61
|
} from "./components/quick-action-modal.js";
|
|
62
62
|
export * from "./components/quick-action-sidebar-nav.js";
|
|
63
63
|
export * from "./components/recommended-actions-section.js";
|
|
64
|
+
export * from "./components/related-record-action-card.js";
|
|
64
65
|
export * from "./components/report-card.js";
|
|
65
66
|
export * from "./components/rich-text-toolbar.js";
|
|
66
67
|
export * from "./components/score-analysis-modal.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 * 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":[]}
|
|
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/related-record-action-card\"\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,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
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import "@testing-library/jest-dom/vitest"
|
|
2
|
+
|
|
3
|
+
import React from "react"
|
|
4
|
+
import { fireEvent, render, screen } from "@testing-library/react"
|
|
5
|
+
import { describe, expect, it, vi } from "vitest"
|
|
6
|
+
|
|
7
|
+
import { BRAND_ICONS } from "../../lib/icons"
|
|
8
|
+
import { RelatedRecordActionCard } from "../related-record-action-card"
|
|
9
|
+
|
|
10
|
+
describe("RelatedRecordActionCard", () => {
|
|
11
|
+
it("renders an enabled href as a link with pointer affordance", () => {
|
|
12
|
+
render(
|
|
13
|
+
<RelatedRecordActionCard
|
|
14
|
+
kind="account"
|
|
15
|
+
label="Open account"
|
|
16
|
+
subtitle="Acme Corp"
|
|
17
|
+
href="/accounts/acme"
|
|
18
|
+
testId="record-card"
|
|
19
|
+
/>
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const card = screen.getByTestId("record-card")
|
|
23
|
+
|
|
24
|
+
expect(card.tagName).toBe("A")
|
|
25
|
+
expect(card).toHaveAttribute("href", "/accounts/acme")
|
|
26
|
+
expect(card.className).toContain("cursor-pointer")
|
|
27
|
+
expect(card.className).toContain("hover:bg-muted/50")
|
|
28
|
+
expect(card.className).toContain("hover:border-border/80")
|
|
29
|
+
expect(card.className).toContain("focus-visible:ring-2")
|
|
30
|
+
expect(card.className).toContain("active:text-primary")
|
|
31
|
+
expect(screen.getByText("Acme Corp")).toBeInTheDocument()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it("renders an enabled onClick action as a button and invokes the callback", () => {
|
|
35
|
+
const onClick = vi.fn()
|
|
36
|
+
|
|
37
|
+
render(
|
|
38
|
+
<RelatedRecordActionCard
|
|
39
|
+
kind="case"
|
|
40
|
+
label="Open case"
|
|
41
|
+
onClick={onClick}
|
|
42
|
+
testId="record-card"
|
|
43
|
+
/>
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
const card = screen.getByRole("button", { name: /open case/i })
|
|
47
|
+
|
|
48
|
+
expect(card.tagName).toBe("BUTTON")
|
|
49
|
+
expect(card).toHaveAttribute("type", "button")
|
|
50
|
+
expect(card.className).toContain("cursor-pointer")
|
|
51
|
+
|
|
52
|
+
fireEvent.click(card)
|
|
53
|
+
|
|
54
|
+
expect(onClick).toHaveBeenCalledTimes(1)
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
it("renders a disabled card when disabledReason is present", () => {
|
|
58
|
+
render(
|
|
59
|
+
<RelatedRecordActionCard
|
|
60
|
+
kind="opportunity"
|
|
61
|
+
label="Open opportunity"
|
|
62
|
+
disabledReason="Connect Salesforce to view this opportunity."
|
|
63
|
+
href="/opportunities/1"
|
|
64
|
+
testId="record-card"
|
|
65
|
+
/>
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
const card = screen.getByTestId("record-card")
|
|
69
|
+
|
|
70
|
+
expect(card.tagName).toBe("DIV")
|
|
71
|
+
expect(card).toHaveAttribute("aria-disabled", "true")
|
|
72
|
+
expect(card.className).toContain("cursor-not-allowed")
|
|
73
|
+
expect(card.className).toContain("text-muted-foreground")
|
|
74
|
+
expect(card.className).not.toContain("cursor-pointer")
|
|
75
|
+
expect(card.className).not.toContain("hover:bg-muted/50")
|
|
76
|
+
expect(screen.getByText("Connect Salesforce to view this opportunity.")).toBeInTheDocument()
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
it("renders a disabled card when no action is available", () => {
|
|
80
|
+
render(<RelatedRecordActionCard kind="generic" label="Unavailable record" testId="record-card" />)
|
|
81
|
+
|
|
82
|
+
const card = screen.getByTestId("record-card")
|
|
83
|
+
|
|
84
|
+
expect(card.tagName).toBe("DIV")
|
|
85
|
+
expect(card).toHaveAttribute("aria-disabled", "true")
|
|
86
|
+
expect(card.className).toContain("cursor-not-allowed")
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it("sets external link attributes and shows the external icon", () => {
|
|
90
|
+
const { container } = render(
|
|
91
|
+
<RelatedRecordActionCard
|
|
92
|
+
kind="salesforce"
|
|
93
|
+
label="Open in Salesforce"
|
|
94
|
+
href="https://example.salesforce.com/001"
|
|
95
|
+
external
|
|
96
|
+
testId="record-card"
|
|
97
|
+
/>
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const card = screen.getByTestId("record-card")
|
|
101
|
+
|
|
102
|
+
expect(card).toHaveAttribute("target", "_blank")
|
|
103
|
+
expect(card).toHaveAttribute("rel", "noopener noreferrer")
|
|
104
|
+
expect(container.querySelector('[data-slot="related-record-action-card-external-icon"]')).not.toBeNull()
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it("renders the Salesforce brand icon when icon is salesforce", () => {
|
|
108
|
+
const { container } = render(
|
|
109
|
+
<RelatedRecordActionCard
|
|
110
|
+
kind="generic"
|
|
111
|
+
label="Salesforce record"
|
|
112
|
+
href="https://example.salesforce.com/001"
|
|
113
|
+
icon="salesforce"
|
|
114
|
+
/>
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
const icon = container.querySelector('[data-slot="related-record-action-card-icon"] img')
|
|
118
|
+
|
|
119
|
+
expect(icon).toHaveAttribute("src", BRAND_ICONS.salesforce)
|
|
120
|
+
expect(icon).toHaveAttribute("alt", "Salesforce")
|
|
121
|
+
})
|
|
122
|
+
})
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import * as React from "react"
|
|
4
|
+
import { ExternalLink } from "lucide-react"
|
|
5
|
+
|
|
6
|
+
import { BRAND_ICONS } from "../lib/icons"
|
|
7
|
+
import { cn } from "../lib/utils"
|
|
8
|
+
|
|
9
|
+
export type RelatedRecordActionCardKind = "case" | "account" | "opportunity" | "salesforce" | "generic"
|
|
10
|
+
|
|
11
|
+
export type RelatedRecordActionIcon = "salesforce" | React.ReactNode
|
|
12
|
+
|
|
13
|
+
export interface RelatedRecordActionCardProps {
|
|
14
|
+
kind: RelatedRecordActionCardKind
|
|
15
|
+
label: string
|
|
16
|
+
subtitle?: string
|
|
17
|
+
disabledReason?: string
|
|
18
|
+
href?: string
|
|
19
|
+
external?: boolean
|
|
20
|
+
icon?: RelatedRecordActionIcon
|
|
21
|
+
onClick?: React.MouseEventHandler<HTMLButtonElement>
|
|
22
|
+
className?: string
|
|
23
|
+
testId?: string
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderActionIcon(icon: RelatedRecordActionIcon | undefined, kind: RelatedRecordActionCardKind) {
|
|
27
|
+
if (icon === "salesforce" || kind === "salesforce") {
|
|
28
|
+
return (
|
|
29
|
+
<img
|
|
30
|
+
src={BRAND_ICONS.salesforce}
|
|
31
|
+
alt="Salesforce"
|
|
32
|
+
className="h-4 w-4 object-contain"
|
|
33
|
+
draggable={false}
|
|
34
|
+
/>
|
|
35
|
+
)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (icon) {
|
|
39
|
+
return icon
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return <span aria-hidden="true">{kind.slice(0, 1).toUpperCase()}</span>
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function RelatedRecordActionCard({
|
|
46
|
+
kind,
|
|
47
|
+
label,
|
|
48
|
+
subtitle,
|
|
49
|
+
disabledReason,
|
|
50
|
+
href,
|
|
51
|
+
external,
|
|
52
|
+
icon,
|
|
53
|
+
onClick,
|
|
54
|
+
className,
|
|
55
|
+
testId,
|
|
56
|
+
}: RelatedRecordActionCardProps) {
|
|
57
|
+
const isDisabled = Boolean(disabledReason) || (!href && !onClick)
|
|
58
|
+
|
|
59
|
+
const content = (
|
|
60
|
+
<>
|
|
61
|
+
<span
|
|
62
|
+
data-slot="related-record-action-card-icon"
|
|
63
|
+
className={cn(
|
|
64
|
+
"flex h-8 w-8 shrink-0 items-center justify-center rounded-md border text-xs font-semibold transition-colors",
|
|
65
|
+
isDisabled
|
|
66
|
+
? "border-border/60 bg-muted/40 text-muted-foreground"
|
|
67
|
+
: "border-border bg-muted/30 text-muted-foreground group-hover:bg-muted/60 group-active:text-primary"
|
|
68
|
+
)}
|
|
69
|
+
>
|
|
70
|
+
{renderActionIcon(icon, kind)}
|
|
71
|
+
</span>
|
|
72
|
+
<span className="min-w-0 flex-1">
|
|
73
|
+
<span
|
|
74
|
+
data-slot="related-record-action-card-label"
|
|
75
|
+
className={cn(
|
|
76
|
+
"block truncate text-sm font-medium transition-colors",
|
|
77
|
+
isDisabled ? "text-muted-foreground" : "text-foreground group-active:text-primary"
|
|
78
|
+
)}
|
|
79
|
+
>
|
|
80
|
+
{label}
|
|
81
|
+
</span>
|
|
82
|
+
{subtitle && (
|
|
83
|
+
<span
|
|
84
|
+
data-slot="related-record-action-card-subtitle"
|
|
85
|
+
className="mt-0.5 block truncate text-xs text-muted-foreground"
|
|
86
|
+
>
|
|
87
|
+
{subtitle}
|
|
88
|
+
</span>
|
|
89
|
+
)}
|
|
90
|
+
{disabledReason && (
|
|
91
|
+
<span
|
|
92
|
+
data-slot="related-record-action-card-disabled-reason"
|
|
93
|
+
className="mt-1 block text-xs text-muted-foreground"
|
|
94
|
+
>
|
|
95
|
+
{disabledReason}
|
|
96
|
+
</span>
|
|
97
|
+
)}
|
|
98
|
+
</span>
|
|
99
|
+
{external && (
|
|
100
|
+
<ExternalLink
|
|
101
|
+
aria-hidden="true"
|
|
102
|
+
data-slot="related-record-action-card-external-icon"
|
|
103
|
+
className={cn(
|
|
104
|
+
"h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors",
|
|
105
|
+
isDisabled ? "" : "group-active:text-primary"
|
|
106
|
+
)}
|
|
107
|
+
/>
|
|
108
|
+
)}
|
|
109
|
+
</>
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if (isDisabled) {
|
|
113
|
+
return (
|
|
114
|
+
<div
|
|
115
|
+
aria-disabled="true"
|
|
116
|
+
data-kind={kind}
|
|
117
|
+
data-slot="related-record-action-card"
|
|
118
|
+
data-testid={testId}
|
|
119
|
+
className={cn(
|
|
120
|
+
"group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors",
|
|
121
|
+
"cursor-not-allowed border-border/60 bg-muted/20 text-muted-foreground opacity-70",
|
|
122
|
+
className
|
|
123
|
+
)}
|
|
124
|
+
>
|
|
125
|
+
{content}
|
|
126
|
+
</div>
|
|
127
|
+
)
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (href) {
|
|
131
|
+
return (
|
|
132
|
+
<a
|
|
133
|
+
href={href}
|
|
134
|
+
target={external ? "_blank" : undefined}
|
|
135
|
+
rel={external ? "noopener noreferrer" : undefined}
|
|
136
|
+
data-kind={kind}
|
|
137
|
+
data-slot="related-record-action-card"
|
|
138
|
+
data-testid={testId}
|
|
139
|
+
className={cn(
|
|
140
|
+
"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
|
|
141
|
+
"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary",
|
|
142
|
+
className
|
|
143
|
+
)}
|
|
144
|
+
>
|
|
145
|
+
{content}
|
|
146
|
+
</a>
|
|
147
|
+
)
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
onClick={onClick}
|
|
154
|
+
data-kind={kind}
|
|
155
|
+
data-slot="related-record-action-card"
|
|
156
|
+
data-testid={testId}
|
|
157
|
+
className={cn(
|
|
158
|
+
"group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
|
|
159
|
+
"cursor-pointer hover:bg-muted/50 hover:border-border/80 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 active:text-primary",
|
|
160
|
+
className
|
|
161
|
+
)}
|
|
162
|
+
>
|
|
163
|
+
{content}
|
|
164
|
+
</button>
|
|
165
|
+
)
|
|
166
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -76,6 +76,7 @@ export {
|
|
|
76
76
|
} from "./components/quick-action-modal"
|
|
77
77
|
export * from "./components/quick-action-sidebar-nav"
|
|
78
78
|
export * from "./components/recommended-actions-section"
|
|
79
|
+
export * from "./components/related-record-action-card"
|
|
79
80
|
export * from "./components/report-card"
|
|
80
81
|
export * from "./components/rich-text-toolbar"
|
|
81
82
|
export * from "./components/score-analysis-modal"
|