@handled-ai/design-system 0.18.38 → 0.18.40

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.
@@ -0,0 +1,150 @@
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__ */ jsxs(Fragment, { children: [
80
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "opens in a new tab" }),
81
+ /* @__PURE__ */ jsx(
82
+ ExternalLink,
83
+ {
84
+ "aria-hidden": "true",
85
+ "data-slot": "related-record-action-card-external-icon",
86
+ className: cn(
87
+ "h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors",
88
+ isDisabled ? "" : "group-active:text-primary"
89
+ )
90
+ }
91
+ )
92
+ ] })
93
+ ] });
94
+ if (isDisabled) {
95
+ return /* @__PURE__ */ jsx(
96
+ "div",
97
+ {
98
+ "aria-disabled": "true",
99
+ "data-kind": kind,
100
+ "data-slot": "related-record-action-card",
101
+ "data-testid": testId,
102
+ className: cn(
103
+ "group flex w-full items-center gap-3 rounded-lg border px-3 py-2 text-left transition-colors",
104
+ "cursor-not-allowed border-border/60 bg-muted/20 text-muted-foreground opacity-70",
105
+ className
106
+ ),
107
+ children: content
108
+ }
109
+ );
110
+ }
111
+ if (href) {
112
+ return /* @__PURE__ */ jsx(
113
+ "a",
114
+ {
115
+ href,
116
+ target: external ? "_blank" : void 0,
117
+ rel: external ? "noopener noreferrer" : void 0,
118
+ "data-kind": kind,
119
+ "data-slot": "related-record-action-card",
120
+ "data-testid": testId,
121
+ className: cn(
122
+ "group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
123
+ "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",
124
+ className
125
+ ),
126
+ children: content
127
+ }
128
+ );
129
+ }
130
+ return /* @__PURE__ */ jsx(
131
+ "button",
132
+ {
133
+ type: "button",
134
+ onClick,
135
+ "data-kind": kind,
136
+ "data-slot": "related-record-action-card",
137
+ "data-testid": testId,
138
+ className: cn(
139
+ "group flex w-full items-center gap-3 rounded-lg border border-border bg-background px-3 py-2 text-left transition-colors",
140
+ "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",
141
+ className
142
+ ),
143
+ children: content
144
+ }
145
+ );
146
+ }
147
+ export {
148
+ RelatedRecordActionCard
149
+ };
150
+ //# 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 <>\n <span className=\"sr-only\">opens in a new tab</span>\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\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,SAuEE,UAvEF,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,iCACE;AAAA,0BAAC,UAAK,WAAU,WAAU,gCAAkB;AAAA,MAC5C;AAAA,QAAC;AAAA;AAAA,UACC,eAAY;AAAA,UACZ,aAAU;AAAA,UACV,WAAW;AAAA,YACT;AAAA,YACA,aAAa,KAAK;AAAA,UACpB;AAAA;AAAA,MACF;AAAA,OACF;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":[]}
@@ -102,7 +102,7 @@ function Trigger({ className }) {
102
102
  className
103
103
  ),
104
104
  children: [
105
- /* @__PURE__ */ jsx(Check, { className: "w-3 h-3 text-emerald-500" }),
105
+ /* @__PURE__ */ jsx(Check, { className: "w-3 h-3 text-foreground" }),
106
106
  /* @__PURE__ */ jsx("span", { className: "text-[11px] text-muted-foreground", children: label })
107
107
  ]
108
108
  }
@@ -116,9 +116,9 @@ function Trigger({ className }) {
116
116
  onClick: () => handleThumbClick("up"),
117
117
  className: cn(
118
118
  "p-1.5 rounded transition-colors",
119
- thumbState === "up" ? "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400" : "hover:bg-muted text-muted-foreground hover:text-foreground"
119
+ thumbState === "up" ? "bg-muted text-foreground" : "hover:bg-muted text-muted-foreground hover:text-foreground"
120
120
  ),
121
- children: /* @__PURE__ */ jsx(ThumbsUp, { className: "w-3.5 h-3.5", fill: thumbState === "up" ? "currentColor" : "none" })
121
+ children: /* @__PURE__ */ jsx(ThumbsUp, { className: "w-3.5 h-3.5" })
122
122
  }
