@liveblocks/react-ui 3.18.0-rc1 → 3.18.0-rc2

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.
Files changed (53) hide show
  1. package/dist/_private/index.cjs +3 -2
  2. package/dist/_private/index.cjs.map +1 -1
  3. package/dist/_private/index.d.cts +24 -18
  4. package/dist/_private/index.d.ts +24 -18
  5. package/dist/_private/index.js +1 -1
  6. package/dist/components/Avatar.cjs +142 -0
  7. package/dist/components/Avatar.cjs.map +1 -0
  8. package/dist/components/Avatar.js +138 -0
  9. package/dist/components/Avatar.js.map +1 -0
  10. package/dist/components/AvatarStack.cjs +58 -44
  11. package/dist/components/AvatarStack.cjs.map +1 -1
  12. package/dist/components/AvatarStack.js +58 -44
  13. package/dist/components/AvatarStack.js.map +1 -1
  14. package/dist/components/Comment.cjs +3 -3
  15. package/dist/components/Comment.cjs.map +1 -1
  16. package/dist/components/Comment.js +3 -3
  17. package/dist/components/Comment.js.map +1 -1
  18. package/dist/components/CommentPin.cjs +2 -2
  19. package/dist/components/CommentPin.cjs.map +1 -1
  20. package/dist/components/CommentPin.js +2 -2
  21. package/dist/components/CommentPin.js.map +1 -1
  22. package/dist/components/Composer.cjs +3 -3
  23. package/dist/components/Composer.cjs.map +1 -1
  24. package/dist/components/Composer.js +3 -3
  25. package/dist/components/Composer.js.map +1 -1
  26. package/dist/components/InboxNotification.cjs +2 -2
  27. package/dist/components/InboxNotification.cjs.map +1 -1
  28. package/dist/components/InboxNotification.js +2 -2
  29. package/dist/components/InboxNotification.js.map +1 -1
  30. package/dist/components/internal/User.cjs +24 -10
  31. package/dist/components/internal/User.cjs.map +1 -1
  32. package/dist/components/internal/User.js +25 -11
  33. package/dist/components/internal/User.js.map +1 -1
  34. package/dist/index.cjs +2 -0
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +33 -1
  37. package/dist/index.d.ts +33 -1
  38. package/dist/index.js +1 -0
  39. package/dist/index.js.map +1 -1
  40. package/dist/version.cjs +1 -1
  41. package/dist/version.js +1 -1
  42. package/package.json +4 -4
  43. package/src/styles/index.css +21 -0
  44. package/styles.css +1 -1
  45. package/styles.css.map +1 -1
  46. package/dist/components/internal/Avatar.cjs +0 -63
  47. package/dist/components/internal/Avatar.cjs.map +0 -1
  48. package/dist/components/internal/Avatar.js +0 -61
  49. package/dist/components/internal/Avatar.js.map +0 -1
  50. package/dist/utils/use-user-or-group-info.cjs +0 -49
  51. package/dist/utils/use-user-or-group-info.cjs.map +0 -1
  52. package/dist/utils/use-user-or-group-info.js +0 -46
  53. package/dist/utils/use-user-or-group-info.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"Composer.js","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, Permission } from \"@liveblocks/core\";\nimport { useRoom } from \"@liveblocks/react\";\nimport {\n useCreateRoomComment,\n useCreateRoomThread,\n useEditRoomComment,\n useLayoutEffect,\n useResolveMentionSuggestions,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n PropsWithChildren,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../config\";\nimport { FLOATING_ELEMENT_SIDE_OFFSET } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\nimport { AttachmentIcon } from \"../icons/Attachment\";\nimport { BoldIcon } from \"../icons/Bold\";\nimport { CodeIcon } from \"../icons/Code\";\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { ItalicIcon } from \"../icons/Italic\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport { StrikethroughIcon } from \"../icons/Strikethrough\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport {\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n} from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerFormProps,\n ComposerMarkToggleProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { useComposerAttachmentsDropArea } from \"../primitives/Composer/utils\";\nimport type { ComposerBodyMark } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { useIsGroupMentionMember } from \"../utils/use-group-mention\";\nimport { FileAttachment } from \"./internal/Attachment\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n tooltipLabel?: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ninterface MarkToggleProps extends ComposerMarkToggleProps {\n icon?: ReactNode;\n shortcut?: string;\n}\n\nexport type ComposerCreateThreadProps<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerEditCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * The composer's initial attachments.\n */\n defaultAttachments?: CommentAttachment[];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether to show and allow adding attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show formatting controls (e.g. a floating toolbar with formatting toggles when selecting text)\n */\n showFormattingControls?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerFormProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n\n /**\n * @internal\n */\n roomId?: string;\n };\n\ninterface ComposerEditorContainerProps\n extends Pick<\n ComposerProps,\n | \"defaultValue\"\n | \"showAttachments\"\n | \"showFormattingControls\"\n | \"showAttribution\"\n | \"overrides\"\n | \"actions\"\n | \"autoFocus\"\n | \"disabled\"\n > {\n isCollapsed: boolean | undefined;\n onEmptyChange: (isEmpty: boolean) => void;\n hasResolveMentionSuggestions: boolean;\n onEmojiPickerOpenChange: (isOpen: boolean) => void;\n onEditorClick: (event: MouseEvent<HTMLDivElement>) => void;\n}\n\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\n}\n\nfunction ComposerInsertMentionEditorAction({\n label,\n tooltipLabel,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n icon={<MentionIcon />}\n {...props}\n />\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n tooltipLabel,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={tooltipLabel ?? label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<EmojiIcon />}\n {...props}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerAttachFilesEditorAction({\n label,\n tooltipLabel,\n className,\n ...props\n}: EditorActionProps) {\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <ComposerPrimitive.AttachFiles asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<AttachmentIcon />}\n {...props}\n />\n </ComposerPrimitive.AttachFiles>\n </Tooltip>\n );\n}\n\nfunction ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"Unhandled mention kind\");\n }\n}\n\nfunction ComposerMentionSuggestions({\n mentions,\n}: ComposerEditorMentionSuggestionsProps) {\n return mentions.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {mentions.map((mention) => {\n return (\n <ComposerPrimitive.SuggestionsListItem\n key={mention.id}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={mention.id}\n >\n {mention.kind === \"user\" ? (\n <>\n <Avatar\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </>\n ) : mention.kind === \"group\" ? (\n <>\n <Avatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\n );\n })}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction MarkToggle({\n mark,\n icon,\n shortcut,\n children,\n ...props\n}: MarkToggleProps) {\n const $ = useOverrides();\n const label = useMemo(() => {\n return $.COMPOSER_TOGGLE_MARK(mark);\n }, [$, mark]);\n\n return (\n <ShortcutTooltip\n content={label}\n shortcut={shortcut}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET + 2}\n >\n <ComposerPrimitive.MarkToggle mark={mark} asChild {...props}>\n <Button aria-label={label} variant=\"toolbar\" icon={icon}>\n {children}\n </Button>\n </ComposerPrimitive.MarkToggle>\n </ShortcutTooltip>\n );\n}\n\ntype MarkToggles = {\n [K in ComposerBodyMark]: ComponentType<PropsWithChildren>;\n};\n\nconst markToggles: MarkToggles = {\n bold: () => <MarkToggle mark=\"bold\" shortcut=\"Mod-B\" icon={<BoldIcon />} />,\n italic: () => (\n <MarkToggle mark=\"italic\" shortcut=\"Mod-I\" icon={<ItalicIcon />} />\n ),\n strikethrough: () => (\n <MarkToggle\n mark=\"strikethrough\"\n shortcut=\"Mod-Shift-S\"\n icon={<StrikethroughIcon />}\n />\n ),\n code: () => <MarkToggle mark=\"code\" shortcut=\"Mod-E\" icon={<CodeIcon />} />,\n};\n\nconst markTogglesList = Object.entries(markToggles).map(([mark, Toggle]) => (\n <Toggle key={mark} />\n));\n\nfunction ComposerFloatingToolbar() {\n return (\n <ComposerPrimitive.FloatingToolbar className=\"lb-root lb-portal lb-elevation lb-composer-floating-toolbar\">\n {markTogglesList}\n </ComposerPrimitive.FloatingToolbar>\n );\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\ninterface ComposerAttachmentsProps extends ComponentPropsWithoutRef<\"div\"> {\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\ninterface ComposerFileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\nfunction ComposerFileAttachment({\n attachment,\n className,\n overrides,\n ...props\n}: ComposerFileAttachmentProps) {\n const { removeAttachment } = useComposer();\n const { roomId } = useComposerEditorContext();\n\n const handleDeleteClick = useCallback(() => {\n removeAttachment(attachment.id);\n }, [attachment.id, removeAttachment]);\n\n return (\n <FileAttachment\n className={cn(\"lb-composer-attachment\", className)}\n {...props}\n attachment={attachment}\n onDeleteClick={handleDeleteClick}\n preventFocusOnDelete\n overrides={overrides}\n roomId={roomId}\n />\n );\n}\n\nfunction ComposerAttachments({\n overrides,\n className,\n ...props\n}: ComposerAttachmentsProps) {\n const { attachments } = useComposer();\n\n if (attachments.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"lb-composer-attachments\", className)} {...props}>\n <div className=\"lb-attachments\">\n {attachments.map((attachment) => {\n return (\n <ComposerFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n );\n })}\n </div>\n </div>\n );\n}\n\nconst editorRequiredComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nfunction ComposerEditorContainer({\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n defaultValue,\n isCollapsed,\n overrides,\n actions,\n autoFocus,\n disabled,\n hasResolveMentionSuggestions,\n onEmojiPickerOpenChange,\n onEmptyChange,\n onEditorClick,\n}: ComposerEditorContainerProps) {\n const { isEmpty } = useComposer();\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const $ = useOverrides(overrides);\n const components = useMemo(() => {\n return {\n ...editorRequiredComponents,\n FloatingToolbar: showFormattingControls\n ? ComposerFloatingToolbar\n : undefined,\n };\n }, [showFormattingControls]);\n\n const [isDraggingOver, dropAreaProps] = useComposerAttachmentsDropArea({\n disabled: disabled || !showAttachments || hasMaxAttachments,\n });\n\n useLayoutEffect(() => {\n onEmptyChange(isEmpty);\n }, [isEmpty, onEmptyChange]);\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <div className=\"lb-composer-editor-container\" {...dropAreaProps}>\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={onEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n autoFocus={autoFocus}\n components={components}\n disabled={disabled}\n dir={$.dir}\n />\n {showAttachments && <ComposerAttachments overrides={overrides} />}\n {(!isCollapsed || isDraggingOver) && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={disabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={onEmojiPickerOpenChange}\n disabled={disabled}\n />\n {showAttachments && (\n <ComposerAttachFilesEditorAction\n label={$.COMPOSER_ATTACH_FILES}\n disabled={disabled}\n />\n )}\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip content={$.COMPOSER_SEND} shortcut=\"Enter\">\n <ComposerPrimitive.Submit asChild>\n <Button\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n icon={<SendIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n {showAttachments && isDraggingOver && (\n <div className=\"lb-composer-attachments-drop-area\">\n <div className=\"lb-composer-attachments-drop-area-label\">\n <AttachmentIcon />\n {$.COMPOSER_ATTACH_FILES}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const ComposerRoomIdContext = createContext<string | null>(null);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\n defaultValue,\n defaultAttachments,\n onComposerSubmit,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n overrides,\n actions,\n onBlur,\n className,\n onFocus,\n autoFocus,\n disabled,\n blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const room = useRoom({ allowOutsideRoom: true });\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\n \"Composer must be a descendant of RoomProvider component\"\n );\n }\n\n const createThread = useCreateRoomThread(roomId);\n const createComment = useCreateRoomComment(roomId);\n const editComment = useEditRoomComment(roomId);\n const { preventUnsavedComposerChanges } = useLiveblocksUiConfig();\n const hasResolveMentionSuggestions =\n useResolveMentionSuggestions() !== undefined;\n const isEmptyRef = useRef(true);\n const isEmojiPickerOpenRef = useRef(false);\n const $ = useOverrides(overrides);\n const [isCollapsed, onCollapsedChange] = useControllableState(\n defaultCollapsed ?? false,\n controlledCollapsed,\n controlledOnCollapsedChange\n );\n\n const canCommentFallback = useSyncExternalStore(\n useCallback(\n (callback) => {\n if (room === null) return () => {};\n return room.events.self.subscribeOnce(callback);\n },\n [room]\n ),\n useCallback(() => {\n return room?.getSelf()?.canComment ?? true;\n }, [room]),\n useCallback(() => true, [])\n );\n\n const permissions = useRoomPermissions(roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : canCommentFallback;\n\n const setEmptyRef = useCallback((isEmpty: boolean) => {\n isEmptyRef.current = isEmpty;\n }, []);\n\n const setEmojiPickerOpenRef = useCallback((isEmojiPickerOpen: boolean) => {\n isEmojiPickerOpenRef.current = isEmojiPickerOpen;\n }, []);\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, onFocus, canComment]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(\n event.relatedTarget ?? document.activeElement\n );\n\n if (isOutside && isEmptyRef.current && !isEmojiPickerOpenRef.current) {\n onCollapsedChange?.(true);\n }\n },\n [onBlur, onCollapsedChange]\n );\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, canComment]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form\n onComposerSubmit={handleComposerSubmit}\n className={cn(\"lb-root lb-composer lb-composer-form\", className)}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={isCollapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled || !canComment}\n defaultAttachments={defaultAttachments}\n pasteFilesAsAttachments={showAttachments}\n preventUnsavedChanges={preventUnsavedComposerChanges}\n blurOnSubmit={blurOnSubmit}\n roomId={roomId}\n >\n <ComposerEditorContainer\n defaultValue={defaultValue}\n actions={actions}\n overrides={overrides}\n isCollapsed={isCollapsed}\n showAttachments={showAttachments}\n showAttribution={showAttribution}\n showFormattingControls={showFormattingControls}\n hasResolveMentionSuggestions={hasResolveMentionSuggestions}\n onEmptyChange={setEmptyRef}\n onEmojiPickerOpenChange={setEmojiPickerOpenRef}\n onEditorClick={handleEditorClick}\n autoFocus={autoFocus}\n disabled={disabled}\n />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;AAEA;AAA2D;AAChD;AACW;AAEtB;AAEA;AAAiC;AACb;AACO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAAO;AACF;AAGC;AACN;AAGF;AAAuE;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;AACO;AACzB;AACQ;AACL;AAIL;AAEA;AACA;AACE;AAAU;AACR;AACF;AAGF;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAyC;AACnB;AACpB;AACA;AAGF;AAA2B;AACzB;AAEI;AAAmB;AAAa;AAChC;AAA8C;AAChD;AACK;AACP;AAEE;AAAsC;AAC/B;AACiB;AAG5B;AACA;AAMA;AACE;AAAqB;AAGvB;AACE;AAA+B;AAGjC;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACuC;AAGzC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAAuC;AACL;AAGlC;AACE;AAAwB;AAC1B;AACF;AAC0B;AAG5B;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC8B;AAGhC;AAA6B;AAEzB;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAY;AACV;AACA;AACc;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;AAGN;;"}
