'use client'; import { isValidElement } from 'react'; import { cn } from '@djangocfg/ui-core/lib'; import type { ComposerFooterProps } from './types'; /** Counter starts announcing once the draft passes this fraction of the cap. */ const COUNTER_THRESHOLD = 0.8; const TEXT_SIZE = { sm: 'text-[11px]', md: 'text-xs', lg: 'text-xs', } as const; function shortcutHint(submitOn: 'enter' | 'cmd+enter'): string { return submitOn === 'cmd+enter' ? '⌘⏎ to send' : '⏎ to send · ⇧⏎ for newline'; } /** * The quiet strip below the input surface. Three zones: start (auto * shortcut hint), center (host extras), end (auto char counter). Renders * as a plain `div` unless it carries interactive controls. */ export function ComposerFooter({ start, center, end, showCounter = true, // Off by default — ChatGPT / Gemini don't surface a keyboard hint. // Hosts can opt back in with `showHint`. showHint = false, value = '', maxLength, submitOn = 'enter', size = 'md', className, }: ComposerFooterProps) { const nearLimit = maxLength !== undefined && value.length >= maxLength * COUNTER_THRESHOLD; const counterNode = showCounter && maxLength !== undefined && nearLimit ? ( = maxLength ? 'text-destructive' : 'text-muted-foreground', )} > {value.length} / {maxLength} ) : null; const hintNode = showHint && !start ? ( {shortcutHint(submitOn)} ) : null; const startNode = start ?? hintNode; const endNode = end ?? counterNode; // Nothing to show — render nothing rather than an empty strip. if (!startNode && !center && !endNode) return null; // A toolbar role is only correct when the strip carries host-provided // interactive controls. The auto hint/counter alone stay a plain div. const hasInteractive = isValidElement(center) || isValidElement(start) || isValidElement(end); return (
{startNode}
{center ?
{center}
: null}
{endNode}
); }