123
123
  ),
124
124
  /* @__PURE__ */ jsx(
@@ -128,9 +128,9 @@ function Trigger({ className }) {
128
128
  onClick: () => handleThumbClick("down"),
129
129
  className: cn(
130
130
  "p-1.5 rounded transition-colors",
131
- thumbState === "down" ? "bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400" : "hover:bg-muted text-muted-foreground hover:text-foreground"
131
+ thumbState === "down" ? "bg-muted text-foreground" : "hover:bg-muted text-muted-foreground hover:text-foreground"
132
132
  ),
133
- children: /* @__PURE__ */ jsx(ThumbsDown, { className: "w-3.5 h-3.5", fill: thumbState === "down" ? "currentColor" : "none" })
133
+ children: /* @__PURE__ */ jsx(ThumbsDown, { className: "w-3.5 h-3.5" })
134
134
  }
135
135
  )
136
136
  ] });
@@ -158,7 +158,7 @@ function Panel({ className }) {
158
158
  onClick: () => togglePill(pill),
159
159
  className: cn(
160
160
  "px-2.5 py-1 rounded-full text-[11px] font-medium border transition-colors",
161
- selectedPills.includes(pill) ? thumbState === "up" ? "bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800" : "bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800" : "bg-background text-muted-foreground border-border hover:bg-muted/50 hover:text-foreground"
161
+ selectedPills.includes(pill) ? thumbState === "up" ? "bg-muted text-foreground border-border" : "bg-red-50 text-red-700 border-red-200 dark:bg-red-950/30 dark:text-red-300 dark:border-red-800" : "bg-background text-muted-foreground border-border hover:bg-muted/50 hover:text-foreground"
162
162
  ),
163
163
  children: pill
164
164
  },
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/score-feedback.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ThumbsUp, ThumbsDown, Check } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\nconst positivePills = [\n \"Right timing\",\n \"Accurate data\",\n \"Good prospect fit\",\n \"Actionable\",\n]\n\nconst negativePills = [\n \"Bad timing\",\n \"Inaccurate data\",\n \"Wrong prospect\",\n \"Already handled\",\n \"Not actionable\",\n \"Other\",\n]\n\ninterface SubmittedScoreFeedback {\n type: \"up\" | \"down\"\n pills: string[]\n detail: string\n}\n\ninterface ScoreFeedbackState {\n thumbState: \"up\" | \"down\" | null\n selectedPills: string[]\n detailText: string\n notedType: \"up\" | \"down\" | null\n submittedFeedback: SubmittedScoreFeedback | null\n otherSelected: boolean\n hasRequiredInput: boolean\n handleThumbClick: (type: \"up\" | \"down\") => void\n togglePill: (pill: string) => void\n setDetailText: (text: string) => void\n handleSubmit: () => void\n editSubmitted: () => void\n}\n\nconst ScoreFeedbackCtx = React.createContext<ScoreFeedbackState | null>(null)\n\nfunction useScoreFeedback() {\n const ctx = React.useContext(ScoreFeedbackCtx)\n if (!ctx) throw new Error(\"Must be used within ScoreFeedback.Root\")\n return ctx\n}\n\ninterface RootProps {\n children: React.ReactNode\n onSubmitFeedback?: (type: \"up\" | \"down\", pills: string[], detail: string) => void\n initialFeedback?: { type: \"up\" | \"down\"; pills: string[]; detail: string } | null\n}\n\nfunction Root({ children, onSubmitFeedback, initialFeedback }: RootProps) {\n const [thumbState, setThumbState] = React.useState<\"up\" | \"down\" | null>(null)\n const [selectedPills, setSelectedPills] = React.useState<string[]>([])\n const [detailText, setDetailTextState] = React.useState(\"\")\n const [notedType, setNotedType] = React.useState<\"up\" | \"down\" | null>(null)\n const [submittedFeedback, setSubmittedFeedback] = React.useState<SubmittedScoreFeedback | null>(\n initialFeedback ?? null\n )\n\n // Sync submitted feedback when initialFeedback prop changes (e.g. async\n // detail load). Skip when the user has an in-progress edit (thumbState set).\n React.useEffect(() => {\n if (thumbState !== null) return\n setSubmittedFeedback(initialFeedback ?? null)\n }, [initialFeedback]) // eslint-disable-line react-hooks/exhaustive-deps -- intentionally omits thumbState to read it as a guard, not a trigger\n\n const otherSelected = selectedPills.includes(\"Other\")\n\n const hasRequiredInput =\n thumbState === \"down\"\n ? selectedPills.length > 0 && (!otherSelected || detailText.trim().length > 0)\n : selectedPills.length > 0 || detailText.trim().length > 0\n\n const togglePill = React.useCallback((pill: string) => {\n setSelectedPills((prev) =>\n prev.includes(pill) ? prev.filter((p) => p !== pill) : [...prev, pill]\n )\n }, [])\n\n const handleThumbClick = React.useCallback((type: \"up\" | \"down\") => {\n setThumbState((prev) => (prev === type ? null : type))\n setSelectedPills([])\n setDetailTextState(\"\")\n }, [])\n\n const handleSubmit = React.useCallback(() => {\n if (!thumbState) return\n onSubmitFeedback?.(thumbState, selectedPills, detailText)\n setSubmittedFeedback({ type: thumbState, pills: [...selectedPills], detail: detailText.trim() })\n setNotedType(thumbState)\n setThumbState(null)\n setSelectedPills([])\n setDetailTextState(\"\")\n setTimeout(() => setNotedType(null), 3000)\n }, [thumbState, selectedPills, detailText, onSubmitFeedback])\n\n const editSubmitted = React.useCallback(() => {\n if (!submittedFeedback) return\n setThumbState(submittedFeedback.type)\n setSelectedPills([...submittedFeedback.pills])\n setDetailTextState(submittedFeedback.detail)\n setNotedType(null)\n }, [submittedFeedback])\n\n return (\n <ScoreFeedbackCtx.Provider\n value={{\n thumbState,\n selectedPills,\n detailText,\n notedType,\n submittedFeedback,\n otherSelected,\n hasRequiredInput,\n handleThumbClick,\n togglePill,\n setDetailText: setDetailTextState,\n handleSubmit,\n editSubmitted,\n }}\n >\n {children}\n </ScoreFeedbackCtx.Provider>\n )\n}\n\nfunction Trigger({ className }: { className?: string }) {\n const { thumbState, notedType, submittedFeedback, handleThumbClick, editSubmitted } = useScoreFeedback()\n\n if (notedType || (submittedFeedback && !thumbState)) {\n const label = notedType\n ? notedType === \"up\" ? \"Noted\" : \"Recorded\"\n : submittedFeedback?.type === \"up\" ? \"Noted\" : \"Recorded\"\n\n return (\n <button\n type=\"button\"\n onClick={submittedFeedback ? editSubmitted : undefined}\n className={cn(\n \"flex items-center gap-1 shrink-0 rounded px-1.5 py-1 transition-colors\",\n submittedFeedback ? \"cursor-pointer hover:bg-muted/50\" : \"cursor-default\",\n className,\n )}\n >\n <Check className=\"w-3 h-3 text-emerald-500\" />\n <span className=\"text-[11px] text-muted-foreground\">{label}</span>\n </button>\n )\n }\n\n return (\n <div className={cn(\"flex gap-0.5 shrink-0\", className)}>\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"up\")}\n className={cn(\n \"p-1.5 rounded transition-colors\",\n thumbState === \"up\"\n ? \"bg-emerald-100 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400\"\n : \"hover:bg-muted text-muted-foreground hover:text-foreground\"\n )}\n >\n <ThumbsUp className=\"w-3.5 h-3.5\" fill={thumbState === \"up\" ? \"currentColor\" : \"none\"} />\n </button>\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"down\")}\n className={cn(\n \"p-1.5 rounded transition-colors\",\n thumbState === \"down\"\n ? \"bg-red-100 text-red-600 dark:bg-red-900/30 dark:text-red-400\"\n : \"hover:bg-muted text-muted-foreground hover:text-foreground\"\n )}\n >\n <ThumbsDown className=\"w-3.5 h-3.5\" fill={thumbState === \"down\" ? \"currentColor\" : \"none\"} />\n </button>\n </div>\n )\n}\n\nfunction Panel({ className }: { className?: string }) {\n const {\n thumbState,\n selectedPills,\n detailText,\n otherSelected,\n hasRequiredInput,\n togglePill,\n setDetailText,\n handleSubmit,\n } = useScoreFeedback()\n\n if (!thumbState) return null\n\n return (\n <div className={cn(\"overflow-hidden\", className)}>\n <div className=\"mt-4 pt-4 pb-1 space-y-3 border-t border-border/60\">\n <span className=\"text-[11px] font-bold text-muted-foreground/70 uppercase tracking-wider\">\n How&apos;s this score?\n </span>\n <div>\n <span className=\"text-xs text-muted-foreground mb-2 block font-medium\">\n {thumbState === \"up\" ? \"What was useful?\" : \"What\\u2019s the issue?\"}\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {(thumbState === \"up\" ? positivePills : negativePills).map((pill) => (\n <button\n key={pill}\n type=\"button\"\n onClick={() => togglePill(pill)}\n className={cn(\n \"px-2.5 py-1 rounded-full text-[11px] font-medium border transition-colors\",\n selectedPills.includes(pill)\n ? thumbState === \"up\"\n ? \"bg-emerald-100 text-emerald-700 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-300 dark:border-emerald-800\"\n : \"bg-red-100 text-red-700 border-red-200 dark:bg-red-900/30 dark:text-red-300 dark:border-red-800\"\n : \"bg-background text-muted-foreground border-border hover:bg-muted/50 hover:text-foreground\"\n )}\n >\n {pill}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && hasRequiredInput) handleSubmit()\n }}\n placeholder={\n thumbState === \"up\"\n ? \"Tell us more (optional)\"\n : \"e.g., The risk factors are outdated\"\n }\n className=\"w-full text-xs bg-background border border-border rounded-md px-2.5 py-2 text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n {otherSelected && detailText.trim().length === 0 && (\n <span className=\"text-[10px] text-red-500\">\n Please describe when &ldquo;Other&rdquo; is selected\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!hasRequiredInput}\n className={cn(\n \"flex-1 py-1.5 rounded-md text-xs font-semibold transition-colors\",\n hasRequiredInput\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-muted text-muted-foreground cursor-not-allowed\"\n )}\n >\n Submit\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport const ScoreFeedback = { Root, Trigger, Panel }\nexport { useScoreFeedback }\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components/score-feedback.tsx"],"sourcesContent":["\"use client\"\n\nimport * as React from \"react\"\nimport { ThumbsUp, ThumbsDown, Check } from \"lucide-react\"\nimport { cn } from \"../lib/utils\"\n\nconst positivePills = [\n \"Right timing\",\n \"Accurate data\",\n \"Good prospect fit\",\n \"Actionable\",\n]\n\nconst negativePills = [\n \"Bad timing\",\n \"Inaccurate data\",\n \"Wrong prospect\",\n \"Already handled\",\n \"Not actionable\",\n \"Other\",\n]\n\ninterface SubmittedScoreFeedback {\n type: \"up\" | \"down\"\n pills: string[]\n detail: string\n}\n\ninterface ScoreFeedbackState {\n thumbState: \"up\" | \"down\" | null\n selectedPills: string[]\n detailText: string\n notedType: \"up\" | \"down\" | null\n submittedFeedback: SubmittedScoreFeedback | null\n otherSelected: boolean\n hasRequiredInput: boolean\n handleThumbClick: (type: \"up\" | \"down\") => void\n togglePill: (pill: string) => void\n setDetailText: (text: string) => void\n handleSubmit: () => void\n editSubmitted: () => void\n}\n\nconst ScoreFeedbackCtx = React.createContext<ScoreFeedbackState | null>(null)\n\nfunction useScoreFeedback() {\n const ctx = React.useContext(ScoreFeedbackCtx)\n if (!ctx) throw new Error(\"Must be used within ScoreFeedback.Root\")\n return ctx\n}\n\ninterface RootProps {\n children: React.ReactNode\n onSubmitFeedback?: (type: \"up\" | \"down\", pills: string[], detail: string) => void\n initialFeedback?: { type: \"up\" | \"down\"; pills: string[]; detail: string } | null\n}\n\nfunction Root({ children, onSubmitFeedback, initialFeedback }: RootProps) {\n const [thumbState, setThumbState] = React.useState<\"up\" | \"down\" | null>(null)\n const [selectedPills, setSelectedPills] = React.useState<string[]>([])\n const [detailText, setDetailTextState] = React.useState(\"\")\n const [notedType, setNotedType] = React.useState<\"up\" | \"down\" | null>(null)\n const [submittedFeedback, setSubmittedFeedback] = React.useState<SubmittedScoreFeedback | null>(\n initialFeedback ?? null\n )\n\n // Sync submitted feedback when initialFeedback prop changes (e.g. async\n // detail load). Skip when the user has an in-progress edit (thumbState set).\n React.useEffect(() => {\n if (thumbState !== null) return\n setSubmittedFeedback(initialFeedback ?? null)\n }, [initialFeedback]) // eslint-disable-line react-hooks/exhaustive-deps -- intentionally omits thumbState to read it as a guard, not a trigger\n\n const otherSelected = selectedPills.includes(\"Other\")\n\n const hasRequiredInput =\n thumbState === \"down\"\n ? selectedPills.length > 0 && (!otherSelected || detailText.trim().length > 0)\n : selectedPills.length > 0 || detailText.trim().length > 0\n\n const togglePill = React.useCallback((pill: string) => {\n setSelectedPills((prev) =>\n prev.includes(pill) ? prev.filter((p) => p !== pill) : [...prev, pill]\n )\n }, [])\n\n const handleThumbClick = React.useCallback((type: \"up\" | \"down\") => {\n setThumbState((prev) => (prev === type ? null : type))\n setSelectedPills([])\n setDetailTextState(\"\")\n }, [])\n\n const handleSubmit = React.useCallback(() => {\n if (!thumbState) return\n onSubmitFeedback?.(thumbState, selectedPills, detailText)\n setSubmittedFeedback({ type: thumbState, pills: [...selectedPills], detail: detailText.trim() })\n setNotedType(thumbState)\n setThumbState(null)\n setSelectedPills([])\n setDetailTextState(\"\")\n setTimeout(() => setNotedType(null), 3000)\n }, [thumbState, selectedPills, detailText, onSubmitFeedback])\n\n const editSubmitted = React.useCallback(() => {\n if (!submittedFeedback) return\n setThumbState(submittedFeedback.type)\n setSelectedPills([...submittedFeedback.pills])\n setDetailTextState(submittedFeedback.detail)\n setNotedType(null)\n }, [submittedFeedback])\n\n return (\n <ScoreFeedbackCtx.Provider\n value={{\n thumbState,\n selectedPills,\n detailText,\n notedType,\n submittedFeedback,\n otherSelected,\n hasRequiredInput,\n handleThumbClick,\n togglePill,\n setDetailText: setDetailTextState,\n handleSubmit,\n editSubmitted,\n }}\n >\n {children}\n </ScoreFeedbackCtx.Provider>\n )\n}\n\nfunction Trigger({ className }: { className?: string }) {\n const { thumbState, notedType, submittedFeedback, handleThumbClick, editSubmitted } = useScoreFeedback()\n\n if (notedType || (submittedFeedback && !thumbState)) {\n const label = notedType\n ? notedType === \"up\" ? \"Noted\" : \"Recorded\"\n : submittedFeedback?.type === \"up\" ? \"Noted\" : \"Recorded\"\n\n return (\n <button\n type=\"button\"\n onClick={submittedFeedback ? editSubmitted : undefined}\n className={cn(\n \"flex items-center gap-1 shrink-0 rounded px-1.5 py-1 transition-colors\",\n submittedFeedback ? \"cursor-pointer hover:bg-muted/50\" : \"cursor-default\",\n className,\n )}\n >\n <Check className=\"w-3 h-3 text-foreground\" />\n <span className=\"text-[11px] text-muted-foreground\">{label}</span>\n </button>\n )\n }\n\n return (\n <div className={cn(\"flex gap-0.5 shrink-0\", className)}>\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"up\")}\n className={cn(\n \"p-1.5 rounded transition-colors\",\n thumbState === \"up\"\n ? \"bg-muted text-foreground\"\n : \"hover:bg-muted text-muted-foreground hover:text-foreground\"\n )}\n >\n <ThumbsUp className=\"w-3.5 h-3.5\" />\n </button>\n <button\n type=\"button\"\n onClick={() => handleThumbClick(\"down\")}\n className={cn(\n \"p-1.5 rounded transition-colors\",\n thumbState === \"down\"\n ? \"bg-muted text-foreground\"\n : \"hover:bg-muted text-muted-foreground hover:text-foreground\"\n )}\n >\n <ThumbsDown className=\"w-3.5 h-3.5\" />\n </button>\n </div>\n )\n}\n\nfunction Panel({ className }: { className?: string }) {\n const {\n thumbState,\n selectedPills,\n detailText,\n otherSelected,\n hasRequiredInput,\n togglePill,\n setDetailText,\n handleSubmit,\n } = useScoreFeedback()\n\n if (!thumbState) return null\n\n return (\n <div className={cn(\"overflow-hidden\", className)}>\n <div className=\"mt-4 pt-4 pb-1 space-y-3 border-t border-border/60\">\n <span className=\"text-[11px] font-bold text-muted-foreground/70 uppercase tracking-wider\">\n How&apos;s this score?\n </span>\n <div>\n <span className=\"text-xs text-muted-foreground mb-2 block font-medium\">\n {thumbState === \"up\" ? \"What was useful?\" : \"What\\u2019s the issue?\"}\n </span>\n <div className=\"flex flex-wrap gap-1.5\">\n {(thumbState === \"up\" ? positivePills : negativePills).map((pill) => (\n <button\n key={pill}\n type=\"button\"\n onClick={() => togglePill(pill)}\n className={cn(\n \"px-2.5 py-1 rounded-full text-[11px] font-medium border transition-colors\",\n selectedPills.includes(pill)\n ? thumbState === \"up\"\n ? \"bg-muted text-foreground border-border\"\n : \"bg-red-50 text-red-700 border-red-200 dark:bg-red-950/30 dark:text-red-300 dark:border-red-800\"\n : \"bg-background text-muted-foreground border-border hover:bg-muted/50 hover:text-foreground\"\n )}\n >\n {pill}\n </button>\n ))}\n </div>\n </div>\n\n <div className=\"space-y-1\">\n <input\n type=\"text\"\n value={detailText}\n onChange={(e) => setDetailText(e.target.value)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" && hasRequiredInput) handleSubmit()\n }}\n placeholder={\n thumbState === \"up\"\n ? \"Tell us more (optional)\"\n : \"e.g., The risk factors are outdated\"\n }\n className=\"w-full text-xs bg-background border border-border rounded-md px-2.5 py-2 text-foreground placeholder:text-muted-foreground/50 focus:outline-none focus:ring-1 focus:ring-ring\"\n />\n {otherSelected && detailText.trim().length === 0 && (\n <span className=\"text-[10px] text-red-500\">\n Please describe when &ldquo;Other&rdquo; is selected\n </span>\n )}\n </div>\n\n <div className=\"flex items-center gap-2 pt-1\">\n <button\n type=\"button\"\n onClick={handleSubmit}\n disabled={!hasRequiredInput}\n className={cn(\n \"flex-1 py-1.5 rounded-md text-xs font-semibold transition-colors\",\n hasRequiredInput\n ? \"bg-foreground text-background hover:bg-foreground/90\"\n : \"bg-muted text-muted-foreground cursor-not-allowed\"\n )}\n >\n Submit\n </button>\n </div>\n </div>\n </div>\n )\n}\n\nexport const ScoreFeedback = { Root, Trigger, Panel }\nexport { useScoreFeedback }\n"],"mappings":"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","names":[]}
@@ -652,6 +652,16 @@ function SuggestedActionCard({
652
652
  );
653
653
  const [showAiEdit, setShowAiEdit] = React.useState(false);
654
654
  const [feedbackOpen, setFeedbackOpen] = React.useState(false);
655
+ const [feedbackDirection, setFeedbackDirection] = React.useState(null);
656
+ const handleThumbClick = (dir) => {
657
+ if (feedbackOpen && feedbackDirection === dir) {
658
+ setFeedbackOpen(false);
659
+ setFeedbackDirection(null);
660
+ } else {
661
+ setFeedbackDirection(dir);
662
+ setFeedbackOpen(true);
663
+ }
664
+ };
655
665
  const [followUpEnabled, setFollowUpEnabled] = React.useState((_f = (_e = action.followUp) == null ? void 0 : _e.enabled) != null ? _f : false);
656
666
  const [threadExpanded, setThreadExpanded] = React.useState(false);
657
667
  const [expandedMessageId, setExpandedMessageId] = React.useState(null);
@@ -726,16 +736,16 @@ function SuggestedActionCard({
726
736
  /* @__PURE__ */ jsx(
727
737
  "button",
728
738
  {
729
- onClick: () => setFeedbackOpen(!feedbackOpen),
730
- className: `p-1.5 rounded transition-colors ${feedbackOpen ? "bg-emerald-100 text-emerald-600 dark:bg-emerald-900/30 dark:text-emerald-400" : "hover:bg-muted text-muted-foreground hover:text-foreground"}`,
739
+ onClick: () => handleThumbClick("up"),
740
+ className: `p-1.5 rounded transition-colors ${feedbackOpen && feedbackDirection === "up" ? "bg-muted text-foreground" : "hover:bg-muted text-muted-foreground hover:text-foreground"}`,
731
741
  children: /* @__PURE__ */ jsx(ThumbsUp, { className: "w-3.5 h-3.5" })
732
742
  }
733
743
  ),
734
744
  /* @__PURE__ */ jsx(
735
745
  "button",
736
746
  {
737
- onClick: () => setFeedbackOpen(!feedbackOpen),
738
- className: "p-1.5 rounded transition-colors hover:bg-muted text-muted-foreground hover:text-foreground",
747
+ onClick: () => handleThumbClick("down"),
748
+ className: `p-1.5 rounded transition-colors ${feedbackOpen && feedbackDirection === "down" ? "bg-muted text-foreground" : "hover:bg-muted text-muted-foreground hover:text-foreground"}`,
739
749
  children: /* @__PURE__ */ jsx(ThumbsDown, { className: "w-3.5 h-3.5" })
740
750
  }
741
751
  ),
@@ -755,6 +765,7 @@ function SuggestedActionCard({
755
765
  feedbackOpen && /* @__PURE__ */ jsx("div", { className: "px-5 py-3 border-b border-border/40 animate-in fade-in slide-in-from-top-2 duration-200", children: /* @__PURE__ */ jsx(
756
766
  DraftFeedbackInline,
757
767
  {
768
+ initialDirection: feedbackDirection,
758
769
  onRegenerateRequest: (pills, detail) => {
759
770
  onFeedback == null ? void 0 : onFeedback("down", pills, detail);
760
771
  },
@@ -765,7 +776,8 @@ function SuggestedActionCard({
765
776
  onFeedback == null ? void 0 : onFeedback("down", pills, detail);
766
777
  onDismiss == null ? void 0 : onDismiss(action.id);
767
778
  }
768
- }
779
+ },
780
+ `feedback-${feedbackDirection}`
769
781
  ) }),
770
782
  isThreadReply && action.replyTo && /* @__PURE__ */ jsxs("div", { className: "border-b border-border/40", children: [
771
783
  action.threadMessages && action.threadMessages.length > 1 && /* @__PURE__ */ jsx("div", { className: "px-5 py-2 border-b border-border/40", children: /* @__PURE__ */ jsxs(