1
+ {"version":3,"file":"Composer.js","sources":["../../src/components/Composer.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n BaseMetadata,\n CommentAttachment,\n CommentMixedAttachment,\n DCM,\n DTM,\n GroupMentionData,\n Patchable,\n} from \"@liveblocks/core\";\nimport { assertNever, MENTION_CHARACTER, Permission } from \"@liveblocks/core\";\nimport { useRoom } from \"@liveblocks/react\";\nimport {\n useCreateRoomComment,\n useCreateRoomThread,\n useEditRoomComment,\n useLayoutEffect,\n useResolveMentionSuggestions,\n useRoomPermissions,\n} from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n FocusEvent,\n FormEvent,\n ForwardedRef,\n MouseEvent,\n PropsWithChildren,\n ReactNode,\n RefAttributes,\n SyntheticEvent,\n} from \"react\";\nimport {\n createContext,\n forwardRef,\n useCallback,\n useMemo,\n useRef,\n useSyncExternalStore,\n} from \"react\";\n\nimport { useLiveblocksUiConfig } from \"../config\";\nimport { FLOATING_ELEMENT_SIDE_OFFSET } from \"../constants\";\nimport { UsersIcon } from \"../icons\";\nimport { AttachmentIcon } from \"../icons/Attachment\";\nimport { BoldIcon } from \"../icons/Bold\";\nimport { CodeIcon } from \"../icons/Code\";\nimport { EmojiIcon } from \"../icons/Emoji\";\nimport { ItalicIcon } from \"../icons/Italic\";\nimport { MentionIcon } from \"../icons/Mention\";\nimport { SendIcon } from \"../icons/Send\";\nimport { StrikethroughIcon } from \"../icons/Strikethrough\";\nimport type { ComposerOverrides, GlobalOverrides } from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport * as ComposerPrimitive from \"../primitives/Composer\";\nimport {\n useComposer,\n useComposerAttachmentsContext,\n useComposerEditorContext,\n} from \"../primitives/Composer/contexts\";\nimport type {\n ComposerEditorComponents,\n ComposerEditorLinkProps,\n ComposerEditorMentionProps,\n ComposerEditorMentionSuggestionsProps,\n ComposerEditorProps,\n ComposerFormProps,\n ComposerMarkToggleProps,\n ComposerSubmitComment,\n} from \"../primitives/Composer/types\";\nimport { useComposerAttachmentsDropArea } from \"../primitives/Composer/utils\";\nimport type { ComposerBodyMark } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { useControllableState } from \"../utils/use-controllable-state\";\nimport { useIsGroupMentionMember } from \"../utils/use-group-mention\";\nimport { FileAttachment } from \"./internal/Attachment\";\nimport { Attribution } from \"./internal/Attribution\";\nimport { GroupAvatar, UserAvatar } from \"./Avatar\";\nimport { Button } from \"./internal/Button\";\nimport type { EmojiPickerProps } from \"./internal/EmojiPicker\";\nimport { EmojiPicker, EmojiPickerTrigger } from \"./internal/EmojiPicker\";\nimport { Group } from \"./internal/Group\";\nimport { GroupDescription } from \"./internal/GroupDescription\";\nimport { ShortcutTooltip, Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ninterface EditorActionProps extends ComponentPropsWithoutRef<\"button\"> {\n label: string;\n tooltipLabel?: string;\n}\n\ninterface EmojiEditorActionProps extends EditorActionProps {\n onPickerOpenChange?: EmojiPickerProps[\"onOpenChange\"];\n}\n\ninterface MarkToggleProps extends ComposerMarkToggleProps {\n icon?: ReactNode;\n shortcut?: string;\n}\n\nexport type ComposerCreateThreadProps<\n TM extends BaseMetadata,\n CM extends BaseMetadata,\n> = {\n threadId?: never;\n\n commentId?: never;\n\n /**\n * The metadata of the thread to create.\n */\n metadata?: TM;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerCreateCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to reply to.\n */\n threadId: string;\n\n commentId?: never;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to create.\n */\n commentMetadata?: CM;\n};\n\nexport type ComposerEditCommentProps<CM extends BaseMetadata> = {\n /**\n * The ID of the thread to edit a comment in.\n */\n threadId: string;\n\n /**\n * The ID of the comment to edit.\n */\n commentId: string;\n\n metadata?: never;\n\n /**\n * The metadata of the comment to edit.\n */\n commentMetadata?: Patchable<CM>;\n};\n\nexport type ComposerProps<\n TM extends BaseMetadata = DTM,\n CM extends BaseMetadata = DCM,\n> = Omit<ComponentPropsWithoutRef<\"form\">, \"defaultValue\"> &\n (\n | ComposerCreateThreadProps<TM, CM>\n | ComposerCreateCommentProps<CM>\n | ComposerEditCommentProps<CM>\n ) & {\n /**\n * The event handler called when the composer is submitted.\n */\n onComposerSubmit?: (\n comment: ComposerSubmitComment,\n event: FormEvent<HTMLFormElement>\n ) => Promise<void> | void;\n\n /**\n * The composer's initial value.\n */\n defaultValue?: ComposerEditorProps[\"defaultValue\"];\n\n /**\n * The composer's initial attachments.\n */\n defaultAttachments?: CommentAttachment[];\n\n /**\n * Whether the composer is collapsed. Setting a value will make the composer controlled.\n */\n collapsed?: boolean;\n\n /**\n * The event handler called when the collapsed state of the composer changes.\n */\n onCollapsedChange?: (collapsed: boolean) => void;\n\n /**\n * Whether the composer is initially collapsed. Setting a value will make the composer uncontrolled.\n */\n defaultCollapsed?: boolean;\n\n /**\n * Whether to show and allow adding attachments.\n */\n showAttachments?: boolean;\n\n /**\n * Whether to show formatting controls (e.g. a floating toolbar with formatting toggles when selecting text)\n */\n showFormattingControls?: boolean;\n\n /**\n * Whether the composer is disabled.\n */\n disabled?: ComposerFormProps[\"disabled\"];\n\n /**\n * Whether to focus the composer on mount.\n */\n autoFocus?: ComposerEditorProps[\"autoFocus\"];\n\n /**\n * Whether to blur the composer editor when the composer is submitted.\n */\n blurOnSubmit?: boolean;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n\n /**\n * @internal\n */\n actions?: ReactNode;\n\n /**\n * @internal\n */\n showAttribution?: boolean;\n\n /**\n * @internal\n */\n roomId?: string;\n };\n\ninterface ComposerEditorContainerProps\n extends Pick<\n ComposerProps,\n | \"defaultValue\"\n | \"showAttachments\"\n | \"showFormattingControls\"\n | \"showAttribution\"\n | \"overrides\"\n | \"actions\"\n | \"autoFocus\"\n | \"disabled\"\n > {\n isCollapsed: boolean | undefined;\n onEmptyChange: (isEmpty: boolean) => void;\n hasResolveMentionSuggestions: boolean;\n onEmojiPickerOpenChange: (isOpen: boolean) => void;\n onEditorClick: (event: MouseEvent<HTMLDivElement>) => void;\n}\n\ninterface ComposerMentionProps extends ComposerEditorMentionProps {\n overrides?: ComposerProps[\"overrides\"];\n}\n\nfunction ComposerInsertMentionEditorAction({\n label,\n tooltipLabel,\n className,\n onClick,\n ...props\n}: EditorActionProps) {\n const { createMention } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const handleClick = useCallback(\n (event: MouseEvent<HTMLButtonElement>) => {\n onClick?.(event);\n\n if (!event.isDefaultPrevented()) {\n event.stopPropagation();\n createMention();\n }\n },\n [createMention, onClick]\n );\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={handleClick}\n aria-label={label}\n icon={<MentionIcon />}\n {...props}\n />\n </Tooltip>\n );\n}\n\nfunction ComposerInsertEmojiEditorAction({\n label,\n tooltipLabel,\n onPickerOpenChange,\n className,\n ...props\n}: EmojiEditorActionProps) {\n const { insertText } = useComposer();\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <EmojiPicker onEmojiSelect={insertText} onOpenChange={onPickerOpenChange}>\n <Tooltip content={tooltipLabel ?? label}>\n <EmojiPickerTrigger asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<EmojiIcon />}\n {...props}\n />\n </EmojiPickerTrigger>\n </Tooltip>\n </EmojiPicker>\n );\n}\n\nfunction ComposerAttachFilesEditorAction({\n label,\n tooltipLabel,\n className,\n ...props\n}: EditorActionProps) {\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <Tooltip content={tooltipLabel ?? label}>\n <ComposerPrimitive.AttachFiles asChild>\n <Button\n className={cn(\"lb-composer-editor-action\", className)}\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n aria-label={label}\n icon={<AttachmentIcon />}\n {...props}\n />\n </ComposerPrimitive.AttachFiles>\n </Tooltip>\n );\n}\n\nfunction ComposerUserMention({ mention }: ComposerMentionProps) {\n return (\n <ComposerPrimitive.Mention className=\"lb-mention lb-composer-mention\">\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <User userId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nfunction ComposerGroupMention({ mention }: ComposerMentionProps) {\n const isMember = useIsGroupMentionMember(mention as GroupMentionData);\n\n return (\n <ComposerPrimitive.Mention\n className=\"lb-mention lb-composer-mention\"\n data-self={isMember ? \"\" : undefined}\n >\n <span className=\"lb-mention-symbol\">{MENTION_CHARACTER}</span>\n <Group groupId={mention.id} />\n </ComposerPrimitive.Mention>\n );\n}\n\nexport function ComposerMention({ mention, ...props }: ComposerMentionProps) {\n switch (mention.kind) {\n case \"user\":\n return <ComposerUserMention mention={mention} {...props} />;\n\n case \"group\":\n return <ComposerGroupMention mention={mention} {...props} />;\n\n default:\n return assertNever(mention, \"Unhandled mention kind\");\n }\n}\n\nfunction ComposerMentionSuggestions({\n mentions,\n}: ComposerEditorMentionSuggestionsProps) {\n return mentions.length > 0 ? (\n <ComposerPrimitive.Suggestions className=\"lb-root lb-portal lb-elevation lb-composer-suggestions lb-composer-mention-suggestions\">\n <ComposerPrimitive.SuggestionsList className=\"lb-composer-suggestions-list lb-composer-mention-suggestions-list\">\n {mentions.map((mention) => {\n return (\n <ComposerPrimitive.SuggestionsListItem\n key={mention.id}\n className=\"lb-composer-suggestions-list-item lb-composer-mention-suggestion\"\n value={mention.id}\n >\n {mention.kind === \"user\" ? (\n <>\n <UserAvatar\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n />\n <User\n userId={mention.id}\n className=\"lb-composer-mention-suggestion-user\"\n />\n </>\n ) : mention.kind === \"group\" ? (\n <>\n <GroupAvatar\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-avatar\"\n icon={<UsersIcon />}\n />\n <Group\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group\"\n >\n <GroupDescription\n groupId={mention.id}\n className=\"lb-composer-mention-suggestion-group-description\"\n />\n </Group>\n </>\n ) : (\n assertNever(mention, \"Unhandled mention kind\")\n )}\n </ComposerPrimitive.SuggestionsListItem>\n );\n })}\n </ComposerPrimitive.SuggestionsList>\n </ComposerPrimitive.Suggestions>\n ) : null;\n}\n\nfunction MarkToggle({\n mark,\n icon,\n shortcut,\n children,\n ...props\n}: MarkToggleProps) {\n const $ = useOverrides();\n const label = useMemo(() => {\n return $.COMPOSER_TOGGLE_MARK(mark);\n }, [$, mark]);\n\n return (\n <ShortcutTooltip\n content={label}\n shortcut={shortcut}\n sideOffset={FLOATING_ELEMENT_SIDE_OFFSET + 2}\n >\n <ComposerPrimitive.MarkToggle mark={mark} asChild {...props}>\n <Button aria-label={label} variant=\"toolbar\" icon={icon}>\n {children}\n </Button>\n </ComposerPrimitive.MarkToggle>\n </ShortcutTooltip>\n );\n}\n\ntype MarkToggles = {\n [K in ComposerBodyMark]: ComponentType<PropsWithChildren>;\n};\n\nconst markToggles: MarkToggles = {\n bold: () => <MarkToggle mark=\"bold\" shortcut=\"Mod-B\" icon={<BoldIcon />} />,\n italic: () => (\n <MarkToggle mark=\"italic\" shortcut=\"Mod-I\" icon={<ItalicIcon />} />\n ),\n strikethrough: () => (\n <MarkToggle\n mark=\"strikethrough\"\n shortcut=\"Mod-Shift-S\"\n icon={<StrikethroughIcon />}\n />\n ),\n code: () => <MarkToggle mark=\"code\" shortcut=\"Mod-E\" icon={<CodeIcon />} />,\n};\n\nconst markTogglesList = Object.entries(markToggles).map(([mark, Toggle]) => (\n <Toggle key={mark} />\n));\n\nfunction ComposerFloatingToolbar() {\n return (\n <ComposerPrimitive.FloatingToolbar className=\"lb-root lb-portal lb-elevation lb-composer-floating-toolbar\">\n {markTogglesList}\n </ComposerPrimitive.FloatingToolbar>\n );\n}\n\nfunction ComposerLink({ href, children }: ComposerEditorLinkProps) {\n return (\n <ComposerPrimitive.Link href={href} className=\"lb-composer-link\">\n {children}\n </ComposerPrimitive.Link>\n );\n}\n\ninterface ComposerAttachmentsProps extends ComponentPropsWithoutRef<\"div\"> {\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\ninterface ComposerFileAttachmentProps extends ComponentPropsWithoutRef<\"div\"> {\n attachment: CommentMixedAttachment;\n overrides?: Partial<GlobalOverrides & ComposerOverrides>;\n}\n\nfunction ComposerFileAttachment({\n attachment,\n className,\n overrides,\n ...props\n}: ComposerFileAttachmentProps) {\n const { removeAttachment } = useComposer();\n const { roomId } = useComposerEditorContext();\n\n const handleDeleteClick = useCallback(() => {\n removeAttachment(attachment.id);\n }, [attachment.id, removeAttachment]);\n\n return (\n <FileAttachment\n className={cn(\"lb-composer-attachment\", className)}\n {...props}\n attachment={attachment}\n onDeleteClick={handleDeleteClick}\n preventFocusOnDelete\n overrides={overrides}\n roomId={roomId}\n />\n );\n}\n\nfunction ComposerAttachments({\n overrides,\n className,\n ...props\n}: ComposerAttachmentsProps) {\n const { attachments } = useComposer();\n\n if (attachments.length === 0) {\n return null;\n }\n\n return (\n <div className={cn(\"lb-composer-attachments\", className)} {...props}>\n <div className=\"lb-attachments\">\n {attachments.map((attachment) => {\n return (\n <ComposerFileAttachment\n key={attachment.id}\n attachment={attachment}\n overrides={overrides}\n />\n );\n })}\n </div>\n </div>\n );\n}\n\nconst editorRequiredComponents: ComposerEditorComponents = {\n Mention: ComposerMention,\n MentionSuggestions: ComposerMentionSuggestions,\n Link: ComposerLink,\n};\n\nfunction ComposerEditorContainer({\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n defaultValue,\n isCollapsed,\n overrides,\n actions,\n autoFocus,\n disabled,\n hasResolveMentionSuggestions,\n onEmojiPickerOpenChange,\n onEmptyChange,\n onEditorClick,\n}: ComposerEditorContainerProps) {\n const { isEmpty } = useComposer();\n const { hasMaxAttachments } = useComposerAttachmentsContext();\n const $ = useOverrides(overrides);\n const components = useMemo(() => {\n return {\n ...editorRequiredComponents,\n FloatingToolbar: showFormattingControls\n ? ComposerFloatingToolbar\n : undefined,\n };\n }, [showFormattingControls]);\n\n const [isDraggingOver, dropAreaProps] = useComposerAttachmentsDropArea({\n disabled: disabled || !showAttachments || hasMaxAttachments,\n });\n\n useLayoutEffect(() => {\n onEmptyChange(isEmpty);\n }, [isEmpty, onEmptyChange]);\n\n const preventDefault = useCallback((event: SyntheticEvent) => {\n event.preventDefault();\n }, []);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n return (\n <div className=\"lb-composer-editor-container\" {...dropAreaProps}>\n <ComposerPrimitive.Editor\n className=\"lb-composer-editor\"\n onClick={onEditorClick}\n placeholder={$.COMPOSER_PLACEHOLDER}\n defaultValue={defaultValue}\n autoFocus={autoFocus}\n components={components}\n disabled={disabled}\n dir={$.dir}\n />\n {showAttachments && <ComposerAttachments overrides={overrides} />}\n {(!isCollapsed || isDraggingOver) && (\n <div className=\"lb-composer-footer\">\n <div className=\"lb-composer-editor-actions\">\n {hasResolveMentionSuggestions && (\n <ComposerInsertMentionEditorAction\n label={$.COMPOSER_INSERT_MENTION}\n disabled={disabled}\n />\n )}\n <ComposerInsertEmojiEditorAction\n label={$.COMPOSER_INSERT_EMOJI}\n onPickerOpenChange={onEmojiPickerOpenChange}\n disabled={disabled}\n />\n {showAttachments && (\n <ComposerAttachFilesEditorAction\n label={$.COMPOSER_ATTACH_FILES}\n disabled={disabled}\n />\n )}\n </div>\n {showAttribution && <Attribution />}\n <div className=\"lb-composer-actions\">\n {actions ?? (\n <>\n <ShortcutTooltip content={$.COMPOSER_SEND} shortcut=\"Enter\">\n <ComposerPrimitive.Submit asChild>\n <Button\n onPointerDown={preventDefault}\n onClick={stopPropagation}\n className=\"lb-composer-action\"\n variant=\"primary\"\n aria-label={$.COMPOSER_SEND}\n icon={<SendIcon />}\n />\n </ComposerPrimitive.Submit>\n </ShortcutTooltip>\n </>\n )}\n </div>\n </div>\n )}\n {showAttachments && isDraggingOver && (\n <div className=\"lb-composer-attachments-drop-area\">\n <div className=\"lb-composer-attachments-drop-area-label\">\n <AttachmentIcon />\n {$.COMPOSER_ATTACH_FILES}\n </div>\n </div>\n )}\n </div>\n );\n}\n\nexport const ComposerRoomIdContext = createContext<string | null>(null);\n\n/**\n * Displays a composer to create comments.\n *\n * @example\n * <Composer />\n */\nexport const Composer = forwardRef(\n <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n {\n threadId,\n commentId,\n metadata,\n commentMetadata,\n defaultValue,\n defaultAttachments,\n onComposerSubmit,\n collapsed: controlledCollapsed,\n defaultCollapsed,\n onCollapsedChange: controlledOnCollapsedChange,\n overrides,\n actions,\n onBlur,\n className,\n onFocus,\n autoFocus,\n disabled,\n blurOnSubmit = true,\n showAttachments = true,\n showFormattingControls = true,\n showAttribution,\n roomId: _roomId,\n ...props\n }: ComposerProps<TM, CM>,\n forwardedRef: ForwardedRef<HTMLFormElement>\n ) => {\n const room = useRoom({ allowOutsideRoom: true });\n\n const roomId = _roomId !== undefined ? _roomId : room?.id;\n if (roomId === undefined) {\n throw new Error(\n \"Composer must be a descendant of RoomProvider component\"\n );\n }\n\n const createThread = useCreateRoomThread(roomId);\n const createComment = useCreateRoomComment(roomId);\n const editComment = useEditRoomComment(roomId);\n const { preventUnsavedComposerChanges } = useLiveblocksUiConfig();\n const hasResolveMentionSuggestions =\n useResolveMentionSuggestions() !== undefined;\n const isEmptyRef = useRef(true);\n const isEmojiPickerOpenRef = useRef(false);\n const $ = useOverrides(overrides);\n const [isCollapsed, onCollapsedChange] = useControllableState(\n defaultCollapsed ?? false,\n controlledCollapsed,\n controlledOnCollapsedChange\n );\n\n const canCommentFallback = useSyncExternalStore(\n useCallback(\n (callback) => {\n if (room === null) return () => {};\n return room.events.self.subscribeOnce(callback);\n },\n [room]\n ),\n useCallback(() => {\n return room?.getSelf()?.canComment ?? true;\n }, [room]),\n useCallback(() => true, [])\n );\n\n const permissions = useRoomPermissions(roomId);\n const canComment =\n permissions.size > 0\n ? permissions.has(Permission.CommentsWrite) ||\n permissions.has(Permission.Write)\n : canCommentFallback;\n\n const setEmptyRef = useCallback((isEmpty: boolean) => {\n isEmptyRef.current = isEmpty;\n }, []);\n\n const setEmojiPickerOpenRef = useCallback((isEmojiPickerOpen: boolean) => {\n isEmojiPickerOpenRef.current = isEmojiPickerOpen;\n }, []);\n\n const handleFocus = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onFocus?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, onFocus, canComment]\n );\n\n const handleBlur = useCallback(\n (event: FocusEvent<HTMLFormElement>) => {\n onBlur?.(event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const isOutside = !event.currentTarget.contains(\n event.relatedTarget ?? document.activeElement\n );\n\n if (isOutside && isEmptyRef.current && !isEmojiPickerOpenRef.current) {\n onCollapsedChange?.(true);\n }\n },\n [onBlur, onCollapsedChange]\n );\n\n const handleEditorClick = useCallback(\n (event: MouseEvent<HTMLDivElement>) => {\n event.stopPropagation();\n\n if (isEmptyRef.current && canComment) {\n onCollapsedChange?.(false);\n }\n },\n [onCollapsedChange, canComment]\n );\n\n const handleComposerSubmit = useCallback(\n (comment: ComposerSubmitComment, event: FormEvent<HTMLFormElement>) => {\n onComposerSubmit?.(comment, event);\n\n if (event.isDefaultPrevented()) {\n return;\n }\n\n event.stopPropagation();\n\n if (commentId && threadId) {\n editComment({\n commentId,\n threadId,\n body: comment.body,\n metadata: commentMetadata,\n attachments: comment.attachments,\n });\n } else if (threadId) {\n createComment({\n threadId,\n body: comment.body,\n metadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n } else {\n createThread({\n body: comment.body,\n metadata,\n commentMetadata: commentMetadata as CM | undefined,\n attachments: comment.attachments,\n });\n }\n },\n [\n commentId,\n createComment,\n createThread,\n editComment,\n commentMetadata,\n metadata,\n onComposerSubmit,\n threadId,\n ]\n );\n\n return (\n <TooltipProvider>\n <ComposerPrimitive.Form\n onComposerSubmit={handleComposerSubmit}\n className={cn(\"lb-root lb-composer lb-composer-form\", className)}\n dir={$.dir}\n {...props}\n ref={forwardedRef}\n data-collapsed={isCollapsed ? \"\" : undefined}\n onFocus={handleFocus}\n onBlur={handleBlur}\n disabled={disabled || !canComment}\n defaultAttachments={defaultAttachments}\n pasteFilesAsAttachments={showAttachments}\n preventUnsavedChanges={preventUnsavedComposerChanges}\n blurOnSubmit={blurOnSubmit}\n roomId={roomId}\n >\n <ComposerEditorContainer\n defaultValue={defaultValue}\n actions={actions}\n overrides={overrides}\n isCollapsed={isCollapsed}\n showAttachments={showAttachments}\n showAttribution={showAttribution}\n showFormattingControls={showFormattingControls}\n hasResolveMentionSuggestions={hasResolveMentionSuggestions}\n onEmptyChange={setEmptyRef}\n onEmojiPickerOpenChange={setEmojiPickerOpenRef}\n onEditorClick={handleEditorClick}\n autoFocus={autoFocus}\n disabled={disabled}\n />\n </ComposerPrimitive.Form>\n </TooltipProvider>\n );\n }\n) as <TM extends BaseMetadata = DTM, CM extends BaseMetadata = DCM>(\n props: ComposerProps<TM, CM> & RefAttributes<HTMLFormElement>\n) => JSX.Element;\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA0QA;AAA2C;AACzC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AAAoB;AAEhB;AAEA;AACE;AACA;AAAc;AAChB;AACF;AACuB;AAGzB;AAEI;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACO;AACf;AAAA;AAIZ;AAEA;AAAyC;AACvC;AACA;AACA;AACA;AAEF;AACE;AAEA;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAIQ;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACK;AACb;AAAA;AAMhB;AAEA;AAAyC;AACvC;AACA;AACA;AAEF;AACE;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAGM;AAAC;AAAA;AACqD;AACrC;AACN;AACG;AACU;AAClB;AAAA;AAKd;AAEA;AACE;AAEI;AAAuD;AAC7B;AAGhC;AAEA;AACE;AAEA;AACE;AAAmB;AAAlB;AACW;AACiB;AAE3B;AAAuD;AAC3B;AAAA;AAAA;AAGlC;AAEO;AACL;AAAsB;AAElB;AAAyD;AAGzD;AAA0D;AAG1D;AAAoD;AAE1D;AAEA;AAAoC;AAEpC;AACE;AAIQ;AACE;AAAmB;AAAlB;AAEW;AACK;AAIX;AAAA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AACA;AAAC;AAAA;AACiB;AACN;AAAA;AACZ;AAIA;AAAA;AAAC;AAAA;AACkB;AACP;AACO;AAAA;AACnB;AACA;AAAC;AAAA;AACkB;AACP;AAEV;AAAC;AAAA;AACkB;AACP;AAAA;AACZ;AAAA;AACF;AAG2C;AAAA;AAjClC;AAmCf;AAMZ;AAEA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACA;AACE;AAAkC;AAGpC;AACE;AAAC;AAAA;AACU;AACT;AAC2C;AAM3C;AAAA;AAGN;AAMA;AAAiC;AAC0C;AAEN;AAGjE;AAAC;AAAA;AACM;AACI;AACgB;AAAA;AAC3B;AAGJ;AAEA;AAIA;AACE;AAKF;AAEA;AACE;AAKF;AAWA;AAAgC;AAC9B;AACA;AACA;AAEF;AACE;AACA;AAEA;AACE;AAA8B;AAGhC;AACE;AAAC;AAAA;AACkD;AAC7C;AACJ;AACe;AACK;AACpB;AACA;AAAA;AAGN;AAEA;AAA6B;AAC3B;AACA;AAEF;AACE;AAEA;AACE;AAAO;AAGT;AAIQ;AACE;AAAC;AAAA;AAEC;AACA;AAAA;AAFgB;AAGlB;AAMZ;AAEA;AAA2D;AAChD;AACW;AAEtB;AAEA;AAAiC;AACb;AACO;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAAO;AACF;AAGC;AACN;AAGF;AAAuE;AAC3B;AAG5C;AACE;AAAqB;AAGvB;AACE;AAAqB;AAGvB;AACE;AAAsB;AAGxB;AAEI;AAAA;AAAmB;AAAlB;AACW;AACD;AACM;AACf;AACA;AACA;AACA;AACO;AAAA;AACT;AAC+D;AAG3D;AACG;AACC;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEF;AAAC;AAAA;AACU;AACW;AACpB;AAAA;AACF;AAEE;AAAC;AAAA;AACU;AACT;AAAA;AACF;AAEJ;AACiC;AAMvB;AAAC;AAAA;AACgB;AACN;AACC;AACF;AACM;AACE;AAAA;AAM5B;AACF;AAKI;AAAgB;AACb;AAEP;AAIR;AAEa;AAQN;AAAiB;AAEpB;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACW;AACX;AACmB;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACG;AACO;AACzB;AACQ;AACL;AAIL;AAEA;AACA;AACE;AAAU;AACR;AACF;AAGF;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AAAyC;AACnB;AACpB;AACA;AAGF;AAA2B;AACzB;AAEI;AAAmB;AAAa;AAChC;AAA8C;AAChD;AACK;AACP;AAEE;AAAsC;AAC/B;AACiB;AAG5B;AACA;AAMA;AACE;AAAqB;AAGvB;AACE;AAA+B;AAGjC;AAAoB;AAEhB;AAEA;AACE;AAAA;AAGF;AACE;AAAyB;AAC3B;AACF;AACuC;AAGzC;AAAmB;AAEf;AAEA;AACE;AAAA;AAGF;AAAuC;AACL;AAGlC;AACE;AAAwB;AAC1B;AACF;AAC0B;AAG5B;AAA0B;AAEtB;AAEA;AACE;AAAyB;AAC3B;AACF;AAC8B;AAGhC;AAA6B;AAEzB;AAEA;AACE;AAAA;AAGF;AAEA;AACE;AAAY;AACV;AACA;AACc;AACJ;AACW;AACtB;AAED;AAAc;AACZ;AACc;AACJ;AACW;AACtB;AAED;AAAa;AACG;AACd;AACA;AACqB;AACtB;AACH;AACF;AACA;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACF;AAGF;AAEI;AAAmB;AAAlB;AACmB;AAC6C;AACxD;AACH;AACC;AAC8B;AAC1B;AACD;AACe;AACvB;AACyB;AACF;AACvB;AACA;AAEA;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACe;AACU;AACV;AACf;AACA;AAAA;AACF;AAAA;AAEJ;AAGN;;"}
@@ -18,11 +18,11 @@ var overrides = require('../overrides.cjs');
18
18
  var Timestamp = require('../primitives/Timestamp.cjs');
19
19
  var shared = require('../shared.cjs');
20
20
  var cn = require('../utils/cn.cjs');
21
- var Avatar = require('./internal/Avatar.cjs');
22
21
  var Button = require('./internal/Button.cjs');
23
22
  var CodeBlock = require('./internal/CodeBlock.cjs');
24
23
  var Dropdown = require('./internal/Dropdown.cjs');
25
24
  var InboxNotificationThread$1 = require('./internal/InboxNotificationThread.cjs');
25
+ var Avatar = require('./Avatar.cjs');
26
26
  var List = require('./internal/List.cjs');
27
27
  var Room = require('./internal/Room.cjs');
28
28
  var Tooltip = require('./internal/Tooltip.cjs');
@@ -191,7 +191,7 @@ function InboxNotificationAvatar({
191
191
  ...props
192
192
  }) {
193
193
  return /* @__PURE__ */ jsxRuntime.jsx(
194
- Avatar.Avatar,
194
+ Avatar.UserAvatar,
195
195
  {
196
196
  className: cn.cn("lb-inbox-notification-avatar", className),
197
197
  ...props
@@ -1 +1 @@
1
- {"version":3,"file":"InboxNotification.cjs","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport {\n assertNever,\n generateUrl,\n sanitizeUrl,\n warnOnce,\n} from \"@liveblocks/core\";\nimport {\n useClient,\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { useRoomThreadSubscription } from \"@liveblocks/react/_private\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n InboxNotificationOverrides &\n ThreadOverrides &\n CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationInspectorProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside?: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport interface InboxNotificationAvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? SlotPrimitive.Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={cn(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-date lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n icon={<CheckIcon />}\n >\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div className={cn(\"lb-inbox-notification-icon\", className)} {...props} />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={cn(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const client = useClient();\n const thread = useInboxNotificationThread(inboxNotification.id);\n const {\n status: subscriptionStatus,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const currentUserId = useCurrentUserId();\n const { info } = useRoomInfo(inboxNotification.roomId);\n const contents = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n client,\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n if (contents.comments.length === 0 || contents.userIds.length === 0) {\n return null;\n }\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0]!;\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId) => (\n <User key={userId} userId={userId} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n locale={$.locale}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1]!.id,\n };\n }\n\n case \"mention\": {\n const mentionCreatedBy = contents.userIds[0]!;\n const mentionComment = contents.comments[0]!;\n\n const aside = <InboxNotificationAvatar userId={mentionCreatedBy} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionCreatedBy} userId={mentionCreatedBy} />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n client,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? // Set the comment ID as the URL hash.\n generateUrl(resolvedHref, undefined, contents?.commentId)\n : undefined;\n }, [contents?.commentId, href, info?.url]);\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n if (!contents) {\n return null;\n }\n\n const { aside, title, content, date, unread } = contents;\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n additionalDropdownItemsBefore={\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n }\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n href,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n const { info } = useRoomInfo(inboxNotification.roomId);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? (sanitizeUrl(resolvedHref) ?? undefined)\n : undefined;\n }, [href, info?.url]);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n href={resolvedHref}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationInspector = forwardRef<\n HTMLAnchorElement,\n InboxNotificationInspectorProps\n>(\n (\n { inboxNotification, showActions = \"hover\", overrides, ...props },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n title={<code>{inboxNotification.id}</code>}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n data-inspector=\"\"\n >\n <CodeBlock\n title=\"Data\"\n code={JSON.stringify(inboxNotification, null, 2)}\n />\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered, learn more\n in the console.\n </InboxNotificationCustom>\n );\n});\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(\n `Custom notification kind \"${inboxNotification.kind}\" is not handled so notifications of this kind will not be displayed in production. Use the kinds prop to define how they should be rendered. Learn more: https://liveblocks.io/docs/api-reference/liveblocks-react-ui#Rendering-notification-kinds-differently.`\n );\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n /**\n * Displays a thread inbox notification kind.\n */\n Thread: InboxNotificationThread,\n\n /**\n * Displays a text mention inbox notification kind.\n */\n TextMention: InboxNotificationTextMention,\n\n /**\n * Displays a custom inbox notification kind.\n */\n Custom: InboxNotificationCustom,\n\n /**\n * Display the inbox notification's data, which can be useful during development.\n *\n * @example\n * <InboxNotification\n * inboxNotification={inboxNotification}\n * kinds={{\n * $custom: InboxNotification.Inspector,\n * }}\n * />\n */\n Inspector: InboxNotificationInspector,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2PA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEI;AAAC;AAAA;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEJ;AAA6D;AAE5D;AACE;AAAqD;AAGjD;AAAA;AAAC;AAAA;AACW;AACV;AACU;AAAA;AACZ;AAEE;AAAC;AAAA;AACW;AACL;AAAA;AACP;AAGN;AAGI;AAAC;AAAA;AACO;AACQ;AACR;AAGD;AAAA;AAEC;AAAC;AAAA;AACW;AACD;AACQ;AAEd;AAAA;AAEH;AACJ;AAAC;AAAA;AACW;AACD;AACS;AAEf;AAAA;AACL;AACC;AACH;AAKE;AAAC;AAAA;AACW;AACD;AACM;AACF;AACC;AACM;AAAA;AAG1B;AAAA;AAEJ;AAEJ;AACsD;AACxD;AAAA;AAAA;AAEJ;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AAGF;AAEA;AAAiC;AAC/B;AAEF;AACE;AACE;AAAC;AAAA;AACwD;AACnD;AAAA;AAGV;AAEA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AACA;AAAM;AACI;AACR;AACA;AAEF;AACA;AACA;AACE;AAAiB;AACf;AACA;AACA;AACiB;AAGnB;AACE;AAAO;AAGT;AAAuB;AAEnB;AACA;AAEA;AACA;AAAgB;AACd;AAAC;AAAA;AAGE;AACkB;AACgC;AACzC;AAAA;AACZ;AACiD;AACjC;AAElB;AAGM;AAAC;AAAA;AAEC;AACuC;AACvC;AACA;AACA;AAAA;AALa;AAWrB;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC2C;AAC9D;AACF;AAGE;AACA;AAEA;AACA;AAAgB;AACyC;AACN;AAEnD;AAEI;AAAC;AAAA;AAEU;AACG;AACZ;AACA;AACA;AAAA;AALoB;AAU1B;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGF;AACE;AAEA;AAAO;AAAA;AAEqD;AACxD;AAGN;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACE;AAAsB;AAGxB;AACE;AAAO;AAGT;AAEA;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AAEjB;AAAC;AAAA;AACW;AACD;AAKK;AAMR;AAAA;AACR;AAEE;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACA;AACG;AAIL;AACA;AAEA;AACE;AAEA;AAEI;AAGN;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACqE;AAC5D;AACP;AAAC;AAAA;AAE2B;AAAA;AADH;AAEzB;AAC4D;AAC9D;AACwB;AACxB;AACA;AACA;AACM;AACF;AACJ;AAAA;AACF;AAGN;AAEA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAmC;AAQ/B;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACmC;AACX;AACxB;AACA;AACA;AACI;AACC;AACU;AAEf;AAAC;AAAA;AACO;AACyC;AAAA;AACjD;AAAA;AACF;AAGN;AAEA;AAIE;AACE;AAAC;AAAA;AACC;AACI;AAEA;AAAA;AACuD;AAAO;AAEhE;AAKA;AAEG;AACQ;AACd;AAAA;AACsE;AAC1D;AAAO;AAAA;AAAA;AAIxB;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AAAA;AACqD;AAGrD;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAIF;AAAO;AACT;AAGF;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AACF;AACF;AACF;AACA;AAAA;AAAA;AAAA;AAIU;AAAA;AAAA;AAAA;AAKK;AAAA;AAAA;AAAA;AAKL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaG;AACL;AACE;AAEZ;;"}
1
+ {"version":3,"file":"InboxNotification.cjs","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport {\n assertNever,\n generateUrl,\n sanitizeUrl,\n warnOnce,\n} from \"@liveblocks/core\";\nimport {\n useClient,\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { useRoomThreadSubscription } from \"@liveblocks/react/_private\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./internal/Button\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { UserAvatar } from \"./Avatar\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n InboxNotificationOverrides &\n ThreadOverrides &\n CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationInspectorProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside?: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport interface InboxNotificationAvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? SlotPrimitive.Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={cn(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-date lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n icon={<CheckIcon />}\n >\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div className={cn(\"lb-inbox-notification-icon\", className)} {...props} />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <UserAvatar\n className={cn(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const client = useClient();\n const thread = useInboxNotificationThread(inboxNotification.id);\n const {\n status: subscriptionStatus,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const currentUserId = useCurrentUserId();\n const { info } = useRoomInfo(inboxNotification.roomId);\n const contents = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n client,\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n if (contents.comments.length === 0 || contents.userIds.length === 0) {\n return null;\n }\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0]!;\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId) => (\n <User key={userId} userId={userId} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n locale={$.locale}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1]!.id,\n };\n }\n\n case \"mention\": {\n const mentionCreatedBy = contents.userIds[0]!;\n const mentionComment = contents.comments[0]!;\n\n const aside = <InboxNotificationAvatar userId={mentionCreatedBy} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionCreatedBy} userId={mentionCreatedBy} />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n client,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? // Set the comment ID as the URL hash.\n generateUrl(resolvedHref, undefined, contents?.commentId)\n : undefined;\n }, [contents?.commentId, href, info?.url]);\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n if (!contents) {\n return null;\n }\n\n const { aside, title, content, date, unread } = contents;\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n additionalDropdownItemsBefore={\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n }\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n href,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n const { info } = useRoomInfo(inboxNotification.roomId);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? (sanitizeUrl(resolvedHref) ?? undefined)\n : undefined;\n }, [href, info?.url]);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n href={resolvedHref}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationInspector = forwardRef<\n HTMLAnchorElement,\n InboxNotificationInspectorProps\n>(\n (\n { inboxNotification, showActions = \"hover\", overrides, ...props },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n title={<code>{inboxNotification.id}</code>}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n data-inspector=\"\"\n >\n <CodeBlock\n title=\"Data\"\n code={JSON.stringify(inboxNotification, null, 2)}\n />\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered, learn more\n in the console.\n </InboxNotificationCustom>\n );\n});\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(\n `Custom notification kind \"${inboxNotification.kind}\" is not handled so notifications of this kind will not be displayed in production. Use the kinds prop to define how they should be rendered. Learn more: https://liveblocks.io/docs/api-reference/liveblocks-react-ui#Rendering-notification-kinds-differently.`\n );\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n /**\n * Displays a thread inbox notification kind.\n */\n Thread: InboxNotificationThread,\n\n /**\n * Displays a text mention inbox notification kind.\n */\n TextMention: InboxNotificationTextMention,\n\n /**\n * Displays a custom inbox notification kind.\n */\n Custom: InboxNotificationCustom,\n\n /**\n * Display the inbox notification's data, which can be useful during development.\n *\n * @example\n * <InboxNotification\n * inboxNotification={inboxNotification}\n * kinds={{\n * $custom: InboxNotification.Inspector,\n * }}\n * />\n */\n Inspector: InboxNotificationInspector,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2PA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEI;AAAC;AAAA;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEJ;AAA6D;AAE5D;AACE;AAAqD;AAGjD;AAAA;AAAC;AAAA;AACW;AACV;AACU;AAAA;AACZ;AAEE;AAAC;AAAA;AACW;AACL;AAAA;AACP;AAGN;AAGI;AAAC;AAAA;AACO;AACQ;AACR;AAGD;AAAA;AAEC;AAAC;AAAA;AACW;AACD;AACQ;AAEd;AAAA;AAEH;AACJ;AAAC;AAAA;AACW;AACD;AACS;AAEf;AAAA;AACL;AACC;AACH;AAKE;AAAC;AAAA;AACW;AACD;AACM;AACF;AACC;AACM;AAAA;AAG1B;AAAA;AAEJ;AAEJ;AACsD;AACxD;AAAA;AAAA;AAEJ;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AAGF;AAEA;AAAiC;AAC/B;AAEF;AACE;AACE;AAAC;AAAA;AACwD;AACnD;AAAA;AAGV;AAEA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AACA;AAAM;AACI;AACR;AACA;AAEF;AACA;AACA;AACE;AAAiB;AACf;AACA;AACA;AACiB;AAGnB;AACE;AAAO;AAGT;AAAuB;AAEnB;AACA;AAEA;AACA;AAAgB;AACd;AAAC;AAAA;AAGE;AACkB;AACgC;AACzC;AAAA;AACZ;AACiD;AACjC;AAElB;AAGM;AAAC;AAAA;AAEC;AACuC;AACvC;AACA;AACA;AAAA;AALa;AAWrB;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC2C;AAC9D;AACF;AAGE;AACA;AAEA;AACA;AAAgB;AACyC;AACN;AAEnD;AAEI;AAAC;AAAA;AAEU;AACG;AACZ;AACA;AACA;AAAA;AALoB;AAU1B;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGF;AACE;AAEA;AAAO;AAAA;AAEqD;AACxD;AAGN;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACE;AAAsB;AAGxB;AACE;AAAO;AAGT;AAEA;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AAEjB;AAAC;AAAA;AACW;AACD;AAKK;AAMR;AAAA;AACR;AAEE;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACA;AACG;AAIL;AACA;AAEA;AACE;AAEA;AAEI;AAGN;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACqE;AAC5D;AACP;AAAC;AAAA;AAE2B;AAAA;AADH;AAEzB;AAC4D;AAC9D;AACwB;AACxB;AACA;AACA;AACM;AACF;AACJ;AAAA;AACF;AAGN;AAEA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAmC;AAQ/B;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACmC;AACX;AACxB;AACA;AACA;AACI;AACC;AACU;AAEf;AAAC;AAAA;AACO;AACyC;AAAA;AACjD;AAAA;AACF;AAGN;AAEA;AAIE;AACE;AAAC;AAAA;AACC;AACI;AAEA;AAAA;AACuD;AAAO;AAEhE;AAKA;AAEG;AACQ;AACd;AAAA;AACsE;AAC1D;AAAO;AAAA;AAAA;AAIxB;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AAAA;AACqD;AAGrD;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAIF;AAAO;AACT;AAGF;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AACF;AACF;AACF;AACA;AAAA;AAAA;AAAA;AAIU;AAAA;AAAA;AAAA;AAKK;AAAA;AAAA;AAAA;AAKL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaG;AACL;AACE;AAEZ;;"}
@@ -16,11 +16,11 @@ import { useOverrides } from '../overrides.js';
16
16
  import { Timestamp } from '../primitives/Timestamp.js';
17
17
  import { useCurrentUserId } from '../shared.js';
18
18
  import { cn } from '../utils/cn.js';
19
- import { Avatar } from './internal/Avatar.js';
20
19
  import { Button } from './internal/Button.js';
21
20
  import { CodeBlock } from './internal/CodeBlock.js';
22
21
  import { Dropdown, DropdownItem, DropdownTrigger } from './internal/Dropdown.js';
23
22
  import { generateInboxNotificationThreadContents, InboxNotificationComment, INBOX_NOTIFICATION_THREAD_MAX_COMMENTS } from './internal/InboxNotificationThread.js';
23
+ import { UserAvatar } from './Avatar.js';
24
24
  import { List } from './internal/List.js';
25
25
  import { Room } from './internal/Room.js';
26
26
  import { TooltipProvider, Tooltip } from './internal/Tooltip.js';
@@ -189,7 +189,7 @@ function InboxNotificationAvatar({
189
189
  ...props
190
190
  }) {
191
191
  return /* @__PURE__ */ jsx(
192
- Avatar,
192
+ UserAvatar,
193
193
  {
194
194
  className: cn("lb-inbox-notification-avatar", className),
195
195
  ...props
@@ -1 +1 @@
1
- {"version":3,"file":"InboxNotification.js","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport {\n assertNever,\n generateUrl,\n sanitizeUrl,\n warnOnce,\n} from \"@liveblocks/core\";\nimport {\n useClient,\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { useRoomThreadSubscription } from \"@liveblocks/react/_private\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { Avatar } from \"./internal/Avatar\";\nimport { Button } from \"./internal/Button\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n InboxNotificationOverrides &\n ThreadOverrides &\n CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationInspectorProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside?: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport interface InboxNotificationAvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? SlotPrimitive.Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={cn(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-date lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n icon={<CheckIcon />}\n >\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div className={cn(\"lb-inbox-notification-icon\", className)} {...props} />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <Avatar\n className={cn(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const client = useClient();\n const thread = useInboxNotificationThread(inboxNotification.id);\n const {\n status: subscriptionStatus,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const currentUserId = useCurrentUserId();\n const { info } = useRoomInfo(inboxNotification.roomId);\n const contents = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n client,\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n if (contents.comments.length === 0 || contents.userIds.length === 0) {\n return null;\n }\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0]!;\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId) => (\n <User key={userId} userId={userId} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n locale={$.locale}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1]!.id,\n };\n }\n\n case \"mention\": {\n const mentionCreatedBy = contents.userIds[0]!;\n const mentionComment = contents.comments[0]!;\n\n const aside = <InboxNotificationAvatar userId={mentionCreatedBy} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionCreatedBy} userId={mentionCreatedBy} />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n client,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? // Set the comment ID as the URL hash.\n generateUrl(resolvedHref, undefined, contents?.commentId)\n : undefined;\n }, [contents?.commentId, href, info?.url]);\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n if (!contents) {\n return null;\n }\n\n const { aside, title, content, date, unread } = contents;\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n additionalDropdownItemsBefore={\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n }\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n href,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n const { info } = useRoomInfo(inboxNotification.roomId);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? (sanitizeUrl(resolvedHref) ?? undefined)\n : undefined;\n }, [href, info?.url]);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n href={resolvedHref}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationInspector = forwardRef<\n HTMLAnchorElement,\n InboxNotificationInspectorProps\n>(\n (\n { inboxNotification, showActions = \"hover\", overrides, ...props },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n title={<code>{inboxNotification.id}</code>}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n data-inspector=\"\"\n >\n <CodeBlock\n title=\"Data\"\n code={JSON.stringify(inboxNotification, null, 2)}\n />\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered, learn more\n in the console.\n </InboxNotificationCustom>\n );\n});\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(\n `Custom notification kind \"${inboxNotification.kind}\" is not handled so notifications of this kind will not be displayed in production. Use the kinds prop to define how they should be rendered. Learn more: https://liveblocks.io/docs/api-reference/liveblocks-react-ui#Rendering-notification-kinds-differently.`\n );\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n /**\n * Displays a thread inbox notification kind.\n */\n Thread: InboxNotificationThread,\n\n /**\n * Displays a text mention inbox notification kind.\n */\n TextMention: InboxNotificationTextMention,\n\n /**\n * Displays a custom inbox notification kind.\n */\n Custom: InboxNotificationCustom,\n\n /**\n * Display the inbox notification's data, which can be useful during development.\n *\n * @example\n * <InboxNotification\n * inboxNotification={inboxNotification}\n * kinds={{\n * $custom: InboxNotification.Inspector,\n * }}\n * />\n */\n Inspector: InboxNotificationInspector,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2PA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEI;AAAC;AAAA;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEJ;AAA6D;AAE5D;AACE;AAAqD;AAGjD;AAAA;AAAC;AAAA;AACW;AACV;AACU;AAAA;AACZ;AAEE;AAAC;AAAA;AACW;AACL;AAAA;AACP;AAGN;AAGI;AAAC;AAAA;AACO;AACQ;AACR;AAGD;AAAA;AAEC;AAAC;AAAA;AACW;AACD;AACQ;AAEd;AAAA;AAEH;AACJ;AAAC;AAAA;AACW;AACD;AACS;AAEf;AAAA;AACL;AACC;AACH;AAKE;AAAC;AAAA;AACW;AACD;AACM;AACF;AACC;AACM;AAAA;AAG1B;AAAA;AAEJ;AAEJ;AACsD;AACxD;AAAA;AAAA;AAEJ;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AAGF;AAEA;AAAiC;AAC/B;AAEF;AACE;AACE;AAAC;AAAA;AACwD;AACnD;AAAA;AAGV;AAEA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AACA;AAAM;AACI;AACR;AACA;AAEF;AACA;AACA;AACE;AAAiB;AACf;AACA;AACA;AACiB;AAGnB;AACE;AAAO;AAGT;AAAuB;AAEnB;AACA;AAEA;AACA;AAAgB;AACd;AAAC;AAAA;AAGE;AACkB;AACgC;AACzC;AAAA;AACZ;AACiD;AACjC;AAElB;AAGM;AAAC;AAAA;AAEC;AACuC;AACvC;AACA;AACA;AAAA;AALa;AAWrB;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC2C;AAC9D;AACF;AAGE;AACA;AAEA;AACA;AAAgB;AACyC;AACN;AAEnD;AAEI;AAAC;AAAA;AAEU;AACG;AACZ;AACA;AACA;AAAA;AALoB;AAU1B;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGF;AACE;AAEA;AAAO;AAAA;AAEqD;AACxD;AAGN;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACE;AAAsB;AAGxB;AACE;AAAO;AAGT;AAEA;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AAEjB;AAAC;AAAA;AACW;AACD;AAKK;AAMR;AAAA;AACR;AAEE;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACA;AACG;AAIL;AACA;AAEA;AACE;AAEA;AAEI;AAGN;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACqE;AAC5D;AACP;AAAC;AAAA;AAE2B;AAAA;AADH;AAEzB;AAC4D;AAC9D;AACwB;AACxB;AACA;AACA;AACM;AACF;AACJ;AAAA;AACF;AAGN;AAEA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAmC;AAQ/B;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACmC;AACX;AACxB;AACA;AACA;AACI;AACC;AACU;AAEf;AAAC;AAAA;AACO;AACyC;AAAA;AACjD;AAAA;AACF;AAGN;AAEA;AAIE;AACE;AAAC;AAAA;AACC;AACI;AAEA;AAAA;AACuD;AAAO;AAEhE;AAKA;AAEG;AACQ;AACd;AAAA;AACsE;AAC1D;AAAO;AAAA;AAAA;AAIxB;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AAAA;AACqD;AAGrD;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAIF;AAAO;AACT;AAGF;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AACF;AACF;AACF;AACA;AAAA;AAAA;AAAA;AAIU;AAAA;AAAA;AAAA;AAKK;AAAA;AAAA;AAAA;AAKL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaG;AACL;AACE;AAEZ;;"}
1
+ {"version":3,"file":"InboxNotification.js","sources":["../../src/components/InboxNotification.tsx"],"sourcesContent":["\"use client\";\n\nimport type {\n InboxNotificationCustomData,\n InboxNotificationData,\n InboxNotificationTextMentionData,\n InboxNotificationThreadData,\n KDAD,\n} from \"@liveblocks/core\";\nimport {\n assertNever,\n generateUrl,\n sanitizeUrl,\n warnOnce,\n} from \"@liveblocks/core\";\nimport {\n useClient,\n useDeleteInboxNotification,\n useInboxNotificationThread,\n useMarkInboxNotificationAsRead,\n useRoomInfo,\n} from \"@liveblocks/react\";\nimport { useRoomThreadSubscription } from \"@liveblocks/react/_private\";\nimport { Slot as SlotPrimitive } from \"radix-ui\";\nimport type {\n ComponentProps,\n ComponentPropsWithoutRef,\n ComponentType,\n MouseEvent as ReactMouseEvent,\n ReactNode,\n SyntheticEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useMemo, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { useComponents } from \"../components\";\nimport { BellIcon } from \"../icons/Bell\";\nimport { BellCrossedIcon } from \"../icons/BellCrossed\";\nimport { CheckIcon } from \"../icons/Check\";\nimport { DeleteIcon } from \"../icons/Delete\";\nimport { EllipsisIcon } from \"../icons/Ellipsis\";\nimport { WarningIcon } from \"../icons/Warning\";\nimport type {\n CommentOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n ThreadOverrides,\n} from \"../overrides\";\nimport { useOverrides } from \"../overrides\";\nimport { Timestamp } from \"../primitives/Timestamp\";\nimport { useCurrentUserId } from \"../shared\";\nimport type { SlotProp } from \"../types\";\nimport { cn } from \"../utils/cn\";\nimport { Button } from \"./internal/Button\";\nimport { CodeBlock } from \"./internal/CodeBlock\";\nimport { Dropdown, DropdownItem, DropdownTrigger } from \"./internal/Dropdown\";\nimport {\n generateInboxNotificationThreadContents,\n INBOX_NOTIFICATION_THREAD_MAX_COMMENTS,\n InboxNotificationComment,\n} from \"./internal/InboxNotificationThread\";\nimport { UserAvatar } from \"./Avatar\";\nimport { List } from \"./internal/List\";\nimport { Room } from \"./internal/Room\";\nimport { Tooltip, TooltipProvider } from \"./internal/Tooltip\";\nimport { User } from \"./internal/User\";\n\ntype ComponentTypeWithRef<\n T extends keyof JSX.IntrinsicElements,\n P,\n> = ComponentType<P & Pick<ComponentProps<T>, \"ref\">>;\n\ntype InboxNotificationKinds<KS extends KDAD = KDAD> = {\n // For some reason, we cannot directly use KDAD in the mapped type line\n // below, because it will result in '{}' rather than picking up the\n // definition from the user-provided 'ActivitiesData'. Might be an internal\n // TS optimization, so we're making it a param to defer the resolution.\n [K in KS]: ComponentTypeWithRef<\"a\", InboxNotificationCustomKindProps<K>>;\n} & {\n thread: ComponentTypeWithRef<\"a\", InboxNotificationThreadKindProps>;\n textMention: ComponentTypeWithRef<\"a\", InboxNotificationTextMentionKindProps>;\n};\n\ninterface InboxNotificationSharedProps {\n /**\n * How to show or hide the actions.\n */\n showActions?: boolean | \"hover\";\n}\n\nexport interface InboxNotificationProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n\n /**\n * Override specific kinds of inbox notifications.\n */\n kinds?: Partial<InboxNotificationKinds>;\n\n /**\n * Override the component's strings.\n */\n overrides?: Partial<\n GlobalOverrides &\n InboxNotificationOverrides &\n ThreadOverrides &\n CommentOverrides\n >;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents>;\n}\n\nexport interface InboxNotificationThreadProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationThreadData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n\n /**\n * Whether to show reactions.\n */\n showReactions?: boolean;\n\n /**\n * Whether to show attachments.\n */\n showAttachments?: boolean;\n}\n\nexport interface InboxNotificationTextMentionProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationTextMentionData;\n\n /**\n * Whether to show the room name in the title.\n */\n showRoomName?: boolean;\n}\n\nexport interface InboxNotificationInspectorProps\n extends Omit<InboxNotificationProps, \"kinds\" | \"children\">,\n InboxNotificationSharedProps {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationData;\n}\n\nexport interface InboxNotificationCustomProps\n extends Omit<InboxNotificationProps, \"kinds\">,\n InboxNotificationSharedProps,\n SlotProp {\n /**\n * The inbox notification to display.\n */\n inboxNotification: InboxNotificationCustomData;\n\n /**\n * The inbox notification's content.\n */\n children: ReactNode;\n\n /**\n * The inbox notification's title.\n */\n title: ReactNode;\n\n /**\n * The inbox notification's aside content.\n * Can be combined with `InboxNotification.Icon` or `InboxNotification.Avatar` to easily follow default styles.\n */\n aside?: ReactNode;\n\n /**\n * Whether to mark the inbox notification as read when clicked.\n */\n markAsReadOnClick?: boolean;\n}\n\nexport type InboxNotificationThreadKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationThreadData;\n};\n\nexport type InboxNotificationTextMentionKindProps = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationTextMentionData;\n};\n\nexport type InboxNotificationCustomKindProps<K extends KDAD = KDAD> = Omit<\n InboxNotificationProps,\n \"kinds\"\n> & {\n inboxNotification: InboxNotificationCustomData<K>;\n};\n\ninterface InboxNotificationLayoutProps\n extends Omit<ComponentPropsWithoutRef<\"a\">, \"title\">,\n InboxNotificationSharedProps,\n SlotProp {\n inboxNotification: InboxNotificationData;\n aside?: ReactNode;\n title: ReactNode;\n date: Date | string | number;\n unread?: boolean;\n overrides?: Partial<GlobalOverrides & InboxNotificationOverrides>;\n components?: Partial<GlobalComponents>;\n markAsReadOnClick?: boolean;\n\n /**\n * @internal\n */\n additionalDropdownItemsBefore?: ReactNode;\n\n /**\n * @internal\n */\n additionalDropdownItemsAfter?: ReactNode;\n}\n\nexport type InboxNotificationIconProps = ComponentProps<\"div\">;\n\nexport interface InboxNotificationAvatarProps extends ComponentProps<\"div\"> {\n /**\n * The user ID to display the avatar for.\n */\n userId: string;\n}\n\nconst InboxNotificationLayout = forwardRef<\n HTMLAnchorElement,\n InboxNotificationLayoutProps\n>(\n (\n {\n inboxNotification,\n children,\n aside,\n title,\n date,\n unread,\n markAsReadOnClick,\n onClick,\n href,\n showActions,\n overrides,\n components,\n className,\n asChild,\n additionalDropdownItemsBefore,\n additionalDropdownItemsAfter,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const { Anchor } = useComponents(components);\n const Component = asChild ? SlotPrimitive.Slot : Anchor;\n const [isMoreActionOpen, setMoreActionOpen] = useState(false);\n const markInboxNotificationAsRead = useMarkInboxNotificationAsRead();\n const deleteInboxNotification = useDeleteInboxNotification();\n\n const handleClick = useCallback(\n (event: ReactMouseEvent<HTMLAnchorElement, MouseEvent>) => {\n onClick?.(event);\n\n const shouldMarkAsReadOnClick = markAsReadOnClick ?? Boolean(href);\n\n if (unread && shouldMarkAsReadOnClick) {\n markInboxNotificationAsRead(inboxNotification.id);\n }\n },\n [\n href,\n inboxNotification.id,\n markAsReadOnClick,\n markInboxNotificationAsRead,\n onClick,\n unread,\n ]\n );\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n const preventDefaultAndStopPropagation = useCallback(\n (event: SyntheticEvent) => {\n event.preventDefault();\n event.stopPropagation();\n },\n []\n );\n\n const handleMoreClick = useCallback((event: ReactMouseEvent) => {\n event.preventDefault();\n event.stopPropagation();\n setMoreActionOpen((open) => !open);\n }, []);\n\n const handleMarkAsRead = useCallback(() => {\n markInboxNotificationAsRead(inboxNotification.id);\n }, [inboxNotification.id, markInboxNotificationAsRead]);\n\n const handleDelete = useCallback(() => {\n deleteInboxNotification(inboxNotification.id);\n }, [inboxNotification.id, deleteInboxNotification]);\n\n return (\n <TooltipProvider>\n <Component\n className={cn(\n \"lb-root lb-inbox-notification\",\n showActions === \"hover\" &&\n \"lb-inbox-notification:show-actions-hover\",\n isMoreActionOpen && \"lb-inbox-notification:action-open\",\n className\n )}\n dir={$.dir}\n data-unread={unread ? \"\" : undefined}\n data-kind={inboxNotification.kind}\n onClick={handleClick}\n href={href}\n {...props}\n ref={forwardedRef}\n >\n {aside && <div className=\"lb-inbox-notification-aside\">{aside}</div>}\n <div className=\"lb-inbox-notification-content\">\n <div className=\"lb-inbox-notification-header\">\n <span className=\"lb-inbox-notification-title\">{title}</span>\n <div className=\"lb-inbox-notification-details\">\n <span className=\"lb-inbox-notification-details-labels\">\n <Timestamp\n locale={$.locale}\n date={date}\n className=\"lb-date lb-inbox-notification-date\"\n />\n {unread && (\n <span\n className=\"lb-inbox-notification-unread-indicator\"\n role=\"presentation\"\n />\n )}\n </span>\n </div>\n {showActions && (\n <div className=\"lb-inbox-notification-actions\">\n <Dropdown\n open={isMoreActionOpen}\n onOpenChange={setMoreActionOpen}\n align=\"end\"\n content={\n <>\n {additionalDropdownItemsBefore}\n {unread ? (\n <DropdownItem\n onSelect={handleMarkAsRead}\n onClick={stopPropagation}\n icon={<CheckIcon />}\n >\n {$.INBOX_NOTIFICATION_MARK_AS_READ}\n </DropdownItem>\n ) : null}\n <DropdownItem\n onSelect={handleDelete}\n onClick={stopPropagation}\n icon={<DeleteIcon />}\n >\n {$.INBOX_NOTIFICATION_DELETE}\n </DropdownItem>\n {additionalDropdownItemsAfter}\n </>\n }\n >\n <Tooltip content={$.INBOX_NOTIFICATION_MORE}>\n <DropdownTrigger asChild>\n <Button\n className=\"lb-inbox-notification-action\"\n onClick={handleMoreClick}\n onPointerDown={preventDefaultAndStopPropagation}\n onPointerUp={preventDefaultAndStopPropagation}\n aria-label={$.INBOX_NOTIFICATION_MORE}\n icon={<EllipsisIcon />}\n />\n </DropdownTrigger>\n </Tooltip>\n </Dropdown>\n </div>\n )}\n </div>\n <div className=\"lb-inbox-notification-body\">{children}</div>\n </div>\n </Component>\n </TooltipProvider>\n );\n }\n);\n\nfunction InboxNotificationIcon({\n className,\n ...props\n}: InboxNotificationIconProps) {\n return (\n <div className={cn(\"lb-inbox-notification-icon\", className)} {...props} />\n );\n}\n\nfunction InboxNotificationAvatar({\n className,\n ...props\n}: InboxNotificationAvatarProps) {\n return (\n <UserAvatar\n className={cn(\"lb-inbox-notification-avatar\", className)}\n {...props}\n />\n );\n}\n\nconst InboxNotificationThread = forwardRef<\n HTMLAnchorElement,\n InboxNotificationThreadProps\n>(\n (\n {\n inboxNotification,\n href,\n showRoomName = true,\n showReactions = true,\n showAttachments = true,\n showActions = \"hover\",\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const $ = useOverrides(overrides);\n const client = useClient();\n const thread = useInboxNotificationThread(inboxNotification.id);\n const {\n status: subscriptionStatus,\n subscribe,\n unsubscribe,\n } = useRoomThreadSubscription(thread.roomId, thread.id);\n const currentUserId = useCurrentUserId();\n const { info } = useRoomInfo(inboxNotification.roomId);\n const contents = useMemo(() => {\n const contents = generateInboxNotificationThreadContents(\n client,\n inboxNotification,\n thread,\n currentUserId ?? \"\"\n );\n\n if (contents.comments.length === 0 || contents.userIds.length === 0) {\n return null;\n }\n\n switch (contents.type) {\n case \"comments\": {\n const reversedUserIds = [...contents.userIds].reverse();\n const firstUserId = reversedUserIds[0]!;\n\n const aside = <InboxNotificationAvatar userId={firstUserId} />;\n const title = $.INBOX_NOTIFICATION_THREAD_COMMENTS_LIST(\n <List\n values={reversedUserIds.map((userId) => (\n <User key={userId} userId={userId} replaceSelf />\n ))}\n formatRemaining={$.LIST_REMAINING_USERS}\n truncate={INBOX_NOTIFICATION_THREAD_MAX_COMMENTS - 1}\n locale={$.locale}\n />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined,\n reversedUserIds.length\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n {contents.comments.map((comment) => (\n <InboxNotificationComment\n key={comment.id}\n comment={comment}\n showHeader={contents.comments.length > 1}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n ))}\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: contents.comments[contents.comments.length - 1]!.id,\n };\n }\n\n case \"mention\": {\n const mentionCreatedBy = contents.userIds[0]!;\n const mentionComment = contents.comments[0]!;\n\n const aside = <InboxNotificationAvatar userId={mentionCreatedBy} />;\n const title = $.INBOX_NOTIFICATION_THREAD_MENTION(\n <User key={mentionCreatedBy} userId={mentionCreatedBy} />,\n showRoomName ? <Room roomId={thread.roomId} /> : undefined\n );\n const content = (\n <div className=\"lb-inbox-notification-comments\">\n <InboxNotificationComment\n key={mentionComment.id}\n comment={mentionComment}\n showHeader={false}\n showAttachments={showAttachments}\n showReactions={showReactions}\n overrides={overrides}\n />\n </div>\n );\n\n return {\n unread: contents.unread,\n date: contents.date,\n aside,\n title,\n content,\n threadId: thread.id,\n commentId: mentionComment.id,\n };\n }\n\n default:\n return assertNever(\n contents,\n \"Unexpected thread inbox notification type\"\n );\n }\n }, [\n $,\n client,\n currentUserId,\n inboxNotification,\n overrides,\n showRoomName,\n showAttachments,\n showReactions,\n thread,\n ]);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? // Set the comment ID as the URL hash.\n generateUrl(resolvedHref, undefined, contents?.commentId)\n : undefined;\n }, [contents?.commentId, href, info?.url]);\n\n const handleSubscribeChange = useCallback(() => {\n if (subscriptionStatus === \"subscribed\") {\n unsubscribe();\n } else {\n subscribe();\n }\n }, [subscriptionStatus, subscribe, unsubscribe]);\n\n const stopPropagation = useCallback((event: SyntheticEvent) => {\n event.stopPropagation();\n }, []);\n\n if (!contents) {\n return null;\n }\n\n const { aside, title, content, date, unread } = contents;\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={date}\n unread={unread}\n overrides={overrides}\n href={resolvedHref}\n showActions={showActions}\n markAsReadOnClick={false}\n additionalDropdownItemsBefore={\n <DropdownItem\n onSelect={handleSubscribeChange}\n onClick={stopPropagation}\n icon={\n subscriptionStatus === \"subscribed\" ? (\n <BellCrossedIcon />\n ) : (\n <BellIcon />\n )\n }\n >\n {subscriptionStatus === \"subscribed\"\n ? $.THREAD_UNSUBSCRIBE\n : $.THREAD_SUBSCRIBE}\n </DropdownItem>\n }\n {...props}\n ref={forwardedRef}\n >\n {content}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationTextMention = forwardRef<\n HTMLAnchorElement,\n InboxNotificationTextMentionProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n showRoomName = true,\n href,\n overrides,\n ...props\n },\n ref\n ) => {\n const $ = useOverrides(overrides);\n const { info } = useRoomInfo(inboxNotification.roomId);\n // Use URL from `resolveRoomsInfo` if `href` isn't set.\n const resolvedHref = useMemo(() => {\n const resolvedHref = href ?? info?.url;\n\n return resolvedHref\n ? (sanitizeUrl(resolvedHref) ?? undefined)\n : undefined;\n }, [href, info?.url]);\n\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={<InboxNotificationAvatar userId={inboxNotification.createdBy} />}\n title={$.INBOX_NOTIFICATION_TEXT_MENTION(\n <User\n key={inboxNotification.createdBy}\n userId={inboxNotification.createdBy}\n />,\n showRoomName ? <Room roomId={inboxNotification.roomId} /> : undefined\n )}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n href={resolvedHref}\n {...props}\n ref={ref}\n />\n );\n }\n);\n\nconst InboxNotificationCustom = forwardRef<\n HTMLAnchorElement,\n InboxNotificationCustomProps\n>(\n (\n {\n inboxNotification,\n showActions = \"hover\",\n title,\n aside,\n children,\n overrides,\n ...props\n },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n aside={aside}\n title={title}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n >\n {children}\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationInspector = forwardRef<\n HTMLAnchorElement,\n InboxNotificationInspectorProps\n>(\n (\n { inboxNotification, showActions = \"hover\", overrides, ...props },\n forwardedRef\n ) => {\n const unread = useMemo(() => {\n return (\n !inboxNotification.readAt ||\n inboxNotification.notifiedAt > inboxNotification.readAt\n );\n }, [inboxNotification.notifiedAt, inboxNotification.readAt]);\n\n return (\n <InboxNotificationLayout\n inboxNotification={inboxNotification}\n title={<code>{inboxNotification.id}</code>}\n date={inboxNotification.notifiedAt}\n unread={unread}\n overrides={overrides}\n showActions={showActions}\n {...props}\n ref={forwardedRef}\n data-inspector=\"\"\n >\n <CodeBlock\n title=\"Data\"\n code={JSON.stringify(inboxNotification, null, 2)}\n />\n </InboxNotificationLayout>\n );\n }\n);\n\nconst InboxNotificationCustomMissing = forwardRef<\n HTMLAnchorElement,\n Omit<InboxNotificationCustomProps, \"children\" | \"title\" | \"aside\">\n>(({ inboxNotification, ...props }, forwardedRef) => {\n return (\n <InboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n title={\n <>\n Custom notification kind <code>{inboxNotification.kind}</code> is not\n handled\n </>\n }\n aside={\n <InboxNotificationIcon>\n <WarningIcon />\n </InboxNotificationIcon>\n }\n ref={forwardedRef}\n data-missing=\"\"\n >\n Notifications of this kind won’t be displayed in production. Use the{\" \"}\n <code>kinds</code> prop to define how they should be rendered, learn more\n in the console.\n </InboxNotificationCustom>\n );\n});\n\n/**\n * Displays a single inbox notification.\n *\n * @example\n * <>\n * {inboxNotifications.map((inboxNotification) => (\n * <InboxNotification\n * key={inboxNotification.id}\n * inboxNotification={inboxNotification}\n * href={`/rooms/${inboxNotification.roomId}`\n * />\n * ))}\n * </>\n */\nexport const InboxNotification = Object.assign(\n forwardRef<HTMLAnchorElement, InboxNotificationProps>(\n ({ inboxNotification, kinds, ...props }, forwardedRef) => {\n switch (inboxNotification.kind) {\n case \"thread\": {\n const ResolvedInboxNotificationThread =\n kinds?.thread ?? InboxNotificationThread;\n\n return (\n <ResolvedInboxNotificationThread\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n case \"textMention\": {\n const ResolvedInboxNotificationTextMention =\n kinds?.textMention ?? InboxNotificationTextMention;\n\n return (\n <ResolvedInboxNotificationTextMention\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n\n default: {\n const ResolvedInboxNotificationCustom =\n kinds?.[inboxNotification.kind];\n\n if (!ResolvedInboxNotificationCustom) {\n if (process.env.NODE_ENV !== \"production\") {\n warnOnce(\n `Custom notification kind \"${inboxNotification.kind}\" is not handled so notifications of this kind will not be displayed in production. Use the kinds prop to define how they should be rendered. Learn more: https://liveblocks.io/docs/api-reference/liveblocks-react-ui#Rendering-notification-kinds-differently.`\n );\n\n return (\n <InboxNotificationCustomMissing\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n } else {\n // Don't render anything in production if this inbox notification kind is not defined.\n return null;\n }\n }\n\n return (\n <ResolvedInboxNotificationCustom\n inboxNotification={inboxNotification}\n {...props}\n ref={forwardedRef}\n />\n );\n }\n }\n }\n ),\n {\n /**\n * Displays a thread inbox notification kind.\n */\n Thread: InboxNotificationThread,\n\n /**\n * Displays a text mention inbox notification kind.\n */\n TextMention: InboxNotificationTextMention,\n\n /**\n * Displays a custom inbox notification kind.\n */\n Custom: InboxNotificationCustom,\n\n /**\n * Display the inbox notification's data, which can be useful during development.\n *\n * @example\n * <InboxNotification\n * inboxNotification={inboxNotification}\n * kinds={{\n * $custom: InboxNotification.Inspector,\n * }}\n * />\n */\n Inspector: InboxNotificationInspector,\n Icon: InboxNotificationIcon,\n Avatar: InboxNotificationAvatar,\n }\n);\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2PA;AAAgC;AAK5B;AACE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACG;AAIL;AACA;AACA;AACA;AACA;AACA;AAEA;AAAoB;AAEhB;AAEA;AAEA;AACE;AAAgD;AAClD;AACF;AACA;AACE;AACkB;AAClB;AACA;AACA;AACA;AACF;AAGF;AACE;AAAsB;AAGxB;AAAyC;AAErC;AACA;AAAsB;AACxB;AACC;AAGH;AACE;AACA;AACA;AAAiC;AAGnC;AACE;AAAgD;AAGlD;AACE;AAA4C;AAG9C;AAEI;AAAC;AAAA;AACY;AACT;AAEE;AACkB;AACpB;AACF;AACO;AACoB;AACE;AACpB;AACT;AACI;AACC;AAEJ;AAA6D;AAE5D;AACE;AAAqD;AAGjD;AAAA;AAAC;AAAA;AACW;AACV;AACU;AAAA;AACZ;AAEE;AAAC;AAAA;AACW;AACL;AAAA;AACP;AAGN;AAGI;AAAC;AAAA;AACO;AACQ;AACR;AAGD;AAAA;AAEC;AAAC;AAAA;AACW;AACD;AACQ;AAEd;AAAA;AAEH;AACJ;AAAC;AAAA;AACW;AACD;AACS;AAEf;AAAA;AACL;AACC;AACH;AAKE;AAAC;AAAA;AACW;AACD;AACM;AACF;AACC;AACM;AAAA;AAG1B;AAAA;AAEJ;AAEJ;AACsD;AACxD;AAAA;AAAA;AAEJ;AAGN;AAEA;AAA+B;AAC7B;AAEF;AACE;AAGF;AAEA;AAAiC;AAC/B;AAEF;AACE;AACE;AAAC;AAAA;AACwD;AACnD;AAAA;AAGV;AAEA;AAAgC;AAK5B;AACE;AACA;AACe;AACC;AACE;AACJ;AACd;AACG;AAIL;AACA;AACA;AACA;AAAM;AACI;AACR;AACA;AAEF;AACA;AACA;AACE;AAAiB;AACf;AACA;AACA;AACiB;AAGnB;AACE;AAAO;AAGT;AAAuB;AAEnB;AACA;AAEA;AACA;AAAgB;AACd;AAAC;AAAA;AAGE;AACkB;AACgC;AACzC;AAAA;AACZ;AACiD;AACjC;AAElB;AAGM;AAAC;AAAA;AAEC;AACuC;AACvC;AACA;AACA;AAAA;AALa;AAWrB;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AAC2C;AAC9D;AACF;AAGE;AACA;AAEA;AACA;AAAgB;AACyC;AACN;AAEnD;AAEI;AAAC;AAAA;AAEU;AACG;AACZ;AACA;AACA;AAAA;AALoB;AAU1B;AAAO;AACY;AACF;AACf;AACA;AACA;AACiB;AACS;AAC5B;AACF;AAGE;AAAO;AACL;AACA;AACF;AACJ;AACC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGF;AACE;AAEA;AAAO;AAAA;AAEqD;AACxD;AAGN;AACE;AACE;AAAY;AAEZ;AAAU;AACZ;AAGF;AACE;AAAsB;AAGxB;AACE;AAAO;AAGT;AAEA;AACE;AAAC;AAAA;AACC;AACA;AACA;AACA;AACA;AACA;AACM;AACN;AACmB;AAEjB;AAAC;AAAA;AACW;AACD;AAKK;AAMR;AAAA;AACR;AAEE;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAqC;AAKjC;AACE;AACc;AACC;AACf;AACA;AACG;AAIL;AACA;AAEA;AACE;AAEA;AAEI;AAGN;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACqE;AAC5D;AACP;AAAC;AAAA;AAE2B;AAAA;AADH;AAEzB;AAC4D;AAC9D;AACwB;AACxB;AACA;AACA;AACM;AACF;AACJ;AAAA;AACF;AAGN;AAEA;AAAgC;AAK5B;AACE;AACc;AACd;AACA;AACA;AACA;AACG;AAIL;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACA;AACA;AACwB;AACxB;AACA;AACA;AACI;AACC;AAEJ;AAAA;AACH;AAGN;AAEA;AAAmC;AAQ/B;AACE;AAEmD;AAIrD;AACE;AAAC;AAAA;AACC;AACmC;AACX;AACxB;AACA;AACA;AACI;AACC;AACU;AAEf;AAAC;AAAA;AACO;AACyC;AAAA;AACjD;AAAA;AACF;AAGN;AAEA;AAIE;AACE;AAAC;AAAA;AACC;AACI;AAEA;AAAA;AACuD;AAAO;AAEhE;AAKA;AAEG;AACQ;AACd;AAAA;AACsE;AAC1D;AAAO;AAAA;AAAA;AAIxB;AAgBO;AAAiC;AACtC;AAEI;AAAgC;AAE5B;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AAGE;AAGA;AACE;AACE;AAAA;AACqD;AAGrD;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAIF;AAAO;AACT;AAGF;AACE;AAAC;AAAA;AACC;AACI;AACC;AAAA;AACP;AAEJ;AACF;AACF;AACF;AACA;AAAA;AAAA;AAAA;AAIU;AAAA;AAAA;AAAA;AAKK;AAAA;AAAA;AAAA;AAKL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaG;AACL;AACE;AAEZ;;"}
@@ -9,19 +9,13 @@ var shared = require('../../shared.cjs');
9
9
  var cn = require('../../utils/cn.cjs');
10
10
 
11
11
 
12
- function User({
13
- userId,
14
- replaceSelf,
12
+ function UserLayout({
13
+ isLoading,
14
+ name,
15
15
  className,
16
16
  children,
17
17
  ...props
18
18
  }) {
19
- const currentId = shared.useCurrentUserId();
20
- const { user, isLoading } = react.useUser(userId);
21
- const $ = overrides.useOverrides();
22
- const resolvedUserName = react$1.useMemo(() => {
23
- return replaceSelf && currentId === userId ? $.USER_SELF : user?.name ?? $.USER_UNKNOWN;
24
- }, [replaceSelf, currentId, userId, $.USER_SELF, $.USER_UNKNOWN, user?.name]);
25
19
  return /* @__PURE__ */ jsxRuntime.jsxs(
26
20
  "span",
27
21
  {
@@ -29,12 +23,32 @@ function User({
29
23
  "data-loading": isLoading ? "" : void 0,
30
24
  ...props,
31
25
  children: [
32
- isLoading ? null : resolvedUserName,
26
+ isLoading ? null : name,
33
27
  children
34
28
  ]
35
29
  }
36
30
  );
37
31
  }
32
+ function ResolvedUser({
33
+ userId,
34
+ replaceSelf,
35
+ ...props
36
+ }) {
37
+ const currentId = shared.useCurrentUserId();
38
+ const { user, isLoading } = react.useUser(userId);
39
+ const $ = overrides.useOverrides();
40
+ const resolvedUserName = react$1.useMemo(() => {
41
+ return replaceSelf && currentId === userId ? $.USER_SELF : user?.name ?? $.USER_UNKNOWN;
42
+ }, [replaceSelf, currentId, userId, $.USER_SELF, $.USER_UNKNOWN, user?.name]);
43
+ return /* @__PURE__ */ jsxRuntime.jsx(UserLayout, { isLoading, name: resolvedUserName, ...props });
44
+ }
45
+ function User({ userId, ...props }) {
46
+ const $ = overrides.useOverrides();
47
+ if (!userId) {
48
+ return /* @__PURE__ */ jsxRuntime.jsx(UserLayout, { isLoading: false, name: $.USER_UNKNOWN, ...props });
49
+ }
50
+ return /* @__PURE__ */ jsxRuntime.jsx(ResolvedUser, { userId, ...props });
51
+ }
38
52
 
39
53
  exports.User = User;
40
54
  //# sourceMappingURL=User.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"User.cjs","sources":["../../../src/components/internal/User.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { useOverrides } from \"../../overrides\";\nimport { useCurrentUserId } from \"../../shared\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface UserProps extends ComponentProps<\"span\"> {\n /**\n * The user ID to display the user name for.\n */\n userId: string;\n\n /**\n * Whether to replace the user name with \"you\" ($.USER_SELF) for the current user.\n */\n replaceSelf?: boolean;\n}\n\nexport function User({\n userId,\n replaceSelf,\n className,\n children,\n ...props\n}: UserProps) {\n const currentId = useCurrentUserId();\n const { user, isLoading } = useUser(userId);\n const $ = useOverrides();\n const resolvedUserName = useMemo(() => {\n return replaceSelf && currentId === userId\n ? $.USER_SELF\n : (user?.name ?? $.USER_UNKNOWN);\n }, [replaceSelf, currentId, userId, $.USER_SELF, $.USER_UNKNOWN, user?.name]);\n\n return (\n <span\n className={cn(\"lb-name lb-user\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {isLoading ? null : resolvedUserName}\n {children}\n </span>\n );\n}\n"],"names":[],"mappings":";;;;;;;;;;;AAsBO;AAAc;AACnB;AACA;AACA;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAEqB;AAGvB;AACE;AAAC;AAAA;AAC2C;AACX;AAC3B;AAEH;AAAmB;AACnB;AAAA;AAAA;AAGP;;"}
1
+ {"version":3,"file":"User.cjs","sources":["../../../src/components/internal/User.tsx"],"sourcesContent":["\"use client\";\n\nimport { useUser } from \"@liveblocks/react\";\nimport type { ComponentProps } from \"react\";\nimport { useMemo } from \"react\";\n\nimport { useOverrides } from \"../../overrides\";\nimport { useCurrentUserId } from \"../../shared\";\nimport { cn } from \"../../utils/cn\";\n\nexport interface UserProps extends ComponentProps<\"span\"> {\n /**\n * The user ID to display the user name for.\n */\n userId?: string;\n\n /**\n * Whether to replace the user name with \"you\" ($.USER_SELF) for the current user.\n */\n replaceSelf?: boolean;\n}\n\ninterface UserLayoutProps extends ComponentProps<\"span\"> {\n isLoading: boolean;\n name: string;\n}\n\nfunction UserLayout({\n isLoading,\n name,\n className,\n children,\n ...props\n}: UserLayoutProps) {\n return (\n <span\n className={cn(\"lb-name lb-user\", className)}\n data-loading={isLoading ? \"\" : undefined}\n {...props}\n >\n {isLoading ? null : name}\n {children}\n </span>\n );\n}\n\nfunction ResolvedUser({\n userId,\n replaceSelf,\n ...props\n}: UserProps & { userId: string }) {\n const currentId = useCurrentUserId();\n const { user, isLoading } = useUser(userId);\n const $ = useOverrides();\n const resolvedUserName = useMemo(() => {\n return replaceSelf && currentId === userId\n ? $.USER_SELF\n : (user?.name ?? $.USER_UNKNOWN);\n }, [replaceSelf, currentId, userId, $.USER_SELF, $.USER_UNKNOWN, user?.name]);\n\n return (\n <UserLayout isLoading={isLoading} name={resolvedUserName} {...props} />\n );\n}\n\nexport function User({ userId, ...props }: UserProps) {\n const $ = useOverrides();\n\n if (!userId) {\n return <UserLayout isLoading={false} name={$.USER_UNKNOWN} {...props} />;\n }\n\n return <ResolvedUser userId={userId} {...props} />;\n}\n"],"names":[],"mappings":";;;;;;;;;;;AA2BA;AAAoB;AAClB;AACA;AACA;AACA;AAEF;AACE;AACE;AAAC;AAAA;AAC2C;AACX;AAC3B;AAEH;AAAmB;AACnB;AAAA;AAAA;AAGP;AAEA;AAAsB;AACpB;AACA;AAEF;AACE;AACA;AACA;AACA;AACE;AAEqB;AAGvB;AAGF;AAEO;AACL;AAEA;AACE;AAAsE;AAGxE;AACF;;"}