@handled-ai/design-system 0.18.35 → 0.18.37
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/charts/chart.d.ts +1 -1
- package/dist/components/badge.d.ts +1 -1
- package/dist/components/button.d.ts +1 -1
- package/dist/components/draft-feedback-inline.d.ts +1 -1
- package/dist/components/draft-feedback-inline.js +10 -10
- package/dist/components/draft-feedback-inline.js.map +1 -1
- package/dist/components/email-composer-row.d.ts +11 -0
- package/dist/components/email-composer-row.js +82 -0
- package/dist/components/email-composer-row.js.map +1 -0
- package/dist/components/email-preview-card.d.ts +17 -0
- package/dist/components/email-preview-card.js +71 -0
- package/dist/components/email-preview-card.js.map +1 -0
- package/dist/components/email-recipient-field.d.ts +26 -0
- package/dist/components/email-recipient-field.js +400 -0
- package/dist/components/email-recipient-field.js.map +1 -0
- package/dist/components/email-send-bar.d.ts +22 -0
- package/dist/components/email-send-bar.js +66 -0
- package/dist/components/email-send-bar.js.map +1 -0
- package/dist/components/pill.d.ts +1 -1
- package/dist/components/score-feedback.js +6 -6
- package/dist/components/score-feedback.js.map +1 -1
- package/dist/components/suggested-actions.js +5 -17
- package/dist/components/suggested-actions.js.map +1 -1
- package/dist/components/tabs.d.ts +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +5 -1
- package/src/components/__tests__/email-composer-row.test.tsx +51 -0
- package/src/components/__tests__/email-preview-card.test.tsx +62 -0
- package/src/components/__tests__/email-recipient-field.test.tsx +256 -0
- package/src/components/__tests__/email-send-bar.test.tsx +80 -0
- package/src/components/draft-feedback-inline.tsx +13 -13
- package/src/components/email-composer-row.tsx +47 -0
- package/src/components/email-preview-card.tsx +94 -0
- package/src/components/email-recipient-field.tsx +456 -0
- package/src/components/email-send-bar.tsx +95 -0
- package/src/components/score-feedback.tsx +7 -7
- package/src/components/suggested-actions.tsx +5 -19
- package/src/index.ts +4 -0
- package/src/components/__tests__/draft-feedback-inline.test.tsx +0 -72
- package/src/components/__tests__/suggested-actions-feedback-header.test.tsx +0 -86
|
@@ -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-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'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 “Other” 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":";AAgHI,cA8BE,YA9BF;AA9GJ,YAAY,WAAW;AACvB,SAAS,UAAU,YAAY,aAAa;AAC5C,SAAS,UAAU;AAEnB,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,MAAM,gBAAgB;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAuBA,MAAM,mBAAmB,MAAM,cAAyC,IAAI;AAE5E,SAAS,mBAAmB;AAC1B,QAAM,MAAM,MAAM,WAAW,gBAAgB;AAC7C,MAAI,CAAC,IAAK,OAAM,IAAI,MAAM,wCAAwC;AAClE,SAAO;AACT;AAQA,SAAS,KAAK,EAAE,UAAU,kBAAkB,gBAAgB,GAAc;AACxE,QAAM,CAAC,YAAY,aAAa,IAAI,MAAM,SAA+B,IAAI;AAC7E,QAAM,CAAC,eAAe,gBAAgB,IAAI,MAAM,SAAmB,CAAC,CAAC;AACrE,QAAM,CAAC,YAAY,kBAAkB,IAAI,MAAM,SAAS,EAAE;AAC1D,QAAM,CAAC,WAAW,YAAY,IAAI,MAAM,SAA+B,IAAI;AAC3E,QAAM,CAAC,mBAAmB,oBAAoB,IAAI,MAAM;AAAA,IACtD,4CAAmB;AAAA,EACrB;AAIA,QAAM,UAAU,MAAM;AACpB,QAAI,eAAe,KAAM;AACzB,yBAAqB,4CAAmB,IAAI;AAAA,EAC9C,GAAG,CAAC,eAAe,CAAC;AAEpB,QAAM,gBAAgB,cAAc,SAAS,OAAO;AAEpD,QAAM,mBACJ,eAAe,SACX,cAAc,SAAS,MAAM,CAAC,iBAAiB,WAAW,KAAK,EAAE,SAAS,KAC1E,cAAc,SAAS,KAAK,WAAW,KAAK,EAAE,SAAS;AAE7D,QAAM,aAAa,MAAM,YAAY,CAAC,SAAiB;AACrD;AAAA,MAAiB,CAAC,SAChB,KAAK,SAAS,IAAI,IAAI,KAAK,OAAO,CAAC,MAAM,MAAM,IAAI,IAAI,CAAC,GAAG,MAAM,IAAI;AAAA,IACvE;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,mBAAmB,MAAM,YAAY,CAAC,SAAwB;AAClE,kBAAc,CAAC,SAAU,SAAS,OAAO,OAAO,IAAK;AACrD,qBAAiB,CAAC,CAAC;AACnB,uBAAmB,EAAE;AAAA,EACvB,GAAG,CAAC,CAAC;AAEL,QAAM,eAAe,MAAM,YAAY,MAAM;AAC3C,QAAI,CAAC,WAAY;AACjB,yDAAmB,YAAY,eAAe;AAC9C,yBAAqB,EAAE,MAAM,YAAY,OAAO,CAAC,GAAG,aAAa,GAAG,QAAQ,WAAW,KAAK,EAAE,CAAC;AAC/F,iBAAa,UAAU;AACvB,kBAAc,IAAI;AAClB,qBAAiB,CAAC,CAAC;AACnB,uBAAmB,EAAE;AACrB,eAAW,MAAM,aAAa,IAAI,GAAG,GAAI;AAAA,EAC3C,GAAG,CAAC,YAAY,eAAe,YAAY,gBAAgB,CAAC;AAE5D,QAAM,gBAAgB,MAAM,YAAY,MAAM;AAC5C,QAAI,CAAC,kBAAmB;AACxB,kBAAc,kBAAkB,IAAI;AACpC,qBAAiB,CAAC,GAAG,kBAAkB,KAAK,CAAC;AAC7C,uBAAmB,kBAAkB,MAAM;AAC3C,iBAAa,IAAI;AAAA,EACnB,GAAG,CAAC,iBAAiB,CAAC;AAEtB,SACE;AAAA,IAAC,iBAAiB;AAAA,IAAjB;AAAA,MACC,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA,eAAe;AAAA,QACf;AAAA,QACA;AAAA,MACF;AAAA,MAEC;AAAA;AAAA,EACH;AAEJ;AAEA,SAAS,QAAQ,EAAE,UAAU,GAA2B;AACtD,QAAM,EAAE,YAAY,WAAW,mBAAmB,kBAAkB,cAAc,IAAI,iBAAiB;AAEvG,MAAI,aAAc,qBAAqB,CAAC,YAAa;AACnD,UAAM,QAAQ,YACV,cAAc,OAAO,UAAU,cAC/B,uDAAmB,UAAS,OAAO,UAAU;AAEjD,WACE;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,oBAAoB,gBAAgB;AAAA,QAC7C,WAAW;AAAA,UACT;AAAA,UACA,oBAAoB,qCAAqC;AAAA,UACzD;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,SAAM,WAAU,2BAA0B;AAAA,UAC3C,oBAAC,UAAK,WAAU,qCAAqC,iBAAM;AAAA;AAAA;AAAA,IAC7D;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,WAAW,GAAG,yBAAyB,SAAS,GACnD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,iBAAiB,IAAI;AAAA,QACpC,WAAW;AAAA,UACT;AAAA,UACA,eAAe,OACX,6BACA;AAAA,QACN;AAAA,QAEA,8BAAC,YAAS,WAAU,eAAc;AAAA;AAAA,IACpC;AAAA,IACA;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAM,iBAAiB,MAAM;AAAA,QACtC,WAAW;AAAA,UACT;AAAA,UACA,eAAe,SACX,6BACA;AAAA,QACN;AAAA,QAEA,8BAAC,cAAW,WAAU,eAAc;AAAA;AAAA,IACtC;AAAA,KACF;AAEJ;AAEA,SAAS,MAAM,EAAE,UAAU,GAA2B;AACpD,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,IAAI,iBAAiB;AAErB,MAAI,CAAC,WAAY,QAAO;AAExB,SACE,oBAAC,SAAI,WAAW,GAAG,mBAAmB,SAAS,GAC7C,+BAAC,SAAI,WAAU,sDACb;AAAA,wBAAC,UAAK,WAAU,2EAA0E,+BAE1F;AAAA,IACA,qBAAC,SACC;AAAA,0BAAC,UAAK,WAAU,wDACb,yBAAe,OAAO,qBAAqB,0BAC9C;AAAA,MACA,oBAAC,SAAI,WAAU,0BACX,0BAAe,OAAO,gBAAgB,eAAe,IAAI,CAAC,SAC1D;AAAA,QAAC;AAAA;AAAA,UAEC,MAAK;AAAA,UACL,SAAS,MAAM,WAAW,IAAI;AAAA,UAC9B,WAAW;AAAA,YACT;AAAA,YACA,cAAc,SAAS,IAAI,IACvB,eAAe,OACb,2CACA,mGACF;AAAA,UACN;AAAA,UAEC;AAAA;AAAA,QAZI;AAAA,MAaP,CACD,GACH;AAAA,OACF;AAAA,IAEA,qBAAC,SAAI,WAAU,aACb;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,OAAO;AAAA,UACP,UAAU,CAAC,MAAM,cAAc,EAAE,OAAO,KAAK;AAAA,UAC7C,WAAW,CAAC,MAAM;AAChB,gBAAI,EAAE,QAAQ,WAAW,iBAAkB,cAAa;AAAA,UAC1D;AAAA,UACA,aACE,eAAe,OACX,4BACA;AAAA,UAEN,WAAU;AAAA;AAAA,MACZ;AAAA,MACC,iBAAiB,WAAW,KAAK,EAAE,WAAW,KAC7C,oBAAC,UAAK,WAAU,4BAA2B,gEAE3C;AAAA,OAEJ;AAAA,IAEA,oBAAC,SAAI,WAAU,gCACb;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS;AAAA,QACT,UAAU,CAAC;AAAA,QACX,WAAW;AAAA,UACT;AAAA,UACA,mBACI,yDACA;AAAA,QACN;AAAA,QACD;AAAA;AAAA,IAED,GACF;AAAA,KACF,GACF;AAEJ;AAEO,MAAM,gBAAgB,EAAE,MAAM,SAAS,MAAM;","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-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'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 “Other” 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,16 +652,6 @@ 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
|
-
};
|
|
665
655
|
const [followUpEnabled, setFollowUpEnabled] = React.useState((_f = (_e = action.followUp) == null ? void 0 : _e.enabled) != null ? _f : false);
|
|
666
656
|
const [threadExpanded, setThreadExpanded] = React.useState(false);
|
|
667
657
|
const [expandedMessageId, setExpandedMessageId] = React.useState(null);
|
|
@@ -736,16 +726,16 @@ function SuggestedActionCard({
|
|
|
736
726
|
/* @__PURE__ */ jsx(
|
|
737
727
|
"button",
|
|
738
728
|
{
|
|
739
|
-
onClick: () =>
|
|
740
|
-
className: `p-1.5 rounded transition-colors ${feedbackOpen
|
|
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"}`,
|
|
741
731
|
children: /* @__PURE__ */ jsx(ThumbsUp, { className: "w-3.5 h-3.5" })
|
|
742
732
|
}
|
|
743
733
|
),
|
|
744
734
|
/* @__PURE__ */ jsx(
|
|
745
735
|
"button",
|
|
746
736
|
{
|
|
747
|
-
onClick: () =>
|
|
748
|
-
className:
|
|
737
|
+
onClick: () => setFeedbackOpen(!feedbackOpen),
|
|
738
|
+
className: "p-1.5 rounded transition-colors hover:bg-muted text-muted-foreground hover:text-foreground",
|
|
749
739
|
children: /* @__PURE__ */ jsx(ThumbsDown, { className: "w-3.5 h-3.5" })
|
|
750
740
|
}
|
|
751
741
|
),
|
|
@@ -765,7 +755,6 @@ function SuggestedActionCard({
|
|
|
765
755
|
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(
|
|
766
756
|
DraftFeedbackInline,
|
|
767
757
|
{
|
|
768
|
-
initialDirection: feedbackDirection,
|
|
769
758
|
onRegenerateRequest: (pills, detail) => {
|
|
770
759
|
onFeedback == null ? void 0 : onFeedback("down", pills, detail);
|
|
771
760
|
},
|
|
@@ -776,8 +765,7 @@ function SuggestedActionCard({
|
|
|
776
765
|
onFeedback == null ? void 0 : onFeedback("down", pills, detail);
|
|
777
766
|
onDismiss == null ? void 0 : onDismiss(action.id);
|
|
778
767
|
}
|
|
779
|
-
}
|
|
780
|
-
`feedback-${feedbackDirection}`
|
|
768
|
+
}
|
|
781
769
|
) }),
|
|
782
770
|
isThreadReply && action.replyTo && /* @__PURE__ */ jsxs("div", { className: "border-b border-border/40", children: [
|
|
783
771
|
action.threadMessages && action.threadMessages.length > 1 && /* @__PURE__ */ jsx("div", { className: "px-5 py-2 border-b border-border/40", children: /* @__PURE__ */ jsxs(
|