@mieweb/ui 0.9.0-dev.2 → 0.9.0-dev.4
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/{Animated-Cs-naa2g.d.cts → Animated-XmH6k8pZ.d.cts} +16 -3
- package/dist/{Animated-Cs-naa2g.d.ts → Animated-XmH6k8pZ.d.ts} +16 -3
- package/dist/{chunk-XUVEF2RQ.js → chunk-24SEAAOH.js} +2 -2
- package/dist/{chunk-XUVEF2RQ.js.map → chunk-24SEAAOH.js.map} +1 -1
- package/dist/{chunk-FUFBRKOG.cjs → chunk-2WBPNXO2.cjs} +21 -21
- package/dist/{chunk-FUFBRKOG.cjs.map → chunk-2WBPNXO2.cjs.map} +1 -1
- package/dist/{chunk-IUDY6S7I.cjs → chunk-37UZHCLM.cjs} +35 -14
- package/dist/chunk-37UZHCLM.cjs.map +1 -0
- package/dist/{chunk-O425FKDI.cjs → chunk-3MHG4HYB.cjs} +5 -4
- package/dist/chunk-3MHG4HYB.cjs.map +1 -0
- package/dist/{chunk-L52N6BEN.cjs → chunk-AUOTJQGO.cjs} +7 -7
- package/dist/{chunk-L52N6BEN.cjs.map → chunk-AUOTJQGO.cjs.map} +1 -1
- package/dist/{chunk-KATEJG2F.js → chunk-DG6LIEUJ.js} +51 -5
- package/dist/chunk-DG6LIEUJ.js.map +1 -0
- package/dist/{chunk-2A2FLQJC.cjs → chunk-DH7I5HMK.cjs} +56 -10
- package/dist/chunk-DH7I5HMK.cjs.map +1 -0
- package/dist/{chunk-ADUEASXF.cjs → chunk-E7G22IQM.cjs} +27 -27
- package/dist/{chunk-ADUEASXF.cjs.map → chunk-E7G22IQM.cjs.map} +1 -1
- package/dist/{chunk-ONNY7UO4.js → chunk-JDJQTKTX.js} +3 -3
- package/dist/{chunk-ONNY7UO4.js.map → chunk-JDJQTKTX.js.map} +1 -1
- package/dist/{chunk-BJKAVWED.js → chunk-MBWF36DJ.js} +35 -14
- package/dist/chunk-MBWF36DJ.js.map +1 -0
- package/dist/chunk-NV2CWBI2.cjs +290 -0
- package/dist/chunk-NV2CWBI2.cjs.map +1 -0
- package/dist/{chunk-7KN6J7XV.cjs → chunk-OMAACCFW.cjs} +7 -7
- package/dist/{chunk-7KN6J7XV.cjs.map → chunk-OMAACCFW.cjs.map} +1 -1
- package/dist/{chunk-YJP6DUFO.cjs → chunk-PKD3JLS2.cjs} +6 -6
- package/dist/{chunk-YJP6DUFO.cjs.map → chunk-PKD3JLS2.cjs.map} +1 -1
- package/dist/{chunk-5H7SAEQO.js → chunk-QKFJDQEK.js} +3 -3
- package/dist/{chunk-5H7SAEQO.js.map → chunk-QKFJDQEK.js.map} +1 -1
- package/dist/{chunk-XJTFZLWH.cjs → chunk-QO6PRHDX.cjs} +2 -2
- package/dist/{chunk-XJTFZLWH.cjs.map → chunk-QO6PRHDX.cjs.map} +1 -1
- package/dist/{chunk-OHDIJOGG.js → chunk-RD3JDFYJ.js} +3 -3
- package/dist/{chunk-OHDIJOGG.js.map → chunk-RD3JDFYJ.js.map} +1 -1
- package/dist/{chunk-4SM3I7WE.cjs → chunk-RXPEZXAB.cjs} +67 -38
- package/dist/chunk-RXPEZXAB.cjs.map +1 -0
- package/dist/{chunk-VTR2KGLY.cjs → chunk-S3BCHPXT.cjs} +9 -9
- package/dist/{chunk-VTR2KGLY.cjs.map → chunk-S3BCHPXT.cjs.map} +1 -1
- package/dist/{chunk-KU3XRHWA.js → chunk-TZX76ZNZ.js} +67 -38
- package/dist/chunk-TZX76ZNZ.js.map +1 -0
- package/dist/{chunk-RPG2ZP2T.js → chunk-USZ3VEPE.js} +5 -4
- package/dist/chunk-USZ3VEPE.js.map +1 -0
- package/dist/{chunk-Q7G56ZIO.js → chunk-WUBMDOTG.js} +3 -3
- package/dist/{chunk-Q7G56ZIO.js.map → chunk-WUBMDOTG.js.map} +1 -1
- package/dist/chunk-XCP454Q6.js +263 -0
- package/dist/chunk-XCP454Q6.js.map +1 -0
- package/dist/{chunk-KI5ES4GR.js → chunk-XEZCHQHB.js} +11 -2
- package/dist/chunk-XEZCHQHB.js.map +1 -0
- package/dist/{chunk-I3DQXUSC.js → chunk-Y6DFMDMH.js} +3 -3
- package/dist/{chunk-I3DQXUSC.js.map → chunk-Y6DFMDMH.js.map} +1 -1
- package/dist/{chunk-2KQWEROH.js → chunk-YSEMAI4I.js} +3 -3
- package/dist/{chunk-2KQWEROH.js.map → chunk-YSEMAI4I.js.map} +1 -1
- package/dist/{chunk-XRKBHECB.cjs → chunk-Z3RYJWSV.cjs} +11 -2
- package/dist/chunk-Z3RYJWSV.cjs.map +1 -0
- package/dist/components/AlertDialog/index.cjs +4 -4
- package/dist/components/AlertDialog/index.js +3 -3
- package/dist/components/Collapsible/index.cjs +6 -4
- package/dist/components/Collapsible/index.js +3 -1
- package/dist/components/Dropdown/index.cjs +9 -8
- package/dist/components/Dropdown/index.js +2 -1
- package/dist/components/KeyboardShortcutsOverlay/index.cjs +5 -5
- package/dist/components/KeyboardShortcutsOverlay/index.js +3 -3
- package/dist/components/MediaEditor/index.cjs +8 -8
- package/dist/components/MediaEditor/index.js +3 -3
- package/dist/components/Modal/index.cjs +10 -10
- package/dist/components/Modal/index.js +2 -2
- package/dist/components/RichTextEditor/index.cjs +6 -5
- package/dist/components/RichTextEditor/index.js +3 -2
- package/dist/components/SuperChat/index.cjs +14 -13
- package/dist/components/SuperChat/index.cjs.map +1 -1
- package/dist/components/SuperChat/index.js +3 -2
- package/dist/components/SuperChat/index.js.map +1 -1
- package/dist/components/SuperChat/plugins/index.cjs +2 -2
- package/dist/components/SuperChat/plugins/index.js +1 -1
- package/dist/esheet.cjs +6 -6
- package/dist/esheet.js +3 -3
- package/dist/hooks/index.cjs +13 -13
- package/dist/hooks/index.js +1 -1
- package/dist/index.cjs +1068 -1048
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +28 -2
- package/dist/index.d.ts +28 -2
- package/dist/index.js +689 -669
- package/dist/index.js.map +1 -1
- package/dist/motion.cjs +7 -7
- package/dist/motion.d.cts +1 -1
- package/dist/motion.d.ts +1 -1
- package/dist/motion.js +2 -2
- package/dist/styles.css +1 -1
- package/dist/tailwind-preset.cjs +4 -4
- package/dist/tailwind-preset.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2A2FLQJC.cjs.map +0 -1
- package/dist/chunk-4SM3I7WE.cjs.map +0 -1
- package/dist/chunk-BJKAVWED.js.map +0 -1
- package/dist/chunk-BN75TLUN.cjs +0 -163
- package/dist/chunk-BN75TLUN.cjs.map +0 -1
- package/dist/chunk-IUDY6S7I.cjs.map +0 -1
- package/dist/chunk-KATEJG2F.js.map +0 -1
- package/dist/chunk-KI5ES4GR.js.map +0 -1
- package/dist/chunk-KU3XRHWA.js.map +0 -1
- package/dist/chunk-O425FKDI.cjs.map +0 -1
- package/dist/chunk-RPG2ZP2T.js.map +0 -1
- package/dist/chunk-WYMO3IIK.js +0 -136
- package/dist/chunk-WYMO3IIK.js.map +0 -1
- package/dist/chunk-XRKBHECB.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/Messaging/MessageComposer.tsx","../src/components/Messaging/MessageBubble.tsx","../src/components/Messaging/MessageList.tsx","../src/components/Messaging/ConversationHeader.tsx","../src/components/Messaging/MessageThread.tsx","../src/components/Messaging/hooks.ts"],"names":["React","cva","jsxs","jsx","React2","React3","React4","React5"],"mappings":"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","file":"chunk-RPG2ZP2T.js","sourcesContent":["import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\nimport {\n MentionMenu,\n useMentionAutocomplete,\n type MentionOption,\n} from './useMentionAutocomplete';\nimport type { AttachmentType, NewMessage } from './types';\nimport {\n AttachmentPicker,\n AttachmentPreviewItem,\n CameraButton,\n DragDropZone,\n getFileType,\n generateAttachmentId,\n} from './AttachmentPicker';\n\n// ============================================================================\n// Types\n// ============================================================================\n\ninterface PendingAttachment {\n id: string;\n file: File;\n previewUrl?: string;\n type: AttachmentType;\n state: 'pending' | 'uploading' | 'uploaded' | 'failed';\n progress?: number;\n error?: string;\n}\n\n// `MentionOption` lives in the shared mention module (used by ChatComposer\n// too); re-exported here so existing deep imports keep working.\nexport type { MentionOption };\n\n/**\n * Whether a file satisfies one of the accepted `<input accept>` tokens.\n * Supports `type/*` wildcards, exact `type/subtype` tokens, and `.ext`\n * extension tokens (matched against the file name, mirroring the native\n * `<input accept>` behavior used by the picker and drag-and-drop).\n */\nfunction isFileAccepted(file: File, accepted: string[]): boolean {\n if (!accepted || accepted.length === 0) return true;\n const mime = file.type;\n const name = file.name.toLowerCase();\n return accepted.some((token) => {\n if (token.startsWith('.')) return name.endsWith(token.toLowerCase());\n if (token.endsWith('/*')) return mime.startsWith(token.slice(0, -1));\n if (token.includes('/')) return mime === token;\n return false;\n });\n}\n\n// ============================================================================\n// Character Counter Component\n// ============================================================================\n\nexport interface CharacterCounterProps {\n current: number;\n max: number;\n showWarningAt?: number;\n className?: string;\n}\n\n/**\n * Displays character count with warning colors.\n */\nfunction CharacterCounter({\n current,\n max,\n showWarningAt = 0.9,\n className,\n}: CharacterCounterProps) {\n const percentage = current / max;\n const isWarning = percentage >= showWarningAt && percentage < 1;\n const isOver = current > max;\n\n return (\n <span\n className={cn(\n 'text-xs tabular-nums',\n isOver\n ? 'font-medium text-red-700 dark:text-red-400'\n : isWarning\n ? 'text-amber-700 dark:text-amber-400'\n : 'text-neutral-600 dark:text-neutral-400',\n className\n )}\n aria-live=\"polite\"\n aria-label={`${current} of ${max} characters`}\n >\n {current}/{max}\n </span>\n );\n}\n\nCharacterCounter.displayName = 'CharacterCounter';\n\n// ============================================================================\n// Send Button Component\n// ============================================================================\n\nconst sendButtonVariants = cva(\n [\n 'inline-flex items-center justify-center',\n 'rounded-full p-3 self-start',\n 'transition-all duration-200',\n 'focus:outline-none focus:ring-2 focus:ring-primary-500',\n 'disabled:opacity-50 disabled:cursor-not-allowed',\n ],\n {\n variants: {\n variant: {\n primary: [\n 'bg-primary-800 text-white',\n 'hover:bg-primary-900',\n 'active:scale-95',\n ],\n subtle: [\n 'bg-transparent text-primary-800',\n 'hover:bg-primary-50 dark:hover:bg-primary-900/20',\n ],\n },\n canSend: {\n true: '',\n false: 'opacity-50 cursor-not-allowed',\n },\n },\n defaultVariants: {\n variant: 'primary',\n canSend: false,\n },\n }\n);\n\nexport interface SendButtonProps\n extends\n React.ButtonHTMLAttributes<HTMLButtonElement>,\n VariantProps<typeof sendButtonVariants> {\n isLoading?: boolean;\n}\n\n/**\n * Send button with loading state.\n */\nconst SendButton = React.forwardRef<HTMLButtonElement, SendButtonProps>(\n ({ className, variant, canSend, isLoading, disabled, ...props }, ref) => {\n return (\n <button\n ref={ref}\n type=\"submit\"\n disabled={disabled || !canSend || isLoading}\n data-slot=\"composer-send-button\"\n className={cn(sendButtonVariants({ variant, canSend }), className)}\n aria-label={isLoading ? 'Sending message' : 'Send message'}\n {...props}\n >\n {isLoading ? (\n <svg\n aria-hidden=\"true\"\n className=\"h-5 w-5 animate-spin\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n ) : (\n <svg\n aria-hidden=\"true\"\n className=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 19l9 2-9-18-9 18 9-2zm0 0v-8\"\n />\n </svg>\n )}\n </button>\n );\n }\n);\n\nSendButton.displayName = 'SendButton';\n\n// ============================================================================\n// Message Composer Component\n// ============================================================================\n\nexport interface MessageComposerProps {\n /** Called when a message is sent */\n onSend: (message: NewMessage) => void | Promise<void>;\n /** Called when the user starts typing */\n onTypingStart?: () => void;\n /** Called when the user stops typing */\n onTypingStop?: () => void;\n /** Controlled value for the textarea */\n value?: string;\n /** Callback when value changes (for controlled mode) */\n onValueChange?: (value: string) => void;\n /** Placeholder text */\n placeholder?: string;\n /** Maximum message length */\n maxLength?: number;\n /** Show character count */\n showCharacterCount?: boolean;\n /** Whether the composer is disabled */\n disabled?: boolean;\n /** Whether a message is currently being sent */\n isSending?: boolean;\n /** Show attachment picker */\n showAttachmentPicker?: boolean;\n /** Show camera button (mobile) */\n showCameraButton?: boolean;\n /** Accepted file types */\n acceptedFileTypes?: string[];\n /** Maximum file size */\n maxFileSize?: number;\n /** Maximum number of attachments */\n maxAttachments?: number;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n /** Auto-focus the input */\n autoFocus?: boolean;\n /** Reply-to message reference */\n replyTo?: {\n id: string;\n content: string;\n senderName: string;\n } | null;\n /** Called when reply is cancelled */\n onCancelReply?: () => void;\n /** Visual variant - 'default' shows border-t, 'minimal' has no border */\n variant?: 'default' | 'minimal';\n /** Content to render inside the input wrapper (e.g. a mic button) */\n inputTrailing?: React.ReactNode;\n /**\n * Candidates for `@mention` autocomplete. When provided (non-empty), typing\n * `@` opens a picker. Omit to disable mentions entirely (default).\n */\n mentionOptions?: MentionOption[];\n /** Additional class name */\n className?: string;\n}\n\n/**\n * A message input component with attachment support and send button.\n *\n * @example\n * ```tsx\n * <MessageComposer\n * onSend={handleSend}\n * placeholder=\"Type a message...\"\n * showAttachmentPicker\n * maxLength={1600}\n * />\n * ```\n */\nconst MessageComposer = React.forwardRef<\n HTMLTextAreaElement,\n MessageComposerProps\n>(\n (\n {\n onSend,\n onTypingStart,\n onTypingStop,\n value: controlledValue,\n onValueChange,\n placeholder = 'Type a message...',\n maxLength = 1600,\n showCharacterCount = false,\n disabled = false,\n isSending = false,\n showAttachmentPicker = true,\n showCameraButton = false,\n acceptedFileTypes = ['image/*', 'video/*', '.pdf', '.doc', '.docx'],\n maxFileSize = 25 * 1024 * 1024,\n maxAttachments = 10,\n onError,\n autoFocus = false,\n replyTo = null,\n onCancelReply,\n variant = 'default',\n inputTrailing,\n mentionOptions,\n className,\n },\n ref\n ) => {\n const textareaRef = React.useRef<HTMLTextAreaElement>(null);\n const [internalContent, setInternalContent] = React.useState('');\n const isControlled = controlledValue !== undefined;\n const content = isControlled ? controlledValue : internalContent;\n const setContent = React.useCallback(\n (val: string | ((prev: string) => string)) => {\n if (isControlled) {\n const newVal = typeof val === 'function' ? val(controlledValue) : val;\n onValueChange?.(newVal);\n } else {\n setInternalContent(val);\n }\n },\n [isControlled, controlledValue, onValueChange]\n );\n const [attachments, setAttachments] = React.useState<PendingAttachment[]>(\n []\n );\n const [isTyping, setIsTyping] = React.useState(false);\n const typingTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);\n\n // Combine refs\n React.useImperativeHandle(ref, () => textareaRef.current!);\n\n // Auto-resize textarea\n React.useEffect(() => {\n const textarea = textareaRef.current;\n if (textarea) {\n textarea.style.height = 'auto';\n textarea.style.height = `${Math.min(textarea.scrollHeight, 150)}px`;\n }\n }, [content]);\n\n // Handle typing indicators\n React.useEffect(() => {\n if (content.length > 0 && !isTyping) {\n setIsTyping(true);\n onTypingStart?.();\n }\n\n // Clear previous timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n // Set timeout to stop typing indicator\n typingTimeoutRef.current = setTimeout(() => {\n if (isTyping) {\n setIsTyping(false);\n onTypingStop?.();\n }\n }, 2000);\n\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n };\n }, [content, isTyping, onTypingStart, onTypingStop]);\n\n // Focus on mount if autoFocus\n React.useEffect(() => {\n if (autoFocus) {\n textareaRef.current?.focus();\n }\n }, [autoFocus]);\n\n // Focus when reply is set\n React.useEffect(() => {\n if (replyTo) {\n textareaRef.current?.focus();\n }\n }, [replyTo]);\n\n // --- @mention autocomplete (opt-in via `mentionOptions`) ---\n const mention = useMentionAutocomplete({\n options: mentionOptions,\n value: content,\n setValue: setContent,\n textareaRef,\n });\n\n const canSend =\n (content.trim().length > 0 || attachments.length > 0) &&\n content.length <= maxLength &&\n !disabled &&\n !isSending;\n\n const handleSubmit = async (event: React.FormEvent) => {\n event.preventDefault();\n if (!canSend) return;\n\n const message: NewMessage = {\n content: content.trim(),\n attachments: attachments.map((a) => a.file),\n replyToId: replyTo?.id,\n };\n\n // Clear state before sending for optimistic UI\n setContent('');\n setAttachments([]);\n setIsTyping(false);\n onTypingStop?.();\n\n try {\n await onSend(message);\n } catch {\n // Restore content on failure\n setContent(message.content);\n // Note: attachments would need to be re-added manually\n onError?.('Failed to send message');\n }\n };\n\n const handleKeyDown = (event: React.KeyboardEvent<HTMLTextAreaElement>) => {\n // @mention menu navigation takes priority over send.\n if (mention.handleKeyDown(event)) return;\n // Send on Enter (without Shift)\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n if (canSend) {\n handleSubmit(event);\n }\n }\n };\n\n const handleFilesSelected = (files: File[]) => {\n const remainingSlots = maxAttachments - attachments.length;\n const filesToAdd = files.slice(0, remainingSlots);\n\n if (files.length > remainingSlots) {\n onError?.(`Maximum ${maxAttachments} attachments allowed`);\n }\n\n const newAttachments: PendingAttachment[] = filesToAdd.map((file) => {\n const type = getFileType(file.type);\n let previewUrl: string | undefined;\n\n if (type === 'image' || type === 'video') {\n previewUrl = URL.createObjectURL(file);\n }\n\n return {\n id: generateAttachmentId(),\n file,\n previewUrl,\n type,\n state: 'pending' as const,\n };\n });\n\n setAttachments((prev) => [...prev, ...newAttachments]);\n };\n\n // Paste-to-attach: route pasted files through the same path as the picker.\n const handlePaste = (event: React.ClipboardEvent<HTMLTextAreaElement>) => {\n if (!showAttachmentPicker || disabled) return;\n const pasted = Array.from(event.clipboardData.items)\n .filter((item) => item.kind === 'file')\n .map((item) => item.getAsFile())\n .filter((f): f is File => f !== null)\n .filter((f) => isFileAccepted(f, acceptedFileTypes));\n if (pasted.length === 0) return;\n // We're attaching the file ourselves; don't also paste a blob/path.\n event.preventDefault();\n handleFilesSelected(pasted);\n };\n\n const handleRemoveAttachment = (attachmentId: string) => {\n setAttachments((prev) => {\n const attachment = prev.find((a) => a.id === attachmentId);\n if (attachment?.previewUrl) {\n URL.revokeObjectURL(attachment.previewUrl);\n }\n return prev.filter((a) => a.id !== attachmentId);\n });\n };\n\n // Cleanup preview URLs on unmount\n React.useEffect(() => {\n // Capture current attachments for cleanup\n const currentAttachments = attachments;\n return () => {\n currentAttachments.forEach((a) => {\n if (a.previewUrl) {\n URL.revokeObjectURL(a.previewUrl);\n }\n });\n };\n }, [attachments]);\n\n return (\n <DragDropZone\n onFilesDropped={handleFilesSelected}\n acceptedTypes={acceptedFileTypes}\n maxFileSize={maxFileSize}\n maxFiles={maxAttachments - attachments.length}\n disabled={disabled || attachments.length >= maxAttachments}\n onError={onError}\n className={cn('w-full', className)}\n >\n <form\n onSubmit={handleSubmit}\n data-slot=\"message-composer\"\n className=\"w-full\"\n >\n {/* Reply preview */}\n {replyTo && (\n <div\n data-slot=\"composer-reply-preview\"\n className={cn(\n 'flex items-center gap-2 px-4 py-2',\n 'bg-neutral-50 dark:bg-neutral-800/50',\n 'border-primary-500 border-s-4'\n )}\n >\n <div className=\"min-w-0 flex-1\">\n <span className=\"text-primary-800 dark:text-primary-400 text-xs font-medium\">\n Replying to {replyTo.senderName}\n </span>\n <p className=\"truncate text-sm text-neutral-600 dark:text-neutral-300\">\n {replyTo.content}\n </p>\n </div>\n <button\n type=\"button\"\n onClick={onCancelReply}\n className={cn(\n 'shrink-0 rounded p-1',\n 'text-neutral-500 hover:text-neutral-700',\n 'dark:text-neutral-400 dark:hover:text-neutral-200',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none'\n )}\n aria-label=\"Cancel reply\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n </div>\n )}\n\n {/* Attachment previews */}\n {attachments.length > 0 && (\n <div\n data-slot=\"composer-attachments\"\n className={cn(\n 'flex flex-wrap gap-2 p-3',\n 'border-t border-neutral-200 dark:border-neutral-700'\n )}\n >\n {attachments.map((attachment) => (\n <AttachmentPreviewItem\n key={attachment.id}\n attachment={attachment}\n onRemove={() => handleRemoveAttachment(attachment.id)}\n />\n ))}\n </div>\n )}\n\n {/* Input area */}\n <div\n data-slot=\"composer-input-area\"\n className={cn(\n 'flex items-center gap-2 p-3',\n 'bg-white dark:bg-neutral-900',\n variant === 'default' &&\n 'border-t border-neutral-200 dark:border-neutral-700'\n )}\n >\n {/* Attachment buttons */}\n {showAttachmentPicker && (\n <AttachmentPicker\n onFilesSelected={handleFilesSelected}\n acceptedTypes={acceptedFileTypes}\n maxFileSize={maxFileSize}\n maxFiles={maxAttachments - attachments.length}\n disabled={disabled || attachments.length >= maxAttachments}\n onError={onError}\n />\n )}\n\n {showCameraButton && (\n <CameraButton\n onCapture={(file) => handleFilesSelected([file])}\n disabled={disabled || attachments.length >= maxAttachments}\n />\n )}\n\n {/* Text input */}\n <div\n data-slot=\"composer-input-wrapper\"\n className=\"relative flex-1\"\n ref={mention.anchorRef}\n >\n <MentionMenu mention={mention} />\n <textarea\n ref={textareaRef}\n data-slot=\"composer-input\"\n value={content}\n onChange={(e) => {\n setContent(e.target.value);\n mention.sync(\n e.target.value,\n e.target.selectionStart ?? e.target.value.length\n );\n }}\n onClick={(e) => {\n const el = e.currentTarget;\n mention.sync(el.value, el.selectionStart ?? el.value.length);\n }}\n onKeyDown={handleKeyDown}\n onPaste={handlePaste}\n placeholder={placeholder}\n disabled={disabled || isSending}\n rows={1}\n className={cn(\n 'w-full resize-none rounded-2xl py-2.5',\n inputTrailing ? 'ps-4 pe-10' : 'px-4',\n 'bg-neutral-100 dark:bg-neutral-800',\n 'text-neutral-900 dark:text-neutral-100',\n 'placeholder:text-neutral-400 dark:placeholder:text-neutral-500',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'transition-colors',\n 'max-h-[150px]'\n )}\n aria-label=\"Message\"\n aria-describedby={showCharacterCount ? 'char-count' : undefined}\n {...mention.inputProps}\n />\n\n {/* Trailing content (e.g. record button) */}\n {inputTrailing && (\n <div\n data-slot=\"composer-input-trailing\"\n className=\"pointer-events-none absolute end-1 top-0 flex h-[44px] items-center [&>*]:pointer-events-auto\"\n >\n {inputTrailing}\n </div>\n )}\n\n {/* Character count */}\n {showCharacterCount && (\n <div\n data-slot=\"composer-char-count\"\n id=\"char-count\"\n className=\"absolute end-3 bottom-1.5\"\n >\n <CharacterCounter current={content.length} max={maxLength} />\n </div>\n )}\n </div>\n\n {/* Send button */}\n <SendButton\n canSend={canSend}\n isLoading={isSending}\n disabled={disabled}\n />\n </div>\n </form>\n </DragDropZone>\n );\n }\n);\n\nMessageComposer.displayName = 'MessageComposer';\n\nexport { MessageComposer, CharacterCounter, SendButton, sendButtonVariants };\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\nimport type {\n Message,\n MessageStatus,\n MessageAttachment,\n ReadReceipt,\n} from './types';\n\n// ============================================================================\n// Message Status Icon Component\n// ============================================================================\n\nconst statusIconVariants = cva(\n 'inline-flex items-center gap-0.5 text-current',\n {\n variants: {\n status: {\n sending: 'text-neutral-500',\n sent: 'text-neutral-500',\n delivered: 'text-muted-foreground',\n read: 'text-primary-800 dark:text-primary-300',\n failed: 'text-red-500',\n },\n },\n defaultVariants: {\n status: 'sent',\n },\n }\n);\n\nexport interface MessageStatusIconProps {\n status: MessageStatus;\n className?: string;\n}\n\n/**\n * Visual status indicator for messages (checkmarks).\n */\nfunction MessageStatusIcon({ status, className }: MessageStatusIconProps) {\n return (\n <span\n className={cn(statusIconVariants({ status }), className)}\n role=\"img\"\n aria-label={`Message ${status}`}\n >\n {status === 'sending' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3.5 w-3.5 animate-spin\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n )}\n {status === 'sent' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3.5 w-3.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5 13l4 4L19 7\"\n />\n </svg>\n )}\n {(status === 'delivered' || status === 'read') && (\n <svg\n aria-hidden=\"true\"\n className=\"h-4 w-4\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M5 13l4 4L19 7\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 13l4 4L26 7\"\n transform=\"translate(-5, 0)\"\n />\n </svg>\n )}\n {status === 'failed' && (\n <svg\n aria-hidden=\"true\"\n className=\"h-3.5 w-3.5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n )}\n </span>\n );\n}\n\n// ============================================================================\n// Read Receipt Indicator Component\n// ============================================================================\n\nexport interface ReadReceiptIndicatorProps {\n /** Read receipts to display */\n receipts: ReadReceipt[];\n /** Maximum avatars to show before +N */\n maxAvatars?: number;\n /** Size of avatars */\n size?: 'xs' | 'sm';\n className?: string;\n}\n\n/**\n * Displays read receipt avatars for group conversations.\n */\nfunction ReadReceiptIndicator({\n receipts,\n maxAvatars = 3,\n size = 'xs',\n className,\n}: ReadReceiptIndicatorProps) {\n if (receipts.length === 0) return null;\n\n const visibleReceipts = receipts.slice(0, maxAvatars);\n const remainingCount = receipts.length - maxAvatars;\n\n const sizeClasses = {\n xs: 'h-4 w-4 text-[8px]',\n sm: 'h-5 w-5 text-[10px]',\n };\n\n return (\n <div\n className={cn(\n 'flex items-center -space-x-1 rtl:space-x-reverse',\n className\n )}\n aria-label={`Read by ${receipts.map((r) => r.participant.name).join(', ')}`}\n >\n {visibleReceipts.map((receipt) => (\n <div\n key={receipt.participant.id}\n className={cn(\n 'rounded-full ring-2 ring-white dark:ring-neutral-900',\n 'bg-primary-800 font-medium text-white',\n 'flex items-center justify-center',\n sizeClasses[size]\n )}\n title={`Read by ${receipt.participant.name}`}\n >\n {receipt.participant.avatarUrl ? (\n <img\n src={receipt.participant.avatarUrl}\n alt={receipt.participant.name}\n className=\"h-full w-full rounded-full object-cover\"\n />\n ) : (\n receipt.participant.name.charAt(0).toUpperCase()\n )}\n </div>\n ))}\n {remainingCount > 0 && (\n <div\n className={cn(\n 'rounded-full ring-2 ring-white dark:ring-neutral-900',\n 'bg-neutral-500 font-medium text-white',\n 'flex items-center justify-center',\n sizeClasses[size]\n )}\n >\n +{remainingCount}\n </div>\n )}\n </div>\n );\n}\n\n// ============================================================================\n// Message Attachment Preview Component\n// ============================================================================\n\nexport interface AttachmentPreviewProps {\n attachment: MessageAttachment;\n onClick?: () => void;\n className?: string;\n}\n\n/**\n * Renders an attachment preview within a message bubble.\n */\nfunction AttachmentPreview({\n attachment,\n onClick,\n className,\n}: AttachmentPreviewProps) {\n const isImage = attachment.type === 'image';\n const isVideo = attachment.type === 'video';\n\n if (isImage || isVideo) {\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'relative block overflow-hidden rounded-lg',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n 'transition-transform hover:scale-[1.02]',\n className\n )}\n aria-label={`View ${attachment.alt || attachment.filename}`}\n >\n <img\n src={attachment.thumbnailUrl || attachment.url}\n alt={attachment.alt || attachment.filename}\n className=\"max-h-64 w-auto rounded-lg object-cover\"\n loading=\"lazy\"\n />\n {isVideo && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/30\">\n <div className=\"rounded-full bg-white/90 p-3\">\n <svg\n aria-hidden=\"true\"\n className=\"h-6 w-6 text-neutral-900\"\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M8 5v14l11-7z\" />\n </svg>\n </div>\n </div>\n )}\n {attachment.state === 'uploading' &&\n attachment.progress !== undefined && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50\">\n <div className=\"text-center text-white\">\n <svg\n aria-hidden=\"true\"\n className=\"mx-auto h-8 w-8 animate-spin\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n <span className=\"mt-1 text-sm\">{attachment.progress}%</span>\n </div>\n </div>\n )}\n {attachment.state === 'failed' && (\n <div className=\"absolute inset-0 flex items-center justify-center bg-black/50\">\n <div className=\"text-center text-white\">\n <svg\n aria-hidden=\"true\"\n className=\"mx-auto h-8 w-8 text-red-400\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z\"\n />\n </svg>\n <span className=\"mt-1 text-sm\">Upload failed</span>\n </div>\n </div>\n )}\n </button>\n );\n }\n\n // File/document attachment\n return (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n 'flex items-center gap-3 rounded-lg p-3',\n 'bg-white/10 hover:bg-white/20',\n 'transition-colors',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n className\n )}\n >\n <div className=\"rounded-lg bg-white/20 p-2\">\n <svg\n aria-hidden=\"true\"\n className=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z\"\n />\n </svg>\n </div>\n <div className=\"min-w-0 flex-1 text-start\">\n <p className=\"truncate text-sm font-medium\">{attachment.filename}</p>\n <p className=\"text-xs opacity-70\">{formatFileSize(attachment.size)}</p>\n </div>\n </button>\n );\n}\n\n/**\n * Format file size in human-readable format.\n */\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`;\n if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;\n}\n\n// ============================================================================\n// Message Bubble Component\n// ============================================================================\n\nconst bubbleVariants = cva(\n [\n 'relative max-w-[85%] sm:max-w-[70%]',\n 'rounded-2xl px-4 py-2',\n 'transition-all duration-200',\n ],\n {\n variants: {\n variant: {\n outgoing: ['bg-primary-800 text-white', 'rounded-ee-md', 'ms-auto'],\n incoming: [\n 'bg-neutral-100 text-neutral-900',\n 'dark:bg-neutral-800 dark:text-neutral-100',\n 'rounded-es-md',\n 'me-auto',\n ],\n system: [\n 'mx-auto max-w-none',\n 'bg-transparent text-muted-foreground',\n 'text-center text-sm',\n 'py-1 px-2',\n ],\n },\n status: {\n sending: '',\n sent: '',\n delivered: '',\n read: '',\n failed: 'ring-2 ring-red-500/50',\n },\n },\n defaultVariants: {\n variant: 'incoming',\n status: 'sent',\n },\n }\n);\n\nexport interface MessageBubbleProps\n extends\n Omit<React.HTMLAttributes<HTMLDivElement>, 'id'>,\n VariantProps<typeof bubbleVariants> {\n /** The message to display */\n message: Message;\n /** Whether to show the sender's avatar */\n showAvatar?: boolean;\n /** Whether to show the sender's name (for group chats) */\n showSenderName?: boolean;\n /** Whether to show the timestamp */\n showTimestamp?: boolean;\n /** Whether to show message status */\n showStatus?: boolean;\n /** Whether to show read receipts */\n showReadReceipts?: boolean;\n /** Called when retry is clicked for failed messages */\n onRetry?: () => void;\n /** Called when an attachment is clicked */\n onAttachmentClick?: (attachment: MessageAttachment) => void;\n /** Whether this is the current user's message */\n isOutgoing?: boolean;\n /** Custom timestamp formatter */\n formatTimestamp?: (timestamp: Date | string) => string;\n}\n\n/**\n * Default timestamp formatter.\n */\nfunction defaultFormatTimestamp(timestamp: Date | string): string {\n const date = typeof timestamp === 'string' ? new Date(timestamp) : timestamp;\n return date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n });\n}\n\n/**\n * A message bubble component for displaying individual messages.\n *\n * @example\n * ```tsx\n * <MessageBubble\n * message={message}\n * isOutgoing={message.sender.isCurrentUser}\n * showAvatar\n * showTimestamp\n * />\n * ```\n */\nconst MessageBubble = React.forwardRef<HTMLDivElement, MessageBubbleProps>(\n (\n {\n className,\n message,\n showAvatar = false,\n showSenderName = false,\n showTimestamp = true,\n showStatus = true,\n showReadReceipts = true,\n onRetry,\n onAttachmentClick,\n isOutgoing,\n formatTimestamp = defaultFormatTimestamp,\n ...props\n },\n ref\n ) => {\n const isSystem = message.type === 'system';\n const variant = isSystem ? 'system' : isOutgoing ? 'outgoing' : 'incoming';\n\n const hasAttachments =\n message.attachments && message.attachments.length > 0;\n const hasText = message.content && message.content.trim().length > 0;\n const isFailed = message.status === 'failed';\n\n // System messages render differently\n if (isSystem) {\n return (\n <div\n ref={ref}\n data-slot=\"message-system\"\n className={cn(bubbleVariants({ variant: 'system' }), className)}\n role=\"status\"\n aria-live=\"polite\"\n {...props}\n >\n {message.content}\n </div>\n );\n }\n\n return (\n <div\n ref={ref}\n data-slot=\"message-bubble\"\n className={cn(\n 'group flex items-end gap-2',\n isOutgoing ? 'flex-row-reverse' : 'flex-row',\n className\n )}\n {...props}\n >\n {/* Avatar */}\n {showAvatar && !isOutgoing && (\n <div data-slot=\"message-avatar\" className=\"mb-1 shrink-0\">\n <div\n className={cn(\n 'flex h-8 w-8 items-center justify-center rounded-full',\n 'bg-primary-800 text-sm font-medium text-white'\n )}\n >\n {message.sender.avatarUrl ? (\n <img\n src={message.sender.avatarUrl}\n alt={message.sender.name}\n className=\"h-full w-full rounded-full object-cover\"\n />\n ) : (\n message.sender.name.charAt(0).toUpperCase()\n )}\n </div>\n </div>\n )}\n\n {/* Message content container.\n *\n * `flex-1 min-w-0` lets this column expand to fill the row so the\n * bubble's `max-w-[85%]` resolves against the row width instead of\n * collapsing to the bubble's own min-content. Without this, short\n * words like \"Yes!\" get squeezed into a vertical stack because the\n * column shrink-wraps the bubble and the bubble's max-width then\n * shrinks the bubble further — a feedback loop that bottoms out at\n * `overflow-wrap: break-word` breaking every character.\n */}\n <div\n className={cn(\n 'flex min-w-0 flex-1 flex-col',\n isOutgoing ? 'items-end' : 'items-start'\n )}\n >\n {/* Sender name (for group chats) */}\n {showSenderName && !isOutgoing && (\n <span\n data-slot=\"message-sender-name\"\n className=\"text-muted-foreground mb-1 px-1 text-xs font-medium\"\n >\n {message.sender.name}\n </span>\n )}\n\n {/* Reply preview */}\n {message.replyTo && (\n <div\n data-slot=\"message-reply-preview\"\n className={cn(\n 'mb-1 max-w-full rounded-lg px-3 py-1.5 text-xs',\n isOutgoing\n ? 'bg-primary-700/50 text-white/80'\n : 'bg-neutral-200 text-neutral-600 dark:bg-neutral-700 dark:text-neutral-300'\n )}\n >\n <span className=\"font-medium\">{message.replyTo.sender.name}</span>\n <p className=\"truncate\">{message.replyTo.content}</p>\n </div>\n )}\n\n {/* Bubble */}\n <div\n data-slot=\"message-bubble-content\"\n className={cn(bubbleVariants({ variant, status: message.status }))}\n role=\"article\"\n aria-label={`Message from ${message.sender.name}`}\n >\n {/* Attachments */}\n {hasAttachments && (\n <div className={cn('space-y-2', hasText && 'mb-2')}>\n {message.attachments!.map((attachment) => (\n <AttachmentPreview\n key={attachment.id}\n attachment={attachment}\n onClick={() => onAttachmentClick?.(attachment)}\n />\n ))}\n </div>\n )}\n\n {/* Text content */}\n {hasText && (\n <p className=\"break-words whitespace-pre-wrap\">\n {message.isDeleted ? (\n <span className=\"italic opacity-60\">\n This message was deleted\n </span>\n ) : (\n message.content\n )}\n </p>\n )}\n\n {/* Edited indicator */}\n {message.isEdited && !message.isDeleted && (\n <span className=\"ms-1 text-xs opacity-60\">(edited)</span>\n )}\n </div>\n\n {/* Footer: timestamp, status, read receipts */}\n <div\n data-slot=\"message-footer\"\n className={cn(\n 'mt-1 flex items-center gap-2 px-1',\n isOutgoing ? 'flex-row-reverse' : 'flex-row'\n )}\n >\n {showTimestamp && (\n <span className=\"text-muted-foreground text-xs\">\n {formatTimestamp(message.timestamp)}\n </span>\n )}\n\n {showStatus && isOutgoing && (\n <MessageStatusIcon status={message.status} />\n )}\n\n {showReadReceipts &&\n isOutgoing &&\n message.readReceipts &&\n message.readReceipts.length > 0 && (\n <ReadReceiptIndicator receipts={message.readReceipts} />\n )}\n\n {/* Retry button for failed messages */}\n {isFailed && onRetry && (\n <button\n type=\"button\"\n onClick={onRetry}\n className={cn(\n 'flex items-center gap-1 rounded px-2 py-0.5',\n 'text-xs font-medium text-red-700 dark:text-red-400',\n 'hover:bg-red-50 dark:hover:bg-red-900/20',\n 'focus:ring-2 focus:ring-red-500 focus:outline-none'\n )}\n aria-label=\"Retry sending message\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-3 w-3\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15\"\n />\n </svg>\n Retry\n </button>\n )}\n </div>\n\n {/* Reactions */}\n {message.reactions && message.reactions.length > 0 && (\n <div\n data-slot=\"message-reactions\"\n className={cn(\n '-mt-1 flex flex-wrap gap-1',\n isOutgoing ? 'justify-end' : 'justify-start'\n )}\n >\n {message.reactions.map((reaction) => (\n <span\n key={reaction.emoji}\n className={cn(\n 'inline-flex items-center gap-1 rounded-full px-2 py-0.5',\n 'bg-neutral-100 text-xs dark:bg-neutral-800',\n 'border border-neutral-200 dark:border-neutral-700'\n )}\n title={reaction.participants.map((p) => p.name).join(', ')}\n >\n <span>{reaction.emoji}</span>\n {reaction.count > 1 && (\n <span className=\"text-neutral-500\">{reaction.count}</span>\n )}\n </span>\n ))}\n </div>\n )}\n </div>\n\n {/* Spacer for avatar alignment when showing own messages */}\n {showAvatar && isOutgoing && <div className=\"w-8 shrink-0\" />}\n </div>\n );\n }\n);\n\nMessageBubble.displayName = 'MessageBubble';\n\nexport {\n MessageBubble,\n MessageStatusIcon,\n ReadReceiptIndicator,\n AttachmentPreview,\n bubbleVariants,\n formatFileSize,\n};\n","import * as React from 'react';\nimport { cn } from '../../utils/cn';\nimport type {\n Message,\n MessageGroup,\n MessageParticipant,\n MessageAttachment,\n TypingState,\n} from './types';\nimport { MessageBubble } from './MessageBubble';\n\n// ============================================================================\n// Utility Functions\n// ============================================================================\n\n/**\n * Groups messages by date.\n */\nfunction groupMessagesByDate(messages: Message[]): MessageGroup[] {\n const groups: Map<string, Message[]> = new Map();\n\n messages.forEach((message) => {\n const date = new Date(message.timestamp);\n const dateKey = date.toDateString();\n const existing = groups.get(dateKey) || [];\n groups.set(dateKey, [...existing, message]);\n });\n\n return Array.from(groups.entries()).map(([dateKey, msgs]) => ({\n date: dateKey,\n label: formatDateLabel(new Date(dateKey)),\n messages: msgs,\n }));\n}\n\n/**\n * Format date label for message grouping.\n */\nfunction formatDateLabel(date: Date): string {\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n const messageDate = new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate()\n );\n\n if (messageDate.getTime() === today.getTime()) {\n return 'Today';\n }\n if (messageDate.getTime() === yesterday.getTime()) {\n return 'Yesterday';\n }\n\n // Check if same year\n if (date.getFullYear() === now.getFullYear()) {\n return date.toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n });\n }\n\n return date.toLocaleDateString(undefined, {\n weekday: 'long',\n month: 'long',\n day: 'numeric',\n year: 'numeric',\n });\n}\n\n/**\n * Check if two messages are from the same sender within a time threshold.\n */\nfunction isSameSenderGroup(\n prev: Message | undefined,\n current: Message,\n thresholdMinutes: number = 5\n): boolean {\n if (!prev) return false;\n if (prev.sender.id !== current.sender.id) return false;\n if (prev.type === 'system' || current.type === 'system') return false;\n\n const prevTime = new Date(prev.timestamp).getTime();\n const currentTime = new Date(current.timestamp).getTime();\n const diffMinutes = (currentTime - prevTime) / (1000 * 60);\n\n return diffMinutes < thresholdMinutes;\n}\n\n// ============================================================================\n// Skeleton Message Component\n// ============================================================================\n\nexport interface SkeletonMessageProps {\n isOutgoing?: boolean;\n showAvatar?: boolean;\n className?: string;\n}\n\n/**\n * A skeleton placeholder for loading messages.\n */\nfunction SkeletonMessage({\n isOutgoing = false,\n showAvatar = true,\n className,\n}: SkeletonMessageProps) {\n return (\n <div\n data-slot=\"skeleton-message\"\n className={cn(\n 'flex items-end gap-2',\n isOutgoing ? 'flex-row-reverse' : 'flex-row',\n className\n )}\n aria-hidden=\"true\"\n >\n {showAvatar && !isOutgoing && (\n <div\n data-slot=\"skeleton-avatar\"\n className=\"h-8 w-8 animate-pulse rounded-full bg-neutral-200 dark:bg-neutral-700\"\n />\n )}\n <div\n data-slot=\"skeleton-bubble\"\n className={cn(\n 'animate-pulse rounded-2xl',\n isOutgoing\n ? 'bg-primary-800/30 rounded-ee-md'\n : 'rounded-es-md bg-neutral-200 dark:bg-neutral-700',\n 'h-10 w-48'\n )}\n />\n {showAvatar && isOutgoing && (\n <div data-slot=\"skeleton-spacer\" className=\"w-8\" />\n )}\n </div>\n );\n}\n\nSkeletonMessage.displayName = 'SkeletonMessage';\n\n// ============================================================================\n// Typing Indicator Component\n// ============================================================================\n\nexport interface TypingIndicatorProps {\n typingState: TypingState;\n className?: string;\n}\n\n/**\n * Displays who is currently typing.\n */\nfunction TypingIndicator({ typingState, className }: TypingIndicatorProps) {\n const { participants } = typingState;\n\n if (participants.length === 0) return null;\n\n const typingText =\n participants.length === 1\n ? `${participants[0].name} is typing`\n : participants.length === 2\n ? `${participants[0].name} and ${participants[1].name} are typing`\n : `${participants[0].name} and ${participants.length - 1} others are typing`;\n\n return (\n <div\n data-slot=\"typing-indicator\"\n className={cn('flex items-center gap-2 px-4 py-2', className)}\n role=\"status\"\n aria-live=\"polite\"\n aria-label={typingText}\n >\n {/* Typing bubble animation */}\n <div className=\"flex items-center gap-1 rounded-2xl rounded-es-md bg-neutral-200 px-4 py-3 dark:bg-neutral-700\">\n <span\n className=\"h-2 w-2 animate-bounce rounded-full bg-neutral-500\"\n style={{ animationDelay: '0ms' }}\n />\n <span\n className=\"h-2 w-2 animate-bounce rounded-full bg-neutral-500\"\n style={{ animationDelay: '150ms' }}\n />\n <span\n className=\"h-2 w-2 animate-bounce rounded-full bg-neutral-500\"\n style={{ animationDelay: '300ms' }}\n />\n </div>\n <span className=\"text-muted-foreground text-xs\">{typingText}</span>\n </div>\n );\n}\n\nTypingIndicator.displayName = 'TypingIndicator';\n\n// ============================================================================\n// Date Separator Component\n// ============================================================================\n\nexport interface DateSeparatorProps {\n label: string;\n className?: string;\n}\n\n/**\n * A visual separator showing the date between message groups.\n */\nfunction DateSeparator({ label, className }: DateSeparatorProps) {\n return (\n <div\n data-slot=\"date-separator\"\n className={cn('flex items-center justify-center py-4', className)}\n role=\"separator\"\n aria-label={label}\n >\n <span\n className={cn(\n 'rounded-full px-3 py-1 text-xs font-medium',\n 'bg-neutral-100 text-neutral-600',\n 'dark:bg-neutral-800 dark:text-neutral-400'\n )}\n >\n {label}\n </span>\n </div>\n );\n}\n\nDateSeparator.displayName = 'DateSeparator';\n\n// ============================================================================\n// Empty State Component\n// ============================================================================\n\nexport interface EmptyStateProps {\n /** Custom title */\n title?: string;\n /** Custom description */\n description?: string;\n /** Custom icon */\n icon?: React.ReactNode;\n /** Action button */\n action?: React.ReactNode;\n className?: string;\n}\n\n/**\n * Empty state shown when there are no messages.\n */\nfunction EmptyState({\n title = 'No messages yet',\n description = 'Start the conversation by sending a message below.',\n icon,\n action,\n className,\n}: EmptyStateProps) {\n return (\n <div\n data-slot=\"message-empty-state\"\n className={cn(\n 'flex flex-1 flex-col items-center justify-center p-8 text-center',\n className\n )}\n role=\"status\"\n aria-label={title}\n >\n {icon || (\n <div\n data-slot=\"message-empty-state-icon\"\n className=\"mb-4 rounded-full bg-neutral-100 p-4 dark:bg-neutral-800\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-12 w-12 text-neutral-500\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={1.5}\n d=\"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z\"\n />\n </svg>\n </div>\n )}\n <h3 className=\"mb-2 text-lg font-semibold text-neutral-900 dark:text-neutral-100\">\n {title}\n </h3>\n <p className=\"text-muted-foreground mb-4 max-w-sm text-sm\">\n {description}\n </p>\n {action}\n </div>\n );\n}\n\nEmptyState.displayName = 'EmptyState';\n\n// ============================================================================\n// Load More Button Component\n// ============================================================================\n\nexport interface LoadMoreButtonProps {\n isLoading?: boolean;\n onClick: () => void;\n className?: string;\n}\n\n/**\n * Button to load more message history.\n */\nfunction LoadMoreButton({\n isLoading,\n onClick,\n className,\n}: LoadMoreButtonProps) {\n return (\n <div\n data-slot=\"load-more-button\"\n className={cn('flex justify-center py-4', className)}\n >\n <button\n type=\"button\"\n onClick={onClick}\n disabled={isLoading}\n className={cn(\n 'rounded-full px-4 py-2 text-sm font-medium',\n 'bg-neutral-100 text-neutral-600 dark:bg-neutral-800 dark:text-neutral-300',\n 'hover:bg-neutral-200 dark:hover:bg-neutral-700',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n 'disabled:cursor-not-allowed disabled:opacity-50',\n 'transition-colors'\n )}\n aria-label={isLoading ? 'Loading more messages' : 'Load more messages'}\n >\n {isLoading ? (\n <span className=\"flex items-center gap-2\">\n <svg\n aria-hidden=\"true\"\n className=\"h-4 w-4 animate-spin\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n >\n <circle\n className=\"opacity-25\"\n cx=\"12\"\n cy=\"12\"\n r=\"10\"\n stroke=\"currentColor\"\n strokeWidth=\"4\"\n />\n <path\n className=\"opacity-75\"\n fill=\"currentColor\"\n d=\"M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z\"\n />\n </svg>\n Loading...\n </span>\n ) : (\n 'Load earlier messages'\n )}\n </button>\n </div>\n );\n}\n\nLoadMoreButton.displayName = 'LoadMoreButton';\n\n// ============================================================================\n// Message List Component\n// ============================================================================\n\nexport interface MessageListProps {\n /** Array of messages to display */\n messages: Message[];\n /** Current user for determining outgoing messages */\n currentUser: MessageParticipant;\n /** Whether messages are loading */\n isLoading?: boolean;\n /** Whether more messages are available */\n hasMore?: boolean;\n /** Whether more messages are being loaded */\n isLoadingMore?: boolean;\n /** Typing indicator state */\n typingState?: TypingState;\n /** Show avatars for incoming messages */\n showAvatars?: boolean;\n /** Show sender names (for group conversations) */\n showSenderNames?: boolean;\n /** Group messages by date */\n groupByDate?: boolean;\n /** Callback when load more is triggered */\n onLoadMore?: () => void;\n /** Callback when a message action (retry) is triggered */\n onRetryMessage?: (messageId: string) => void;\n /** Callback when an attachment is clicked */\n onAttachmentClick?: (attachment: MessageAttachment, message: Message) => void;\n /** Custom empty state */\n emptyState?: React.ReactNode;\n /** Custom timestamp formatter */\n formatTimestamp?: (timestamp: Date | string) => string;\n /** Additional class name */\n className?: string;\n /** Auto-scroll behavior */\n autoScroll?: 'always' | 'onNewMessage' | 'manual';\n}\n\n/**\n * A scrollable list of messages with date grouping, auto-scroll, and loading states.\n *\n * @example\n * ```tsx\n * <MessageList\n * messages={messages}\n * currentUser={currentUser}\n * typingState={typingState}\n * onLoadMore={handleLoadMore}\n * showAvatars\n * groupByDate\n * />\n * ```\n */\nconst MessageList = React.forwardRef<HTMLDivElement, MessageListProps>(\n (\n {\n messages,\n currentUser,\n isLoading = false,\n hasMore = false,\n isLoadingMore = false,\n typingState,\n showAvatars = true,\n showSenderNames = false,\n groupByDate = true,\n onLoadMore,\n onRetryMessage,\n onAttachmentClick,\n emptyState,\n formatTimestamp,\n className,\n autoScroll = 'onNewMessage',\n },\n ref\n ) => {\n const scrollContainerRef = React.useRef<HTMLDivElement>(null);\n const bottomRef = React.useRef<HTMLDivElement>(null);\n const [isUserScrolled, setIsUserScrolled] = React.useState(false);\n const prevMessageCountRef = React.useRef(messages.length);\n\n // Combine refs\n React.useImperativeHandle(ref, () => scrollContainerRef.current!);\n\n // Handle scroll to detect if user has scrolled up\n const handleScroll = React.useCallback(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const { scrollTop, scrollHeight, clientHeight } = container;\n const isAtBottom = scrollHeight - scrollTop - clientHeight < 100;\n setIsUserScrolled(!isAtBottom);\n }, []);\n\n // Auto-scroll on new messages\n React.useEffect(() => {\n const container = scrollContainerRef.current;\n const bottom = bottomRef.current;\n if (!container || !bottom) return;\n\n const messageCountChanged =\n messages.length !== prevMessageCountRef.current;\n prevMessageCountRef.current = messages.length;\n\n if (autoScroll === 'always') {\n bottom.scrollIntoView({ behavior: 'smooth' });\n } else if (autoScroll === 'onNewMessage' && messageCountChanged) {\n // Check if new message is from current user (outgoing)\n const lastMessage = messages[messages.length - 1];\n const isOutgoing = lastMessage?.sender.id === currentUser.id;\n\n // Always scroll on outgoing, only scroll on incoming if at bottom\n if (isOutgoing || !isUserScrolled) {\n bottom.scrollIntoView({ behavior: 'smooth' });\n }\n }\n }, [messages, currentUser.id, autoScroll, isUserScrolled]);\n\n // Scroll to bottom on initial load\n React.useEffect(() => {\n const bottom = bottomRef.current;\n if (bottom && !isLoading) {\n bottom.scrollIntoView();\n }\n }, [isLoading]);\n\n // Group messages\n const messageGroups = groupByDate\n ? groupMessagesByDate(messages)\n : [{ date: 'all', label: '', messages }];\n\n // Loading skeleton\n if (isLoading) {\n return (\n <div\n role=\"status\"\n className={cn(\n 'flex flex-1 flex-col gap-3 overflow-y-auto p-4',\n className\n )}\n aria-busy=\"true\"\n aria-label=\"Loading messages\"\n >\n {Array.from({ length: 8 }).map((_, i) => (\n <SkeletonMessage\n key={i}\n isOutgoing={i % 3 === 0}\n showAvatar={showAvatars}\n />\n ))}\n </div>\n );\n }\n\n // Empty state\n if (messages.length === 0) {\n return emptyState || <EmptyState />;\n }\n\n return (\n <div\n ref={scrollContainerRef}\n data-slot=\"message-list\"\n className={cn(\n 'flex flex-1 flex-col overflow-y-auto',\n 'scroll-smooth',\n className\n )}\n onScroll={handleScroll}\n role=\"log\"\n aria-label=\"Message history\"\n aria-live=\"polite\"\n >\n {/* Load more button */}\n {hasMore && onLoadMore && (\n <LoadMoreButton isLoading={isLoadingMore} onClick={onLoadMore} />\n )}\n\n {/* Messages grouped by date */}\n <div\n data-slot=\"message-list-content\"\n className=\"flex flex-col gap-1 p-4\"\n >\n {messageGroups.map((group) => (\n <React.Fragment key={group.date}>\n {/* Date separator */}\n {groupByDate && group.label && (\n <DateSeparator label={group.label} />\n )}\n\n {/* Messages in group */}\n {group.messages.map((message, index) => {\n const prevMessage = group.messages[index - 1];\n const isOutgoing = message.sender.id === currentUser.id;\n const isSameGroup = isSameSenderGroup(prevMessage, message);\n\n return (\n <div\n key={message.id}\n className={cn(\n 'transition-opacity duration-200',\n isSameGroup ? 'mt-0.5' : 'mt-3',\n index === 0 && 'mt-0'\n )}\n >\n <MessageBubble\n message={message}\n isOutgoing={isOutgoing}\n showAvatar={showAvatars && !isSameGroup && !isOutgoing}\n showSenderName={\n showSenderNames && !isSameGroup && !isOutgoing\n }\n showTimestamp={!isSameGroup}\n onRetry={\n message.status === 'failed' && onRetryMessage\n ? () => onRetryMessage(message.id)\n : undefined\n }\n onAttachmentClick={(attachment) =>\n onAttachmentClick?.(attachment, message)\n }\n formatTimestamp={formatTimestamp}\n />\n </div>\n );\n })}\n </React.Fragment>\n ))}\n </div>\n\n {/* Typing indicator */}\n {typingState && typingState.participants.length > 0 && (\n <TypingIndicator typingState={typingState} />\n )}\n\n {/* Scroll anchor */}\n <div ref={bottomRef} className=\"h-0\" aria-hidden=\"true\" />\n\n {/* Scroll to bottom button when user has scrolled up */}\n {isUserScrolled && (\n <button\n type=\"button\"\n onClick={() => {\n bottomRef.current?.scrollIntoView({ behavior: 'smooth' });\n }}\n className={cn(\n 'fixed end-4 bottom-24 z-10',\n 'rounded-full p-3 shadow-lg',\n 'bg-white dark:bg-neutral-800',\n 'border border-neutral-200 dark:border-neutral-700',\n 'hover:bg-neutral-50 dark:hover:bg-neutral-700',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n 'transition-all'\n )}\n aria-label=\"Scroll to bottom\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-5 w-5 text-neutral-600 dark:text-neutral-300\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M19 14l-7 7m0 0l-7-7m7 7V3\"\n />\n </svg>\n </button>\n )}\n </div>\n );\n }\n);\n\nMessageList.displayName = 'MessageList';\n\nexport {\n MessageList,\n SkeletonMessage,\n TypingIndicator,\n DateSeparator,\n EmptyState,\n LoadMoreButton,\n groupMessagesByDate,\n formatDateLabel,\n isSameSenderGroup,\n};\n","import * as React from 'react';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport { cn } from '../../utils/cn';\nimport type { Conversation, MessageParticipant } from './types';\n\n// ============================================================================\n// Conversation Header Component\n// ============================================================================\n\nconst headerVariants = cva(\n [\n 'flex items-center gap-3 px-4 py-3',\n 'bg-white dark:bg-neutral-900',\n 'border-b border-neutral-200 dark:border-neutral-700',\n ],\n {\n variants: {\n size: {\n sm: 'py-2',\n md: 'py-3',\n lg: 'py-4',\n },\n },\n defaultVariants: {\n size: 'md',\n },\n }\n);\n\nexport interface ConversationHeaderProps\n extends\n React.HTMLAttributes<HTMLElement>,\n VariantProps<typeof headerVariants> {\n /** The conversation to display */\n conversation?: Conversation;\n /** Custom title (overrides conversation name) */\n title?: string;\n /** Custom subtitle */\n subtitle?: string;\n /** Avatar URL */\n avatarUrl?: string;\n /** Participant for direct messages */\n participant?: MessageParticipant;\n /** Show online status indicator */\n showOnlineStatus?: boolean;\n /** Show back button (mobile) */\n showBackButton?: boolean;\n /** Called when back button is clicked */\n onBack?: () => void;\n /** Additional actions (menu, call, etc.) */\n actions?: React.ReactNode;\n /** Custom left content */\n leftContent?: React.ReactNode;\n /** Custom right content */\n rightContent?: React.ReactNode;\n}\n\n/**\n * Get display title for a conversation.\n */\nfunction getConversationTitle(\n conversation?: Conversation,\n participant?: MessageParticipant\n): string {\n if (conversation?.name) return conversation.name;\n if (participant?.name) return participant.name;\n if (conversation?.participants && conversation.participants.length > 0) {\n const names = conversation.participants\n .filter((p) => !p.isCurrentUser)\n .map((p) => p.name);\n if (names.length <= 2) return names.join(' & ');\n return `${names[0]} and ${names.length - 1} others`;\n }\n return 'Conversation';\n}\n\n/**\n * Get subtitle for a conversation.\n */\nfunction getConversationSubtitle(\n conversation?: Conversation,\n participant?: MessageParticipant,\n showOnlineStatus?: boolean\n): string | undefined {\n if (participant) {\n if (showOnlineStatus && participant.isOnline) {\n return 'Online';\n }\n if (participant.lastSeen) {\n const lastSeen = new Date(participant.lastSeen);\n return `Last seen ${formatLastSeen(lastSeen)}`;\n }\n if (participant.phoneNumber) {\n return participant.phoneNumber;\n }\n }\n if (conversation?.type === 'group' && conversation.participants) {\n return `${conversation.participants.length} participants`;\n }\n return undefined;\n}\n\n/**\n * Format last seen time.\n */\nfunction formatLastSeen(date: Date): string {\n const now = new Date();\n const diffMs = now.getTime() - date.getTime();\n const diffMins = Math.floor(diffMs / (1000 * 60));\n const diffHours = Math.floor(diffMs / (1000 * 60 * 60));\n const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));\n\n if (diffMins < 1) return 'just now';\n if (diffMins < 60) return `${diffMins}m ago`;\n if (diffHours < 24) return `${diffHours}h ago`;\n if (diffDays < 7) return `${diffDays}d ago`;\n return date.toLocaleDateString();\n}\n\n/**\n * Header component for a conversation/message thread.\n *\n * @example\n * ```tsx\n * <ConversationHeader\n * conversation={conversation}\n * showBackButton\n * onBack={() => navigate('/conversations')}\n * actions={<IconButton icon={<MoreIcon />} />}\n * />\n * ```\n */\nconst ConversationHeader = React.forwardRef<\n HTMLElement,\n ConversationHeaderProps\n>(\n (\n {\n className,\n size,\n conversation,\n title,\n subtitle,\n avatarUrl,\n participant,\n showOnlineStatus = true,\n showBackButton = false,\n onBack,\n actions,\n leftContent,\n rightContent,\n ...props\n },\n ref\n ) => {\n const displayTitle =\n title || getConversationTitle(conversation, participant);\n const displaySubtitle =\n subtitle ||\n getConversationSubtitle(conversation, participant, showOnlineStatus);\n const displayAvatar =\n avatarUrl || conversation?.avatarUrl || participant?.avatarUrl;\n const isOnline = participant?.isOnline;\n\n return (\n <header\n ref={ref}\n data-slot=\"conversation-header\"\n className={cn(headerVariants({ size }), className)}\n {...props}\n >\n {/* Left content / Back button */}\n {leftContent ||\n (showBackButton && onBack && (\n <button\n type=\"button\"\n onClick={onBack}\n className={cn(\n '-ms-2 rounded-full p-2',\n 'text-neutral-500 hover:text-neutral-700',\n 'dark:text-neutral-400 dark:hover:text-neutral-200',\n 'hover:bg-neutral-100 dark:hover:bg-neutral-800',\n 'focus:ring-primary-500 focus:ring-2 focus:outline-none',\n 'transition-colors'\n )}\n aria-label=\"Go back\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-5 w-5\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M15 19l-7-7 7-7\"\n />\n </svg>\n </button>\n ))}\n\n {/* Avatar */}\n <div\n data-slot=\"conversation-header-avatar\"\n className=\"relative shrink-0\"\n >\n <div\n className={cn(\n 'flex h-10 w-10 items-center justify-center rounded-full',\n 'bg-primary-800 font-medium text-white'\n )}\n >\n {displayAvatar ? (\n <img\n src={displayAvatar}\n alt={displayTitle}\n className=\"h-full w-full rounded-full object-cover\"\n />\n ) : (\n displayTitle.charAt(0).toUpperCase()\n )}\n </div>\n {/* Online indicator */}\n {showOnlineStatus && isOnline && (\n <span\n className={cn(\n 'absolute end-0 bottom-0',\n 'h-3 w-3 rounded-full',\n 'bg-green-500 ring-2 ring-white dark:ring-neutral-900'\n )}\n role=\"status\"\n aria-label=\"Online\"\n />\n )}\n </div>\n\n {/* Title and subtitle */}\n <div data-slot=\"conversation-header-info\" className=\"min-w-0 flex-1\">\n <h2 className=\"truncate font-semibold text-neutral-900 dark:text-neutral-100\">\n {displayTitle}\n </h2>\n {displaySubtitle && (\n <p\n className={cn(\n 'truncate text-sm',\n isOnline\n ? 'text-green-700 dark:text-green-400'\n : 'text-muted-foreground'\n )}\n >\n {displaySubtitle}\n </p>\n )}\n </div>\n\n {/* Right content / Actions */}\n {rightContent ||\n (actions && (\n <div className=\"flex shrink-0 items-center gap-1\">{actions}</div>\n ))}\n </header>\n );\n }\n);\n\nConversationHeader.displayName = 'ConversationHeader';\n\n// ============================================================================\n// Conversation List Item Component\n// ============================================================================\n\nexport interface ConversationListItemProps extends Omit<\n React.HTMLAttributes<HTMLButtonElement>,\n 'onSelect'\n> {\n /** The conversation to display */\n conversation: Conversation;\n /** Whether this item is selected */\n isSelected?: boolean;\n /** Called when the item is clicked */\n onSelect?: (conversation: Conversation) => void;\n}\n\n/**\n * A list item for displaying a conversation in a list.\n */\nconst ConversationListItem = React.forwardRef<\n HTMLButtonElement,\n ConversationListItemProps\n>(({ className, conversation, isSelected, onSelect, ...props }, ref) => {\n const participant = conversation.participants.find((p) => !p.isCurrentUser);\n const title = getConversationTitle(conversation, participant);\n const avatarUrl = conversation.avatarUrl || participant?.avatarUrl;\n const lastMessage = conversation.lastMessage;\n const isUnread = conversation.unreadCount > 0;\n\n const formatTime = (timestamp: Date | string) => {\n const date = new Date(timestamp);\n const now = new Date();\n const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\n const messageDate = new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate()\n );\n\n if (messageDate.getTime() === today.getTime()) {\n return date.toLocaleTimeString(undefined, {\n hour: 'numeric',\n minute: '2-digit',\n });\n }\n\n const yesterday = new Date(today);\n yesterday.setDate(yesterday.getDate() - 1);\n if (messageDate.getTime() === yesterday.getTime()) {\n return 'Yesterday';\n }\n\n return date.toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n });\n };\n\n return (\n <button\n ref={ref}\n type=\"button\"\n onClick={() => onSelect?.(conversation)}\n data-slot=\"conversation-list-item\"\n className={cn(\n 'flex w-full items-center gap-3 px-4 py-3',\n 'text-start transition-colors',\n isSelected\n ? 'bg-primary-50 dark:bg-primary-900/20'\n : 'hover:bg-neutral-50 dark:hover:bg-neutral-800/50',\n 'focus:bg-neutral-50 focus:outline-none dark:focus:bg-neutral-800/50',\n className\n )}\n aria-current={isSelected ? 'true' : undefined}\n {...props}\n >\n {/* Avatar */}\n <div\n data-slot=\"conversation-list-item-avatar\"\n className=\"relative shrink-0\"\n >\n <div\n className={cn(\n 'flex h-12 w-12 items-center justify-center rounded-full',\n 'bg-primary-800 font-medium text-white'\n )}\n >\n {avatarUrl ? (\n <img\n src={avatarUrl}\n alt={title}\n className=\"h-full w-full rounded-full object-cover\"\n />\n ) : (\n title.charAt(0).toUpperCase()\n )}\n </div>\n {participant?.isOnline && (\n <span\n className={cn(\n 'absolute end-0 bottom-0',\n 'h-3 w-3 rounded-full',\n 'bg-green-500 ring-2 ring-white dark:ring-neutral-900'\n )}\n />\n )}\n </div>\n\n {/* Content */}\n <div\n data-slot=\"conversation-list-item-content\"\n className=\"min-w-0 flex-1\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <h3\n className={cn(\n 'truncate text-sm',\n isUnread\n ? 'font-semibold text-neutral-900 dark:text-neutral-100'\n : 'font-medium text-neutral-700 dark:text-neutral-300'\n )}\n >\n {title}\n </h3>\n {lastMessage && (\n <span className=\"shrink-0 text-xs text-neutral-600 dark:text-neutral-400\">\n {formatTime(lastMessage.timestamp)}\n </span>\n )}\n </div>\n <div className=\"flex items-center justify-between gap-2\">\n <p\n className={cn(\n 'truncate text-sm',\n isUnread\n ? 'text-neutral-700 dark:text-neutral-300'\n : 'text-neutral-600 dark:text-neutral-400'\n )}\n >\n {lastMessage?.content || 'No messages yet'}\n </p>\n {isUnread && (\n <span\n data-slot=\"conversation-list-item-badge\"\n className={cn(\n 'flex shrink-0 items-center justify-center',\n 'h-5 min-w-[20px] rounded-full px-1.5',\n 'bg-primary-800 text-xs font-medium text-white'\n )}\n >\n {conversation.unreadCount > 99 ? '99+' : conversation.unreadCount}\n </span>\n )}\n </div>\n </div>\n\n {/* Pinned/Muted indicators */}\n <div className=\"flex shrink-0 flex-col items-center gap-1\">\n {conversation.isPinned && (\n <svg\n aria-hidden=\"true\"\n className=\"text-primary-800 h-4 w-4\"\n fill=\"currentColor\"\n viewBox=\"0 0 24 24\"\n >\n <path d=\"M16 4v8l2 2v2h-6v6l-1 1-1-1v-6H4v-2l2-2V4c0-1.1.9-2 2-2h6c1.1 0 2 .9 2 2z\" />\n </svg>\n )}\n {conversation.isMuted && (\n <svg\n aria-hidden=\"true\"\n className=\"h-4 w-4 text-neutral-500\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M5.586 15H4a1 1 0 01-1-1v-4a1 1 0 011-1h1.586l4.707-4.707C10.923 3.663 12 4.109 12 5v14c0 .891-1.077 1.337-1.707.707L5.586 15z\"\n />\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M17 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2\"\n />\n </svg>\n )}\n </div>\n </button>\n );\n});\n\nConversationListItem.displayName = 'ConversationListItem';\n\n// ============================================================================\n// Conversation List Skeleton Component\n// ============================================================================\n\nexport interface ConversationListSkeletonProps {\n count?: number;\n className?: string;\n}\n\n/**\n * Skeleton loading state for conversation list.\n */\nfunction ConversationListSkeleton({\n count = 5,\n className,\n}: ConversationListSkeletonProps) {\n return (\n <div\n className={cn(\n 'divide-y divide-neutral-200 dark:divide-neutral-700',\n className\n )}\n >\n {Array.from({ length: count }).map((_, i) => (\n <div\n key={i}\n className=\"flex items-center gap-3 px-4 py-3\"\n aria-hidden=\"true\"\n >\n <div className=\"h-12 w-12 animate-pulse rounded-full bg-neutral-200 dark:bg-neutral-700\" />\n <div className=\"flex-1 space-y-2\">\n <div className=\"h-4 w-32 animate-pulse rounded bg-neutral-200 dark:bg-neutral-700\" />\n <div className=\"h-3 w-48 animate-pulse rounded bg-neutral-200 dark:bg-neutral-700\" />\n </div>\n </div>\n ))}\n </div>\n );\n}\n\nConversationListSkeleton.displayName = 'ConversationListSkeleton';\n\nexport {\n ConversationHeader,\n ConversationListItem,\n ConversationListSkeleton,\n headerVariants,\n getConversationTitle,\n getConversationSubtitle,\n formatLastSeen,\n};\n","import * as React from 'react';\nimport { cn } from '../../utils/cn';\nimport type {\n Message,\n MessageParticipant,\n MessageAttachment,\n TypingState,\n Conversation,\n NewMessage,\n MessagingEventHandlers,\n} from './types';\nimport { MessageList } from './MessageList';\nimport { MessageComposer } from './MessageComposer';\nimport { ConversationHeader } from './ConversationHeader';\nimport { DragDropZone } from './AttachmentPicker';\n\n// ============================================================================\n// Lightbox Modal Component\n// ============================================================================\n\nexport interface LightboxModalProps {\n /** The attachment to display */\n attachment: MessageAttachment | null;\n /** Called when the modal is closed */\n onClose: () => void;\n}\n\n/**\n * Full-screen lightbox for viewing media attachments.\n */\nfunction LightboxModal({ attachment, onClose }: LightboxModalProps) {\n // Handle escape key\n React.useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n onClose();\n }\n };\n\n if (attachment) {\n document.addEventListener('keydown', handleKeyDown);\n document.body.style.overflow = 'hidden';\n }\n\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n document.body.style.overflow = '';\n };\n }, [attachment, onClose]);\n\n if (!attachment) return null;\n\n const isImage = attachment.type === 'image';\n const isVideo = attachment.type === 'video';\n\n return (\n <div\n data-slot=\"message-lightbox\"\n className={cn('fixed inset-0 z-50', 'flex items-center justify-center')}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={`View ${attachment.filename}`}\n >\n {/* Backdrop - clickable to close */}\n <button\n type=\"button\"\n className=\"absolute inset-0 cursor-default bg-black/90\"\n onClick={onClose}\n aria-label=\"Close lightbox\"\n />\n\n {/* Close button */}\n <button\n type=\"button\"\n onClick={onClose}\n className={cn(\n 'absolute end-4 top-4 z-10',\n 'rounded-full p-2',\n 'bg-white/10 text-white',\n 'hover:bg-white/20',\n 'focus:ring-2 focus:ring-white focus:outline-none',\n 'transition-colors'\n )}\n aria-label=\"Close\"\n >\n <svg\n aria-hidden=\"true\"\n className=\"h-6 w-6\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n stroke=\"currentColor\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n strokeWidth={2}\n d=\"M6 18L18 6M6 6l12 12\"\n />\n </svg>\n </button>\n\n {/* Media content */}\n <div className=\"relative z-10 max-h-[90vh] max-w-[90vw]\">\n {isImage && (\n <img\n src={attachment.url}\n alt={attachment.alt || attachment.filename}\n className=\"max-h-[90vh] max-w-[90vw] object-contain\"\n />\n )}\n {isVideo && (\n <video\n src={attachment.url}\n controls\n autoPlay\n className=\"max-h-[90vh] max-w-[90vw]\"\n >\n <track kind=\"captions\" />\n </video>\n )}\n </div>\n\n {/* Filename */}\n <div className=\"absolute bottom-4 left-1/2 -translate-x-1/2\">\n <p className=\"rounded-full bg-black/50 px-4 py-2 text-sm text-white\">\n {attachment.filename}\n </p>\n </div>\n </div>\n );\n}\n\nLightboxModal.displayName = 'LightboxModal';\n\n// ============================================================================\n// Message Thread Component\n// ============================================================================\n\nexport interface MessageThreadProps {\n /** The conversation being displayed */\n conversation?: Conversation;\n /** Array of messages in the thread */\n messages: Message[];\n /** Current user for determining message direction */\n currentUser: MessageParticipant;\n /** Typing indicator state */\n typingState?: TypingState;\n /** Whether messages are loading */\n isLoading?: boolean;\n /** Whether more messages are available */\n hasMore?: boolean;\n /** Whether more messages are being loaded */\n isLoadingMore?: boolean;\n /** Whether a message is being sent */\n isSending?: boolean;\n /** Event handlers */\n eventHandlers?: MessagingEventHandlers;\n /** Show header */\n showHeader?: boolean;\n /** Show back button in header */\n showBackButton?: boolean;\n /** Called when back is clicked */\n onBack?: () => void;\n /** Custom header actions */\n headerActions?: React.ReactNode;\n /** Composer placeholder */\n placeholder?: string;\n /** Maximum message length */\n maxMessageLength?: number;\n /** Show character count */\n showCharacterCount?: boolean;\n /** Show attachment picker */\n showAttachmentPicker?: boolean;\n /** Show camera button */\n showCameraButton?: boolean;\n /** Accepted file types */\n acceptedFileTypes?: string[];\n /** Maximum file size */\n maxFileSize?: number;\n /** Maximum attachments */\n maxAttachments?: number;\n /** Show avatars in message list */\n showAvatars?: boolean;\n /** Show sender names (group chats) */\n showSenderNames?: boolean;\n /** Group messages by date */\n groupByDate?: boolean;\n /** Custom empty state */\n emptyState?: React.ReactNode;\n /** Custom timestamp formatter */\n formatTimestamp?: (timestamp: Date | string) => string;\n /** Called when an error occurs */\n onError?: (error: string) => void;\n /** Additional class name */\n className?: string;\n}\n\n/**\n * A complete message thread component combining header, message list, and composer.\n *\n * @example\n * ```tsx\n * <MessageThread\n * conversation={conversation}\n * messages={messages}\n * currentUser={currentUser}\n * typingState={typingState}\n * eventHandlers={{\n * onSendMessage: handleSend,\n * onLoadMore: handleLoadMore,\n * onRetryMessage: handleRetry,\n * }}\n * showHeader\n * showBackButton\n * onBack={() => navigate('/conversations')}\n * />\n * ```\n */\nconst MessageThread = React.forwardRef<HTMLDivElement, MessageThreadProps>(\n (\n {\n conversation,\n messages,\n currentUser,\n typingState,\n isLoading = false,\n hasMore = false,\n isLoadingMore = false,\n isSending = false,\n eventHandlers = {},\n showHeader = true,\n showBackButton = false,\n onBack,\n headerActions,\n placeholder = 'Type a message...',\n maxMessageLength = 1600,\n showCharacterCount = false,\n showAttachmentPicker = true,\n showCameraButton = false,\n acceptedFileTypes,\n maxFileSize,\n maxAttachments,\n showAvatars = true,\n showSenderNames = false,\n groupByDate = true,\n emptyState,\n formatTimestamp,\n onError,\n className,\n },\n ref\n ) => {\n const [lightboxAttachment, setLightboxAttachment] =\n React.useState<MessageAttachment | null>(null);\n const [replyTo, setReplyTo] = React.useState<{\n id: string;\n content: string;\n senderName: string;\n } | null>(null);\n\n // Get participant for direct messages\n const participant =\n conversation?.type === 'direct'\n ? conversation.participants.find((p) => p.id !== currentUser.id)\n : undefined;\n\n // Handle attachment click\n const handleAttachmentClick = (\n attachment: MessageAttachment,\n message: Message\n ) => {\n if (attachment.type === 'image' || attachment.type === 'video') {\n setLightboxAttachment(attachment);\n }\n eventHandlers.onAttachmentClick?.(attachment, message);\n };\n\n // Handle send message\n const handleSendMessage = async (newMessage: NewMessage) => {\n const messageWithReply: NewMessage = {\n ...newMessage,\n replyToId: replyTo?.id || newMessage.replyToId,\n };\n setReplyTo(null);\n await eventHandlers.onSendMessage?.(messageWithReply);\n };\n\n return (\n <div\n ref={ref}\n data-slot=\"message-thread\"\n className={cn(\n 'flex h-full flex-col',\n 'bg-white dark:bg-neutral-900',\n className\n )}\n >\n {/* Header */}\n {showHeader && (\n <ConversationHeader\n conversation={conversation}\n participant={participant}\n showBackButton={showBackButton}\n onBack={onBack}\n actions={headerActions}\n />\n )}\n\n {/* Message list */}\n <DragDropZone\n onFilesDropped={() => {\n // Could trigger composer with attachments\n onError?.('Drop files on the composer to attach them');\n }}\n disabled={!showAttachmentPicker}\n className=\"flex-1 overflow-hidden\"\n >\n <MessageList\n messages={messages}\n currentUser={currentUser}\n isLoading={isLoading}\n hasMore={hasMore}\n isLoadingMore={isLoadingMore}\n typingState={typingState}\n showAvatars={showAvatars}\n showSenderNames={showSenderNames}\n groupByDate={groupByDate}\n onLoadMore={eventHandlers.onLoadMore}\n onRetryMessage={eventHandlers.onRetryMessage}\n onAttachmentClick={handleAttachmentClick}\n emptyState={emptyState}\n formatTimestamp={formatTimestamp}\n className=\"h-full\"\n />\n </DragDropZone>\n\n {/* Composer */}\n <MessageComposer\n onSend={handleSendMessage}\n onTypingStart={eventHandlers.onTypingStart}\n onTypingStop={eventHandlers.onTypingStop}\n placeholder={placeholder}\n maxLength={maxMessageLength}\n showCharacterCount={showCharacterCount}\n isSending={isSending}\n showAttachmentPicker={showAttachmentPicker}\n showCameraButton={showCameraButton}\n acceptedFileTypes={acceptedFileTypes}\n maxFileSize={maxFileSize}\n maxAttachments={maxAttachments}\n onError={onError}\n replyTo={replyTo}\n onCancelReply={() => setReplyTo(null)}\n />\n\n {/* Lightbox */}\n <LightboxModal\n attachment={lightboxAttachment}\n onClose={() => setLightboxAttachment(null)}\n />\n </div>\n );\n }\n);\n\nMessageThread.displayName = 'MessageThread';\n\n// ============================================================================\n// Split View Container Component\n// ============================================================================\n\nexport interface MessagingSplitViewProps {\n /** Conversation list content */\n conversationList: React.ReactNode;\n /** Message thread content */\n messageThread: React.ReactNode;\n /** Whether a conversation is selected */\n hasSelectedConversation?: boolean;\n /** Width of the conversation list on desktop */\n listWidth?: string | number;\n /** Breakpoint for mobile view */\n mobileBreakpoint?: 'sm' | 'md' | 'lg';\n /** Additional class name */\n className?: string;\n}\n\n/**\n * Split view container for desktop with responsive mobile behavior.\n *\n * @example\n * ```tsx\n * <MessagingSplitView\n * conversationList={<ConversationList />}\n * messageThread={<MessageThread />}\n * hasSelectedConversation={!!selectedConversation}\n * />\n * ```\n */\nfunction MessagingSplitView({\n conversationList,\n messageThread,\n hasSelectedConversation = false,\n listWidth = 320,\n mobileBreakpoint = 'md',\n className,\n}: MessagingSplitViewProps) {\n const breakpointClasses = {\n sm: 'sm:flex',\n md: 'md:flex',\n lg: 'lg:flex',\n };\n\n const hideMobileClasses = {\n sm: hasSelectedConversation ? 'hidden sm:block' : 'block sm:block',\n md: hasSelectedConversation ? 'hidden md:block' : 'block md:block',\n lg: hasSelectedConversation ? 'hidden lg:block' : 'block lg:block',\n };\n\n const showMobileClasses = {\n sm: hasSelectedConversation ? 'block sm:block' : 'hidden sm:block',\n md: hasSelectedConversation ? 'block md:block' : 'hidden md:block',\n lg: hasSelectedConversation ? 'block lg:block' : 'hidden lg:block',\n };\n\n return (\n <div\n data-slot=\"messaging-split-view\"\n className={cn(\n 'h-full w-full',\n breakpointClasses[mobileBreakpoint],\n className\n )}\n >\n {/* Conversation list */}\n <div\n data-slot=\"messaging-list-pane\"\n className={cn(\n 'h-full w-full flex-shrink-0',\n 'border-e border-neutral-200 dark:border-neutral-700',\n hideMobileClasses[mobileBreakpoint]\n )}\n style={{\n width: typeof listWidth === 'number' ? `${listWidth}px` : listWidth,\n }}\n >\n {conversationList}\n </div>\n\n {/* Message thread */}\n <div\n data-slot=\"messaging-thread-pane\"\n className={cn(\n 'h-full min-w-0 flex-1',\n showMobileClasses[mobileBreakpoint]\n )}\n >\n {messageThread}\n </div>\n </div>\n );\n}\n\nMessagingSplitView.displayName = 'MessagingSplitView';\n\nexport { MessageThread, LightboxModal, MessagingSplitView };\n","import * as React from 'react';\nimport type {\n Message,\n MessageParticipant,\n MessageStatus,\n TypingState,\n NewMessage,\n} from './types';\n\n// ============================================================================\n// useMessages Hook\n// ============================================================================\n\nexport interface UseMessagesOptions {\n /** Initial messages */\n initialMessages?: Message[];\n /** Current user */\n currentUser: MessageParticipant;\n /** Called when a message is sent */\n onSend?: (message: NewMessage) => Promise<Message>;\n /** Called when a message is retried */\n onRetry?: (messageId: string) => Promise<void>;\n /** Called when messages need to be loaded */\n onLoadMore?: () => Promise<Message[]>;\n}\n\nexport interface UseMessagesReturn {\n /** Current messages */\n messages: Message[];\n /** Add a new message (from external source) */\n addMessage: (message: Message) => void;\n /** Update a message */\n updateMessage: (messageId: string, updates: Partial<Message>) => void;\n /** Remove a message */\n removeMessage: (messageId: string) => void;\n /** Send a new message */\n sendMessage: (content: NewMessage) => Promise<void>;\n /** Retry a failed message */\n retryMessage: (messageId: string) => Promise<void>;\n /** Load more messages */\n loadMore: () => Promise<void>;\n /** Whether sending is in progress */\n isSending: boolean;\n /** Whether loading more is in progress */\n isLoadingMore: boolean;\n /** Mark a message as read */\n markAsRead: (messageId: string) => void;\n /** Update message status */\n updateStatus: (messageId: string, status: MessageStatus) => void;\n}\n\n/**\n * Hook for managing message state with optimistic updates.\n *\n * @example\n * ```tsx\n * const {\n * messages,\n * sendMessage,\n * isSending,\n * } = useMessages({\n * currentUser,\n * onSend: async (msg) => await api.sendMessage(msg),\n * });\n * ```\n */\nexport function useMessages(options: UseMessagesOptions): UseMessagesReturn {\n const {\n initialMessages = [],\n currentUser,\n onSend,\n onRetry,\n onLoadMore,\n } = options;\n\n const [messages, setMessages] = React.useState<Message[]>(initialMessages);\n const [isSending, setIsSending] = React.useState(false);\n const [isLoadingMore, setIsLoadingMore] = React.useState(false);\n\n // Update messages when initialMessages changes\n React.useEffect(() => {\n setMessages(initialMessages);\n }, [initialMessages]);\n\n const addMessage = React.useCallback((message: Message) => {\n setMessages((prev) => {\n // Avoid duplicates\n if (prev.some((m) => m.id === message.id)) {\n return prev;\n }\n return [...prev, message];\n });\n }, []);\n\n const updateMessage = React.useCallback(\n (messageId: string, updates: Partial<Message>) => {\n setMessages((prev) =>\n prev.map((m) => (m.id === messageId ? { ...m, ...updates } : m))\n );\n },\n []\n );\n\n const removeMessage = React.useCallback((messageId: string) => {\n setMessages((prev) => prev.filter((m) => m.id !== messageId));\n }, []);\n\n const updateStatus = React.useCallback(\n (messageId: string, status: MessageStatus) => {\n updateMessage(messageId, { status });\n },\n [updateMessage]\n );\n\n const markAsRead = React.useCallback(\n (messageId: string) => {\n updateStatus(messageId, 'read');\n },\n [updateStatus]\n );\n\n const sendMessage = React.useCallback(\n async (newMessage: NewMessage) => {\n // Create optimistic message\n const optimisticId = `optimistic-${Date.now()}`;\n const optimisticMessage: Message = {\n id: optimisticId,\n type: 'text',\n content: newMessage.content,\n sender: currentUser,\n timestamp: new Date(),\n status: 'sending',\n attachments: [], // Would handle attachment uploads here\n };\n\n // Add optimistic message\n addMessage(optimisticMessage);\n setIsSending(true);\n\n try {\n if (onSend) {\n const sentMessage = await onSend(newMessage);\n // Replace optimistic message with real one\n setMessages((prev) =>\n prev.map((m) => (m.id === optimisticId ? sentMessage : m))\n );\n } else {\n // No send handler, just mark as sent\n updateStatus(optimisticId, 'sent');\n }\n } catch {\n // Mark as failed\n updateStatus(optimisticId, 'failed');\n } finally {\n setIsSending(false);\n }\n },\n [currentUser, onSend, addMessage, updateStatus]\n );\n\n const retryMessage = React.useCallback(\n async (messageId: string) => {\n updateStatus(messageId, 'sending');\n\n try {\n if (onRetry) {\n await onRetry(messageId);\n updateStatus(messageId, 'sent');\n }\n } catch {\n updateStatus(messageId, 'failed');\n }\n },\n [onRetry, updateStatus]\n );\n\n const loadMore = React.useCallback(async () => {\n if (isLoadingMore || !onLoadMore) return;\n\n setIsLoadingMore(true);\n try {\n const olderMessages = await onLoadMore();\n setMessages((prev) => [...olderMessages, ...prev]);\n } finally {\n setIsLoadingMore(false);\n }\n }, [isLoadingMore, onLoadMore]);\n\n return {\n messages,\n addMessage,\n updateMessage,\n removeMessage,\n sendMessage,\n retryMessage,\n loadMore,\n isSending,\n isLoadingMore,\n markAsRead,\n updateStatus,\n };\n}\n\n// ============================================================================\n// useTypingIndicator Hook\n// ============================================================================\n\nexport interface UseTypingIndicatorOptions {\n /** Current typing participants (from server) */\n typingParticipants?: MessageParticipant[];\n /** Debounce time for typing stop (ms) */\n debounceTime?: number;\n /** Called when local user starts typing */\n onTypingStart?: () => void;\n /** Called when local user stops typing */\n onTypingStop?: () => void;\n}\n\nexport interface UseTypingIndicatorReturn {\n /** Current typing state */\n typingState: TypingState;\n /** Signal that local user is typing */\n startTyping: () => void;\n /** Signal that local user stopped typing */\n stopTyping: () => void;\n /** Update remote typing participants */\n setTypingParticipants: (participants: MessageParticipant[]) => void;\n}\n\n/**\n * Hook for managing typing indicator state.\n *\n * @example\n * ```tsx\n * const { typingState, startTyping, stopTyping } = useTypingIndicator({\n * onTypingStart: () => socket.emit('typing', true),\n * onTypingStop: () => socket.emit('typing', false),\n * });\n * ```\n */\nexport function useTypingIndicator(\n options: UseTypingIndicatorOptions = {}\n): UseTypingIndicatorReturn {\n const {\n typingParticipants: initialParticipants = [],\n debounceTime = 2000,\n onTypingStart,\n onTypingStop,\n } = options;\n\n const [participants, setParticipants] =\n React.useState<MessageParticipant[]>(initialParticipants);\n const [isLocalTyping, setIsLocalTyping] = React.useState(false);\n const typingTimeoutRef = React.useRef<NodeJS.Timeout | null>(null);\n\n // Update from props\n React.useEffect(() => {\n setParticipants(initialParticipants);\n }, [initialParticipants]);\n\n const startTyping = React.useCallback(() => {\n if (!isLocalTyping) {\n setIsLocalTyping(true);\n onTypingStart?.();\n }\n\n // Reset timeout\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n\n typingTimeoutRef.current = setTimeout(() => {\n setIsLocalTyping(false);\n onTypingStop?.();\n }, debounceTime);\n }, [isLocalTyping, debounceTime, onTypingStart, onTypingStop]);\n\n const stopTyping = React.useCallback(() => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n setIsLocalTyping(false);\n onTypingStop?.();\n }, [onTypingStop]);\n\n // Cleanup on unmount\n React.useEffect(() => {\n return () => {\n if (typingTimeoutRef.current) {\n clearTimeout(typingTimeoutRef.current);\n }\n };\n }, []);\n\n const typingState: TypingState = React.useMemo(\n () => ({\n participants,\n lastUpdated: new Date(),\n }),\n [participants]\n );\n\n return {\n typingState,\n startTyping,\n stopTyping,\n setTypingParticipants: setParticipants,\n };\n}\n\n// ============================================================================\n// useMessageScroll Hook\n// ============================================================================\n\nexport interface UseMessageScrollOptions {\n /** Messages to watch for changes */\n messages: Message[];\n /** Current user ID */\n currentUserId: string;\n /** Threshold from bottom to consider \"at bottom\" (px) */\n threshold?: number;\n}\n\nexport interface UseMessageScrollReturn {\n /** Ref to attach to scroll container */\n scrollContainerRef: React.RefObject<HTMLDivElement | null>;\n /** Ref to attach to bottom anchor element */\n bottomRef: React.RefObject<HTMLDivElement | null>;\n /** Whether user has scrolled up from bottom */\n isScrolledUp: boolean;\n /** Scroll to bottom */\n scrollToBottom: (smooth?: boolean) => void;\n}\n\n/**\n * Hook for managing message list scroll behavior.\n *\n * @example\n * ```tsx\n * const { scrollContainerRef, bottomRef, isScrolledUp, scrollToBottom } =\n * useMessageScroll({ messages, currentUserId: user.id });\n * ```\n */\nexport function useMessageScroll(\n options: UseMessageScrollOptions\n): UseMessageScrollReturn {\n const { messages, currentUserId, threshold = 100 } = options;\n\n const scrollContainerRef = React.useRef<HTMLDivElement>(null);\n const bottomRef = React.useRef<HTMLDivElement>(null);\n const [isScrolledUp, setIsScrolledUp] = React.useState(false);\n const prevMessageCountRef = React.useRef(messages.length);\n\n // Handle scroll events\n React.useEffect(() => {\n const container = scrollContainerRef.current;\n if (!container) return;\n\n const handleScroll = () => {\n const { scrollTop, scrollHeight, clientHeight } = container;\n const isAtBottom = scrollHeight - scrollTop - clientHeight < threshold;\n setIsScrolledUp(!isAtBottom);\n };\n\n container.addEventListener('scroll', handleScroll);\n return () => container.removeEventListener('scroll', handleScroll);\n }, [threshold]);\n\n const scrollToBottom = React.useCallback((smooth = true) => {\n bottomRef.current?.scrollIntoView({\n behavior: smooth ? 'smooth' : 'auto',\n });\n }, []);\n\n // Auto-scroll on new messages\n React.useEffect(() => {\n const messageCountChanged = messages.length !== prevMessageCountRef.current;\n prevMessageCountRef.current = messages.length;\n\n if (!messageCountChanged) return;\n\n const lastMessage = messages[messages.length - 1];\n const isOutgoing = lastMessage?.sender.id === currentUserId;\n\n // Always scroll on outgoing, only scroll on incoming if at bottom\n if (isOutgoing || !isScrolledUp) {\n scrollToBottom(true);\n }\n }, [messages, currentUserId, isScrolledUp, scrollToBottom]);\n\n return {\n scrollContainerRef,\n bottomRef,\n isScrolledUp,\n scrollToBottom,\n };\n}\n\n// ============================================================================\n// useReadReceipts Hook\n// ============================================================================\n\nexport interface UseReadReceiptsOptions {\n /** Messages to track */\n messages: Message[];\n /** Current user ID */\n currentUserId: string;\n /** Called when a message should be marked as read */\n onMarkRead?: (messageId: string) => void;\n /** IntersectionObserver threshold */\n threshold?: number;\n}\n\n/**\n * Hook for automatically marking messages as read when visible.\n *\n * @example\n * ```tsx\n * const { observeMessage } = useReadReceipts({\n * messages,\n * currentUserId: user.id,\n * onMarkRead: (id) => socket.emit('read', id),\n * });\n * ```\n */\nexport function useReadReceipts(options: UseReadReceiptsOptions) {\n const { currentUserId, onMarkRead, threshold = 0.5 } = options;\n\n const observerRef = React.useRef<IntersectionObserver | null>(null);\n const observedMessagesRef = React.useRef<Set<string>>(new Set());\n\n React.useEffect(() => {\n observerRef.current = new IntersectionObserver(\n (entries) => {\n entries.forEach((entry) => {\n if (entry.isIntersecting) {\n const messageId = entry.target.getAttribute('data-message-id');\n if (messageId && !observedMessagesRef.current.has(messageId)) {\n observedMessagesRef.current.add(messageId);\n onMarkRead?.(messageId);\n }\n }\n });\n },\n { threshold }\n );\n\n return () => {\n observerRef.current?.disconnect();\n };\n }, [onMarkRead, threshold]);\n\n const observeMessage = React.useCallback(\n (element: HTMLElement | null, message: Message) => {\n if (!element || !observerRef.current) return;\n\n // Only observe unread incoming messages\n if (\n message.sender.id !== currentUserId &&\n message.status !== 'read' &&\n !observedMessagesRef.current.has(message.id)\n ) {\n element.setAttribute('data-message-id', message.id);\n observerRef.current.observe(element);\n }\n },\n [currentUserId]\n );\n\n return { observeMessage };\n}\n"]}
|
package/dist/chunk-WYMO3IIK.js
DELETED
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import { cn } from './chunk-TQONQSJO.js';
|
|
2
|
-
import * as React from 'react';
|
|
3
|
-
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
4
|
-
|
|
5
|
-
// src/motion/presets.ts
|
|
6
|
-
var motionPresets = {
|
|
7
|
-
/**
|
|
8
|
-
* Off-canvas panel pinned to the inline-start edge. Animates `x` only, which
|
|
9
|
-
* the compositor can handle without layout or paint.
|
|
10
|
-
*/
|
|
11
|
-
drawerStart: {
|
|
12
|
-
variants: {
|
|
13
|
-
open: { x: "0%" },
|
|
14
|
-
// Off-canvas direction follows writing direction, mirroring the
|
|
15
|
-
// `-translate-x-full rtl:translate-x-full` CSS fallback.
|
|
16
|
-
closed: (isRtl) => ({ x: isRtl ? "100%" : "-100%" })
|
|
17
|
-
},
|
|
18
|
-
transition: { type: "spring", stiffness: 400, damping: 40, mass: 1 }
|
|
19
|
-
},
|
|
20
|
-
/** Scrim behind a drawer or modal. */
|
|
21
|
-
overlay: {
|
|
22
|
-
variants: {
|
|
23
|
-
open: { opacity: 1 },
|
|
24
|
-
closed: { opacity: 0 }
|
|
25
|
-
},
|
|
26
|
-
transition: { duration: 0.2, ease: "easeOut" }
|
|
27
|
-
},
|
|
28
|
-
/** Centered dialog surface — rises and settles rather than popping. */
|
|
29
|
-
modalContent: {
|
|
30
|
-
variants: {
|
|
31
|
-
open: { opacity: 1, scale: 1, y: 0 },
|
|
32
|
-
closed: { opacity: 0, scale: 0.96, y: 8 }
|
|
33
|
-
},
|
|
34
|
-
transition: { type: "spring", stiffness: 500, damping: 40, mass: 0.8 }
|
|
35
|
-
},
|
|
36
|
-
/**
|
|
37
|
-
* Text that disappears as its container narrows — sidebar labels on collapse.
|
|
38
|
-
*
|
|
39
|
-
* Opacity only, and deliberately so. An inline-axis slide would read slightly
|
|
40
|
-
* better but would make every label direction-aware, and resolving direction
|
|
41
|
-
* per nav item is a disproportionate amount of plumbing for an 8px nudge.
|
|
42
|
-
* Fading also degrades to itself under reduced motion instead of becoming a
|
|
43
|
-
* different animation.
|
|
44
|
-
*
|
|
45
|
-
* Short because it runs on many elements at once and has to finish inside the
|
|
46
|
-
* container's own width transition, or labels are still fading after the rail
|
|
47
|
-
* has stopped moving.
|
|
48
|
-
*/
|
|
49
|
-
sidebarLabel: {
|
|
50
|
-
variants: {
|
|
51
|
-
open: { opacity: 1 },
|
|
52
|
-
closed: { opacity: 0 }
|
|
53
|
-
},
|
|
54
|
-
transition: { duration: 0.15, ease: "easeOut" }
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
var CONTEXT_KEY = /* @__PURE__ */ Symbol.for("@mieweb/ui.motionRuntimeContext.v1");
|
|
58
|
-
function getMotionRuntimeContext() {
|
|
59
|
-
const globalScope = globalThis;
|
|
60
|
-
if (!globalScope[CONTEXT_KEY]) {
|
|
61
|
-
globalScope[CONTEXT_KEY] = React.createContext(null);
|
|
62
|
-
}
|
|
63
|
-
return globalScope[CONTEXT_KEY];
|
|
64
|
-
}
|
|
65
|
-
var MotionRuntimeContext = getMotionRuntimeContext();
|
|
66
|
-
function useMotionRuntime() {
|
|
67
|
-
return React.useContext(MotionRuntimeContext);
|
|
68
|
-
}
|
|
69
|
-
function createPresetPropBuilders() {
|
|
70
|
-
return {
|
|
71
|
-
toggle(preset, open, custom) {
|
|
72
|
-
const { variants, transition } = motionPresets[preset];
|
|
73
|
-
return {
|
|
74
|
-
variants,
|
|
75
|
-
transition,
|
|
76
|
-
custom,
|
|
77
|
-
// `false` pins the element to its current variant on mount instead of
|
|
78
|
-
// animating into it.
|
|
79
|
-
initial: false,
|
|
80
|
-
animate: open ? "open" : "closed"
|
|
81
|
-
};
|
|
82
|
-
},
|
|
83
|
-
presence(preset, custom) {
|
|
84
|
-
const { variants, transition } = motionPresets[preset];
|
|
85
|
-
return {
|
|
86
|
-
variants,
|
|
87
|
-
transition,
|
|
88
|
-
custom,
|
|
89
|
-
initial: "closed",
|
|
90
|
-
animate: "open",
|
|
91
|
-
exit: "closed"
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
var Animated = React.forwardRef(
|
|
97
|
-
function Animated2({
|
|
98
|
-
as = "div",
|
|
99
|
-
preset,
|
|
100
|
-
mode,
|
|
101
|
-
open = false,
|
|
102
|
-
custom,
|
|
103
|
-
className,
|
|
104
|
-
fallbackClassName,
|
|
105
|
-
enabled = true,
|
|
106
|
-
children,
|
|
107
|
-
...rest
|
|
108
|
-
}, ref) {
|
|
109
|
-
const runtime = useMotionRuntime();
|
|
110
|
-
if (!runtime || !runtime.enabled || !enabled) {
|
|
111
|
-
const Tag = as;
|
|
112
|
-
return /* @__PURE__ */ jsx(Tag, { ref, className: cn(fallbackClassName, className), ...rest, children });
|
|
113
|
-
}
|
|
114
|
-
const Component = as === "nav" ? runtime.Nav : as === "span" ? runtime.Span : runtime.Div;
|
|
115
|
-
const motionProps = mode === "toggle" ? runtime.toggle(preset, open, custom) : runtime.presence(preset, custom);
|
|
116
|
-
return /* @__PURE__ */ jsx(Component, { ref, className, ...motionProps, ...rest, children });
|
|
117
|
-
}
|
|
118
|
-
);
|
|
119
|
-
Animated.displayName = "Animated";
|
|
120
|
-
function AnimatedPresence({
|
|
121
|
-
children,
|
|
122
|
-
initial,
|
|
123
|
-
onExitComplete
|
|
124
|
-
}) {
|
|
125
|
-
const runtime = useMotionRuntime();
|
|
126
|
-
if (!runtime) {
|
|
127
|
-
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
128
|
-
}
|
|
129
|
-
const { Presence } = runtime;
|
|
130
|
-
return /* @__PURE__ */ jsx(Presence, { initial, onExitComplete, children });
|
|
131
|
-
}
|
|
132
|
-
AnimatedPresence.displayName = "AnimatedPresence";
|
|
133
|
-
|
|
134
|
-
export { Animated, AnimatedPresence, MotionRuntimeContext, createPresetPropBuilders, motionPresets, useMotionRuntime };
|
|
135
|
-
//# sourceMappingURL=chunk-WYMO3IIK.js.map
|
|
136
|
-
//# sourceMappingURL=chunk-WYMO3IIK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/motion/presets.ts","../src/motion/runtime.ts","../src/motion/Animated.tsx"],"names":["React2","Animated"],"mappings":"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","file":"chunk-WYMO3IIK.js","sourcesContent":["/**\n * Motion presets — the shared vocabulary of animations.\n *\n * This module is intentionally **free of any `motion` import**. It ships in the\n * main `@mieweb/ui` entry so components can describe *what* they animate\n * without pulling in a runtime to actually do it. The `@mieweb/ui/motion` entry\n * is what turns these descriptions into real animations.\n *\n * Every preset is expressed as an open/closed variant pair so the same\n * definition serves both usages:\n *\n * - **toggle** — the element stays mounted and animates between `open` and\n * `closed` (a drawer sliding in and out).\n * - **presence** — the element mounts and unmounts, entering on `open` and\n * exiting back to `closed` (a modal).\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** Named animation recipes shared by components. */\nexport type MotionPreset =\n | 'drawerStart'\n | 'overlay'\n | 'modalContent'\n | 'sidebarLabel';\n\n/**\n * A variant value. Either a plain target object or a function of the element's\n * `custom` value — the latter lets a single preset adapt to context, e.g. a\n * drawer flipping its off-canvas direction in RTL.\n */\nexport type MotionVariant =\n | Record<string, unknown>\n | ((custom: unknown) => Record<string, unknown>);\n\nexport interface MotionPresetDefinition {\n variants: {\n open: MotionVariant;\n closed: MotionVariant;\n };\n transition: Record<string, unknown>;\n}\n\n// =============================================================================\n// Presets\n// =============================================================================\n\n/**\n * `custom` contract per preset:\n *\n * - `drawerStart` — `boolean`, whether the document direction is RTL.\n * - `overlay`, `modalContent`, `sidebarLabel` — unused.\n */\nexport const motionPresets: Record<MotionPreset, MotionPresetDefinition> = {\n /**\n * Off-canvas panel pinned to the inline-start edge. Animates `x` only, which\n * the compositor can handle without layout or paint.\n */\n drawerStart: {\n variants: {\n open: { x: '0%' },\n // Off-canvas direction follows writing direction, mirroring the\n // `-translate-x-full rtl:translate-x-full` CSS fallback.\n closed: (isRtl: unknown) => ({ x: isRtl ? '100%' : '-100%' }),\n },\n transition: { type: 'spring', stiffness: 400, damping: 40, mass: 1 },\n },\n\n /** Scrim behind a drawer or modal. */\n overlay: {\n variants: {\n open: { opacity: 1 },\n closed: { opacity: 0 },\n },\n transition: { duration: 0.2, ease: 'easeOut' },\n },\n\n /** Centered dialog surface — rises and settles rather than popping. */\n modalContent: {\n variants: {\n open: { opacity: 1, scale: 1, y: 0 },\n closed: { opacity: 0, scale: 0.96, y: 8 },\n },\n transition: { type: 'spring', stiffness: 500, damping: 40, mass: 0.8 },\n },\n\n /**\n * Text that disappears as its container narrows — sidebar labels on collapse.\n *\n * Opacity only, and deliberately so. An inline-axis slide would read slightly\n * better but would make every label direction-aware, and resolving direction\n * per nav item is a disproportionate amount of plumbing for an 8px nudge.\n * Fading also degrades to itself under reduced motion instead of becoming a\n * different animation.\n *\n * Short because it runs on many elements at once and has to finish inside the\n * container's own width transition, or labels are still fading after the rail\n * has stopped moving.\n */\n sidebarLabel: {\n variants: {\n open: { opacity: 1 },\n closed: { opacity: 0 },\n },\n transition: { duration: 0.15, ease: 'easeOut' },\n },\n};\n","/**\n * Motion runtime — the seam between components and an optional animation library.\n *\n * Components in the main entry never import `motion`. They ask this module for\n * a runtime; if an app has opted in by rendering `<MotionProvider>` from\n * `@mieweb/ui/motion`, they get one and animate. If not, `useMotionRuntime()`\n * returns `null` and they fall back to their existing CSS transitions. That is\n * what keeps `motion` out of the bundle of every app that hasn't asked for it —\n * the opt-in is resolved in the *module graph*, not by a prop.\n *\n * Like `presets`, this module must stay free of any `motion` import.\n */\n\nimport * as React from 'react';\nimport { motionPresets, type MotionPreset } from './presets';\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface MotionPresenceProps {\n children?: React.ReactNode;\n /** Suppress the initial mount animation. */\n initial?: boolean;\n /**\n * Fires once every exiting child has finished and been removed.\n *\n * Needed by anything that guards the DOM while it is open — a focus trap, a\n * scroll lock — because those guards must outlive `open` for as long as the\n * subtree is still on screen. Never fires when no runtime is active, since\n * there is no exit to wait for.\n */\n onExitComplete?: () => void;\n}\n\n/**\n * The capabilities a motion library must supply. Deliberately small: element\n * factories, a presence wrapper, and prop builders. Components depend on this\n * interface, never on a concrete library, so swapping or dropping the library\n * stays a one-file change.\n */\nexport interface MotionRuntime {\n /**\n * Whether animations should actually run.\n *\n * A disabled provider still supplies a runtime rather than `null` so that\n * consumers can tell \"disabled\" apart from \"never opted in\": `Modal` uses it\n * to decide whether an exit animation will ever report completion, and\n * `AnimatedPresence` keeps its wrapper element stable across the flip.\n * `Animated` itself renders the plain fallback tag whenever this is false —\n * withholding animation props from a mounted motion component corrupts\n * `toggle`-mode elements, so the swap (and the remount it implies) is the\n * correct behaviour. See the render branches in `Animated`.\n */\n enabled: boolean;\n /** Animated `div`. */\n Div: React.ElementType;\n /** Animated `nav`. */\n Nav: React.ElementType;\n /** Animated `span`, for inline content that must not become a block. */\n Span: React.ElementType;\n /** Enables exit animations for conditionally rendered children. */\n Presence: React.ComponentType<MotionPresenceProps>;\n /**\n * Props for an element that stays mounted and animates between states.\n * Skips the initial animation so a closed drawer doesn't slide out on load.\n */\n toggle: (\n preset: MotionPreset,\n open: boolean,\n custom?: unknown\n ) => Record<string, unknown>;\n /** Props for an element that mounts and unmounts inside `Presence`. */\n presence: (preset: MotionPreset, custom?: unknown) => Record<string, unknown>;\n}\n\n// =============================================================================\n// Context\n// =============================================================================\n\n/**\n * The context is stashed on `globalThis` under a registered symbol rather than\n * held in a module-local `const`.\n *\n * `@mieweb/ui` and `@mieweb/ui/motion` are separate bundle entries, and CJS\n * builds cannot code-split. Without this, the provider and the components\n * would each get their own copy of the context object and the provider would\n * silently never be seen — animations would simply never turn on, with no\n * error to explain why. A duplicated install of the package causes the same\n * failure. Keying off the global symbol registry makes the context a true\n * singleton in every one of those cases.\n *\n * The key is versioned. Two copies of this package sharing one page share\n * whatever lives under the key, so the `v1` suffix is a compatibility\n * contract: bump it if the `MotionRuntime` interface ever changes shape,\n * or an old provider will hand a new component a runtime it cannot use.\n */\nconst CONTEXT_KEY = Symbol.for('@mieweb/ui.motionRuntimeContext.v1');\n\ntype GlobalWithMotionContext = typeof globalThis & {\n [CONTEXT_KEY]?: React.Context<MotionRuntime | null>;\n};\n\nfunction getMotionRuntimeContext(): React.Context<MotionRuntime | null> {\n const globalScope = globalThis as GlobalWithMotionContext;\n if (!globalScope[CONTEXT_KEY]) {\n globalScope[CONTEXT_KEY] = React.createContext<MotionRuntime | null>(null);\n }\n return globalScope[CONTEXT_KEY];\n}\n\n/** @internal Consumed by `<MotionProvider>` in the `@mieweb/ui/motion` entry. */\nexport const MotionRuntimeContext = getMotionRuntimeContext();\n\n// =============================================================================\n// Hooks\n// =============================================================================\n\n/**\n * The active motion runtime, or `null` when the app has not opted in.\n *\n * Components must treat `null` as the normal case and keep a CSS path that\n * looks good on its own — motion is an enhancement, never a requirement.\n */\nexport function useMotionRuntime(): MotionRuntime | null {\n return React.useContext(MotionRuntimeContext);\n}\n\n// =============================================================================\n// Prop builders\n// =============================================================================\n\n/**\n * Builds the `toggle`/`presence` prop builders around a library-agnostic core.\n * Exported so `<MotionProvider>` can assemble a runtime without restating the\n * preset lookup.\n *\n * @internal\n */\nexport function createPresetPropBuilders(): Pick<\n MotionRuntime,\n 'toggle' | 'presence'\n> {\n return {\n toggle(preset, open, custom) {\n const { variants, transition } = motionPresets[preset];\n return {\n variants,\n transition,\n custom,\n // `false` pins the element to its current variant on mount instead of\n // animating into it.\n initial: false,\n animate: open ? 'open' : 'closed',\n };\n },\n\n presence(preset, custom) {\n const { variants, transition } = motionPresets[preset];\n return {\n variants,\n transition,\n custom,\n initial: 'closed',\n animate: 'open',\n exit: 'closed',\n };\n },\n };\n}\n","/**\n * `Animated` / `AnimatedPresence` — the ergonomic layer components use.\n *\n * These exist so an individual component never has to branch on whether motion\n * is available. It declares the preset it wants and the CSS classes that stand\n * in when motion is absent; this module picks the element to render.\n *\n * Adding motion to a further component should be a matter of swapping its\n * root `<div>` for an `<Animated>` and naming a preset — no new imports, no\n * new dependency, and no behavior change for apps that have not opted in.\n */\n\nimport * as React from 'react';\nimport { cn } from '../utils/cn';\nimport { useMotionRuntime, type MotionPresenceProps } from './runtime';\nimport type { MotionPreset } from './presets';\n\n// =============================================================================\n// Animated\n// =============================================================================\n\nexport interface AnimatedProps extends React.HTMLAttributes<HTMLElement> {\n /** Intrinsic element to render. */\n as?: 'div' | 'nav' | 'span';\n /** Which shared animation recipe to use. */\n preset: MotionPreset;\n /**\n * - `toggle` — element stays mounted and animates between open and closed.\n * - `presence` — element mounts and unmounts; wrap it in `<AnimatedPresence>`\n * so the exit animation gets a chance to run.\n */\n mode: 'toggle' | 'presence';\n /** Current state. Only read in `toggle` mode. */\n open?: boolean;\n /** Per-preset context value — see the `custom` contract in `presets.ts`. */\n custom?: unknown;\n /**\n * Classes applied whenever this element is **not** animating — no provider,\n * a disabled provider, or `enabled={false}`. This is where a component's\n * existing CSS transition lives, so the two paths never both try to drive\n * the same property.\n */\n fallbackClassName?: string;\n /**\n * Set `false` to stop this element animating even when a runtime is active.\n *\n * For states where an animated element would be wrong rather than merely\n * unnecessary. Motion writes a `transform` to hold an element at its resting\n * position, and a transformed ancestor becomes the containing block for any\n * `position: fixed` descendant — so an element that is only sometimes\n * animated should opt out the rest of the time.\n *\n * Flipping this (or the provider's `disabled`) swaps the element back to a\n * plain tag, which **remounts** it — deliberately. See the note on the\n * render branches below.\n */\n enabled?: boolean;\n}\n\nexport const Animated = React.forwardRef<HTMLElement, AnimatedProps>(\n function Animated(\n {\n as = 'div',\n preset,\n mode,\n open = false,\n custom,\n className,\n fallbackClassName,\n enabled = true,\n children,\n ...rest\n },\n ref\n ) {\n const runtime = useMotionRuntime();\n\n /*\n * Anything not animating renders the plain tag with the CSS fallback —\n * no provider, a disabled provider, or `enabled={false}` alike.\n *\n * Crossing between this branch and the motion one changes the element\n * type, which remounts the subtree. That is deliberate. The obvious\n * alternative — keeping the motion component mounted and only withholding\n * its animation props — corrupts `toggle`-mode elements in both\n * directions, because motion only writes variant styles at mount or in\n * response to an animation:\n *\n * - props added in place (a drawer crossing into its mobile breakpoint\n * while closed) never get the `closed` transform, so the drawer sits\n * fully visible over the page;\n * - props removed in place strand whatever inline `transform` motion last\n * wrote, so a sidebar returning to desktop stays off-canvas.\n *\n * Fresh mounts are correct in both worlds, so remounting at the flip is\n * the fix. The flips are rare — a breakpoint cross, a test toggling the\n * provider — and a remount that resets local state beats a stale\n * transform that removes the navigation.\n */\n if (!runtime || !runtime.enabled || !enabled) {\n const Tag = as as React.ElementType;\n return (\n <Tag ref={ref} className={cn(fallbackClassName, className)} {...rest}>\n {children}\n </Tag>\n );\n }\n\n const Component =\n as === 'nav' ? runtime.Nav : as === 'span' ? runtime.Span : runtime.Div;\n\n const motionProps =\n mode === 'toggle'\n ? runtime.toggle(preset, open, custom)\n : runtime.presence(preset, custom);\n\n return (\n <Component ref={ref} className={className} {...motionProps} {...rest}>\n {children}\n </Component>\n );\n }\n);\n\nAnimated.displayName = 'Animated';\n\n// =============================================================================\n// AnimatedPresence\n// =============================================================================\n\n/**\n * Keeps unmounting children on screen long enough to animate out.\n *\n * Without a runtime this is a pass-through, so children disappear immediately —\n * which is exactly what they do today. Children rendered conditionally inside\n * it need a stable `key`.\n */\nexport function AnimatedPresence({\n children,\n initial,\n onExitComplete,\n}: MotionPresenceProps): React.JSX.Element {\n const runtime = useMotionRuntime();\n\n if (!runtime) {\n return <>{children}</>;\n }\n\n const { Presence } = runtime;\n return (\n <Presence initial={initial} onExitComplete={onExitComplete}>\n {children}\n </Presence>\n );\n}\n\nAnimatedPresence.displayName = 'AnimatedPresence';\n"]}
|