EventChip.tsx2.3 KBView on GitHub 'use client';
/**
* The event chip, extracted out of `EventNodeView` so the prose editor and the table grid
* render literally the same component (apps/mail/docs/table-documents.md §3.2 step 10).
* Same `container` mechanism as `ConversationChipContent` — read that module's comment for
* why the in-editor mount must BE the `NodeViewWrapper`.
*
* An event chip carries a denormalized `title` snapshot rather than resolving live: the
* mention popover writes the title into the node's attrs, so there is nothing to fetch.
* A table cell holding `[[event: id]]` has no snapshot, which is why `title` is optional
* and falls back to the id — an honest "this is an event, we don't know which" rather than
* a fabricated label.
*/
import { createElement, type ElementType, type ReactNode } from 'react';
import {
Calendar,
FileQuestion,
Mail,
MessageSquare,
Phone,
Sparkles,
StickyNote,
} from 'lucide-react';
import { cn } from '@/lib/utils';
import { REF_CHIP_CLASS } from '@/modules/documents/chip-styles';
const ICON_BY_TYPE: Record<string, React.ComponentType<{ className?: string }>> = {
email: Mail,
slack: MessageSquare,
meeting: Calendar,
call: Phone,
note: StickyNote,
custom: Sparkles,
};
export interface EventChipContentProps {
eventType?: string | null;
title?: string | null;
className?: string;
/** Element the chip renders AS. The PM node view passes `NodeViewWrapper`. */
container?: ElementType;
/** Forwarded verbatim to the container: PM's data attributes, `contentEditable`, `as`. */
containerProps?: Record<string, unknown>;
}
export function EventChipContent({
eventType,
title,
className,
container,
containerProps,
}: EventChipContentProps) {
const Icon = ICON_BY_TYPE[eventType ?? ''] ?? FileQuestion;
const label = title?.trim() || 'Event';
const shared = { title: label, className: cn(REF_CHIP_CLASS, 'font-medium', className) };
const body: ReactNode = (
<>
<Icon className="text-muted-foreground h-3 w-3 shrink-0" />
<span className="truncate">{label}</span>
</>
);
// See `ConversationChipContent` for why the polymorphic branch uses `createElement`.
if (container) return createElement(container, { ...containerProps, ...shared }, body);
return <span {...shared}>{body}</span>;
}