diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx
index dda1f790..13a6b9f0 100644
--- a/components/email/email-composer.tsx
+++ b/components/email/email-composer.tsx
@@ -49,6 +49,8 @@ import {
waitForPendingUploads,
extractUserAuthoredText,
type Recipient,
+ enrichChipsWithColorsAndIcons,
+ ICON_MAP,
} from "@/lib/email-composer-utils";
import { isValidEmail } from "@/lib/validation";
import { RichTextEditor } from "@/components/email/rich-text-editor";
@@ -826,6 +828,26 @@ export function EmailComposer({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [composerClient, plainTextMode, mode]);
+ const processEnrichment = async (
+ recipients: Recipient[],
+ setRecipients: (items: Recipient[]) => void
+ ) => {
+ const hasUnenriched = recipients.some((r) => !r.extra?.enriched);
+ if (!hasUnenriched) return;
+
+ const newChips = await enrichChipsWithColorsAndIcons(recipients);
+ const fullyEnriched = newChips.map((chip) => ({
+ ...chip,
+ extra: { ...chip.extra, enriched: true },
+ }));
+ setRecipients(fullyEnriched);
+ };
+
+
+ useEffect(() => { processEnrichment(to, setTo); }, [to]);
+ useEffect(() => { processEnrichment(cc, setCc); }, [cc]);
+ useEffect(() => { processEnrichment(bcc, setBcc); }, [bcc]);
+
const composerSignatureHtml = signatureIdentity?.htmlSignature
? `
${sanitizeSignatureHtmlForDisplay(signatureIdentity.htmlSignature)}
`
: signatureIdentity?.textSignature
@@ -3169,6 +3191,11 @@ function RecipientChipInput({
const handleContainerDrop = (e: React.DragEvent) => {
performDrop(e, dropIndex ?? chips.length);
};
+ const colorStyles: Record<'success' | 'destructive' | 'warning', string> = {
+ success: "bg-success/15 text-secondary-foreground hover:bg-success/30 !border-success",
+ destructive: "bg-destructive/15 text-secondary-foreground hover:bg-destructive/30 !border-destructive",
+ warning: "bg-warning/15 text-secondary-foreground hover:bg-warning/30 !border-warning",
+ };
return (
@@ -3186,6 +3213,12 @@ function RecipientChipInput({
{chips.map((chip, i) => {
const isEditing = editingChip?.index === i;
const chipDisplay = formatChipDisplay(chip);
+ let IconComponent = null;
+ if(chip.extra?.icon){
+ IconComponent = ICON_MAP[chip.extra?.icon];
+ }
+ const customColor = chip.extra?.color;
+
return (
{dropIndex === i && (
@@ -3214,11 +3247,17 @@ function RecipientChipInput({
"inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-sm border border-border transition-colors",
isEditing
? "bg-background ring-1 ring-ring"
- : "bg-secondary text-secondary-foreground hover:bg-accent cursor-grab active:cursor-grabbing",
+ : ( customColor && colorStyles[customColor]
+ ? `${colorStyles[customColor]} cursor-grab active:cursor-grabbing`
+ : "bg-secondary text-secondary-foreground hover:bg-accent cursor-grab active:cursor-grabbing"),
!isEditing && draggingIndex === i && "opacity-50"
)}
onContextMenu={isEditing ? undefined : (e) => handleContextMenu(e, i, chip)}
>
+ {IconComponent ? (
+
+ ) : null}
+
{isEditing ? (
};
+ extra?: {
+ color?: "success" | "destructive" | "warning"; // optional color for display purposes. May be populated by plugins via the onRecipientChipsChange hook.
+ icon?: IconName; // optional icon for display purposes. May be populated by plugins via the onRecipientChipsChange hook.
+ enriched?: boolean; // optional flag to indicate if the recipient has been enriched by plugins via the onRecipientChipsChange hook.
+ };
+};
+
+/** Enriches recipient chips with colors and icons. */
+export async function enrichChipsWithColorsAndIcons(chips: Recipient[]): Promise {
+ return await emailHooks.onRecipientChipsChange.transform(chips);
};
/**
diff --git a/lib/plugin-hooks.ts b/lib/plugin-hooks.ts
index 02fb8107..a298e933 100644
--- a/lib/plugin-hooks.ts
+++ b/lib/plugin-hooks.ts
@@ -276,6 +276,10 @@ export const emailHooks = {
// lets plugin edit emails before they are shown in row. Used to populate preview
// field for encryption plugins.
onEmailsFetched: new HookBus(),
+ // Transform hook - lets plugins edit the recipient chips in composer fields.
+ // They can add, remove, or modify chips (e.g. rewrite addresses, add colors/icons).
+ // Take Recipient[] as argument.
+ onRecipientChipsChange: new HookBus(),
};
// ยง7.2 Calendar Hooks