diff --git a/packages/provider/src/TiptapCollabProvider.ts b/packages/provider/src/TiptapCollabProvider.ts index 2947fb14..85ee5d9d 100644 --- a/packages/provider/src/TiptapCollabProvider.ts +++ b/packages/provider/src/TiptapCollabProvider.ts @@ -112,14 +112,27 @@ export class TiptapCollabProvider extends HocuspocusProvider { return this.configuration.document.getMap(`${this.tiptapCollabConfigurationPrefix}config`).set('autoVersioning', 0) } + /** + * Returns all users in the document as Y.Map objects + * @returns An array of Y.Map objects + */ private getYThreads() { return this.configuration.document.getArray>(`${this.tiptapCollabConfigurationPrefix}threads`) } + /** + * Finds all threads in the document and returns them as JSON objects + * @returns An array of threads as JSON objects + */ getThreads(): TCollabThread[] { return this.getYThreads().toJSON() as TCollabThread[] } + /** + * Find the index of a thread by its id + * @param id The thread id + * @returns The index of the thread or null if not found + */ private getThreadIndex(id: string): number | null { let index = null @@ -136,6 +149,11 @@ export class TiptapCollabProvider extends HocuspocusProvider { return index } + /** + * Gets a single thread by its id + * @param id The thread id + * @returns The thread as a JSON object or null if not found + */ getThread(id: string): TCollabThread | null { const index = this.getThreadIndex(id) @@ -146,6 +164,11 @@ export class TiptapCollabProvider extends HocuspocusProvider { return this.getYThreads().get(index).toJSON() as TCollabThread } + /** + * Gets a single thread by its id as a Y.Map object + * @param id The thread id + * @returns The thread as a Y.Map object or null if not found + */ private getYThread(id: string) { const index = this.getThreadIndex(id) @@ -156,6 +179,11 @@ export class TiptapCollabProvider extends HocuspocusProvider { return this.getYThreads().get(index) } + /** + * Create a new thread + * @param data The thread data + * @returns The created thread + */ createThread(data: Omit) { let createdThread: TCollabThread = {} as TCollabThread @@ -173,6 +201,12 @@ export class TiptapCollabProvider extends HocuspocusProvider { return createdThread } + /** + * Update a specific thread + * @param id The thread id + * @param data New data for the thread + * @returns The updated thread or null if the thread is not found + */ updateThread(id: TCollabThread['id'], data: Partial & { resolvedAt: TCollabThread['resolvedAt'] | null }>) { @@ -201,6 +235,11 @@ export class TiptapCollabProvider extends HocuspocusProvider { return updatedThread } + /** + * Delete a specific thread and all its comments + * @param id The thread id + * @returns void + */ deleteThread(id: TCollabThread['id']) { const index = this.getThreadIndex(id) @@ -211,6 +250,12 @@ export class TiptapCollabProvider extends HocuspocusProvider { this.getYThreads().delete(index, 1) } + /** + * Returns comments from a thread, either deleted or not + * @param threadId The thread id + * @param deleted If you want to query deleted comments, defaults to `false` + * @returns The comments or null if the thread is not found + */ getThreadComments(threadId: TCollabThread['id'], deleted?: boolean): TCollabComment[] | null { const index = this.getThreadIndex(threadId) @@ -221,6 +266,11 @@ export class TiptapCollabProvider extends HocuspocusProvider { return (!deleted ? this.getThread(threadId)?.comments : this.getThread(threadId)?.deletedComments) ?? [] } + /** + * Returns all comments of a thread **including deleted ones** + * @param threadId The thread id + * @returns The comments or null if the thread is not found + */ getAllThreadComments(threadId: TCollabThread['id']): TCollabComment[] | null { const index = this.getThreadIndex(threadId) @@ -231,16 +281,32 @@ export class TiptapCollabProvider extends HocuspocusProvider { return [...this.getThreadComments(threadId) ?? [], ...this.getThreadComments(threadId, true) ?? []].sort((a, b) => a.createdAt - b.createdAt) } - getThreadComment(threadId: TCollabThread['id'], commentId: TCollabComment['id']): TCollabComment | null { + /** + * Get a single comment from a specific thread + * @param threadId The thread id + * @param commentId The comment id + * @param deleted If you want to include deleted comments in the search + * @returns The comment or null if not found + */ + getThreadComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], deleted?: boolean): TCollabComment | null { const index = this.getThreadIndex(threadId) if (index === null) { return null } - return this.getAllThreadComments(threadId)?.find(comment => comment.id === commentId) ?? null + const comments = deleted ? this.getAllThreadComments(threadId) : this.getThreadComments(threadId) + + return comments?.find(comment => comment.id === commentId) ?? null } + /** + * Adds a comment to a thread + * @param threadId The thread id + * @param data The comment data + * @returns The updated thread or null if the thread is not found + * @example addComment('123', { content: 'Hello world', data: { author: 'Maria Doe' } }) + */ addComment(threadId: TCollabThread['id'], data: Omit) { let updatedThread: TCollabThread = {} as TCollabThread @@ -262,6 +328,14 @@ export class TiptapCollabProvider extends HocuspocusProvider { return updatedThread } + /** + * Update a comment in a thread + * @param threadId The thread id + * @param commentId The comment id + * @param data The new comment data + * @returns The updated thread or null if the thread or comment is not found + * @example updateComment('123', { content: 'The new content', data: { attachments: ['file1.jpg'] }}) + */ updateComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], data: Partial>) { let updatedThread: TCollabThread = {} as TCollabThread @@ -297,6 +371,13 @@ export class TiptapCollabProvider extends HocuspocusProvider { return updatedThread } + /** + * Deletes a comment from a thread + * @param threadId The thread id + * @param commentId The comment id + * @param deleteThread Set to `true` if you also want to delete the thread when the last comment is deleted + * @returns The updated thread or null if the thread or comment is not found + */ deleteComment(threadId: TCollabThread['id'], commentId: TCollabComment['id'], deleteThread?: boolean) { const thread = this.getYThread(threadId) @@ -335,10 +416,18 @@ export class TiptapCollabProvider extends HocuspocusProvider { return thread.toJSON() as TCollabThread } + /** + * Start watching threads for changes + * @param callback The callback function to be called when a thread changes + */ watchThreads(callback: () => void) { this.getYThreads().observeDeep(callback) } + /** + * Stop watching threads for changes + * @param callback The callback function to be removed + */ unwatchThreads(callback: () => void) { this.getYThreads().unobserveDeep(callback) }