Docyrus

CommentsPanel

Threaded record comments with markdown bodies, @ mentions, file attachments, a pending placeholder and author resolution against a users list.

iOSAndroid
Preview CommentsPanel on your device

Scan with Expo Go

Download Expo Go, then scan the QR code to preview native components.

Installation

pnpm dlx @docyrus/cli add @docyrus/rn-comments-panel
Required Packages(3 packages)
pnpm add @shopify/flash-list expo-document-picker (optional) expo-image-picker (optional)

The attach button offers Files when expo-document-picker is installed and Photo library / Camera when expo-image-picker is installed. With neither, the button is hidden.

Usage

import { CommentsPanel } from '@/components/docyrus-native/comments-panel';

<CommentsPanel
  comments={comments}
  users={users}
  currentUser={currentUser}
  maxHeight={420}
  isCreatePending={createMutation.isPending}
  isDeletePending={deleteMutation.isPending}
  onCreateComment={({ message, parentId, attachments, mentions }) =>
    createMutation.mutateAsync({ message, parentId, attachments, mentions })}
  onUpdateComment={(id, message, mentions) => updateComment(id, message, mentions)}
  onDeleteComment={id => deleteMutation.mutateAsync(id)} />

useDocyrusLogActivity and useDocyrusContactActivity return comments in exactly this shape (created_by ids + a users list), so their output can be spread straight into the panel.

Mentions

Typing @ opens a list of matching users (max 8) above the input. Picking one inserts @Name into the text; on submit it is stored as the same markdown token web uses, [@Name](mention://<userId>), and the ids are passed as mentions. Stored tokens render as highlighted chips. A native TextInput cannot show inline chips, so while editing they appear as plain @Name text.

Actions

Tap Reply under a comment to answer it. Long-press a comment, or tap its ⋯ button, to open an action sheet with Reply, Edit and Delete. Only the author sees Edit and Delete. Delete asks for confirmation through DeleteConfirmDialog.

API Reference

CommentsPanelProps

PropTypeDefaultDescription
commentsDocyrusComment[]-Comments of the record. Top-level comments and their replies (one level) are sorted by created_on
currentUserCommentUser-Signed-in user. Used for ownership (edit / delete) and the composer avatar
usersCommentUser[]-Users used to resolve created_by and to offer @ mentions
titlestring'Comments'Header title
editablebooleantrueShow the composer and the Reply affordance
isLoadingbooleanfalseShow the loading skeleton
maxHeightnumber-Max list height in dp. When set, the list is a virtualised, scrollable FlashList that auto-scrolls to the newest comment. When omitted, the panel grows with its content
onCreateComment(payload: CommentCreatePayload) => void | Promise<void>-Create a comment or reply. The composer and Reply affordance are hidden without it
onUpdateComment(commentId: string, message: string, mentions?: string[]) => void | Promise<void>-Save an edited comment. Enables the Edit action on own comments
onDeleteComment(commentId: string) => void | Promise<void>-Delete a comment after confirmation. Enables the Delete action on own comments
onUploadFile(file: NativeFile) => Promise<CommentAttachment>-Accepted for API parity with web. The panel passes picked files through onCreateComment (attachments)
isCreatePendingbooleanfalseDisables the composer and shows a pending-comment placeholder row
isDeletePendingbooleanfalsePending state of the delete confirmation
enableRichFormattingbooleantrueOffer the formatting toolbar toggle (bold, italic, bulleted list inserted as markdown)
defaultRichFormattingbooleanfalseInitial toolbar visibility when uncontrolled
richFormattingboolean-Controlled toolbar visibility
onRichFormattingChange(rich: boolean) => void-Toolbar toggle callback
enableEmojibooleantrueAccepted for API parity. Native uses the system emoji keyboard
enableMentionsbooleantrueEnable @ mention autocomplete (needs users)
enableAttachmentsbooleantrueShow the attach button (needs an installed picker)
classNamestring-Container classes

CommentCreatePayload

FieldTypeDescription
messagestringMarkdown body. Mentions are stored as [@Name](mention://<userId>)
parentIdstringParent comment id for replies
attachmentsNativeFile[]Picked files ({ uri, name, type, size? }). Upload them with RN FormData
mentionsstring[]Unique mentioned user ids

DocyrusComment

FieldTypeDescription
idstringComment id
messagestringMarkdown body
attachmentsCommentAttachment[] | nullAttached files
created_onstringISO timestamp
created_bystringAuthor user id, resolved against users
last_modified_onstring | nullShows "(edited)" when different from created_on
record_idstring | nullOwning record
parent_idstring | nullParent comment for replies (null for top level)

CommentUser

FieldTypeDescription
idstringUser id
firstnamestring | nullFirst name
lastnamestring | nullLast name
photostring | nullAvatar URL

CommentAttachment

FieldTypeDescription
idstringAttachment id
file_namestringFile name
file_typestring | nullMIME type. image/* with a signed_url renders a thumbnail
file_sizenumber | nullSize in bytes
signed_urlstring | nullTapping the attachment opens it with Linking.openURL

Components

ComponentDescription
CommentsPanelHeader, threaded list, composer, action sheet and delete confirmation

Type Exports

TypeDescription
CommentsPanelPropsProps for CommentsPanel
DocyrusCommentComment row (Docyrus API shape)
CommentUserUser used for authors and mentions
CommentAttachmentFile attached to a comment
CommentThread{ comment, replies } thread built from comments
CommentCreatePayloadPayload of onCreateComment

Breaking changes

The panel now uses the web / Docyrus API data model.

  • Comment was renamed to DocyrusComment. The embedded user: CommentUser was replaced by created_by: string, which is resolved against the new users prop.
  • CommentUser changed from { id, name, avatarUrl? } to { id, firstname?, lastname?, photo? }.
  • Replies are one level deep, like web: the recursive tree is gone, and a comment whose parent is itself a reply is not rendered. Top-level comments and replies are sorted by created_on.
  • onCreateComment receives { message, parentId?, attachments?, mentions? }, and onUpdateComment receives a third mentions argument.
  • Delete uses DeleteConfirmDialog instead of Alert.alert.
  • The panel no longer draws its own card (rounded-[28px] bg-card). Wrap it in a Card or pass className.

On this page