{"version":3,"file":"FloatingThreadController-BMC2B9Lr.cjs","names":[],"sources":["../src/components/Comments/EmojiMartPicker.tsx","../src/components/Comments/EmojiPicker.tsx","../src/components/Comments/useUsers.ts","../src/components/Comments/ReactionBadge.tsx","../src/components/Comments/Comment.tsx","../src/components/Comments/Comments.tsx","../src/components/Comments/Thread.tsx","../src/components/Comments/useThreads.ts","../src/components/Comments/FloatingThreadController.tsx"],"sourcesContent":["// From https://github.com/missive/emoji-mart/blob/main/packages/emoji-mart-react/react.tsx\nimport type { EmojiMartData } from \"@emoji-mart/data\";\nimport React, { useEffect, useRef } from \"react\";\n\n// Temporary fix for https://github.com/missive/emoji-mart/pull/929\nlet emojiLoadingPromise:\n  | Promise<{\n      emojiMart: typeof import(\"emoji-mart\");\n      emojiData: EmojiMartData;\n    }>\n  | undefined;\n\nasync function loadEmojiMart() {\n  if (emojiLoadingPromise) {\n    return emojiLoadingPromise;\n  }\n\n  emojiLoadingPromise = (async () => {\n    // load dynamically because emoji-mart doesn't specify type: module and breaks in nodejs\n    const [emojiMartModule, emojiDataModule] = await Promise.all([\n      import(\"emoji-mart\"),\n      // use a dynamic import to encourage bundle-splitting\n      // and a smaller initial client bundle size\n      import(\"@emoji-mart/data\"),\n    ]);\n\n    const emojiMart =\n      \"default\" in emojiMartModule ? emojiMartModule.default : emojiMartModule;\n    const emojiData =\n      \"default\" in emojiDataModule\n        ? (emojiDataModule.default as EmojiMartData)\n        : (emojiDataModule as EmojiMartData);\n\n    await emojiMart.init({ data: emojiData });\n\n    return { emojiMart, emojiData };\n  })();\n\n  return emojiLoadingPromise;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport default function EmojiPicker(props: any) {\n  const ref = useRef(null);\n  const instance = useRef(null) as any;\n\n  if (instance.current) {\n    instance.current.update(props);\n  }\n\n  useEffect(() => {\n    (async () => {\n      const { emojiMart } = await loadEmojiMart();\n\n      instance.current = new emojiMart.Picker({ ...props, ref });\n    })();\n\n    return () => {\n      instance.current = null;\n    };\n  }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n  return React.createElement(\"div\", { ref });\n}\n","import { ReactNode, useState } from \"react\";\n\nimport { useBlockNoteContext } from \"../../editor/BlockNoteContext.js\";\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport Picker from \"./EmojiMartPicker.js\";\n\nexport const EmojiPicker = (props: {\n  onEmojiSelect: (emoji: { native: string }) => void;\n  onOpenChange?: (open: boolean) => void;\n  children: ReactNode;\n}) => {\n  const [open, setOpen] = useState(false);\n\n  const Components = useComponentsContext()!;\n  const blockNoteContext = useBlockNoteContext()!;\n  const portalRoot = blockNoteContext.editor?.portalElement;\n\n  if (!portalRoot) {\n    throw new Error(\"Portal root not found\");\n  }\n\n  return (\n    <Components.Generic.Popover.Root open={open} portalRoot={portalRoot}>\n      <Components.Generic.Popover.Trigger>\n        <div\n          onClick={(event) => {\n            // Needed as the Picker component's onClickOutside handler\n            // fires immediately after otherwise, preventing the popover\n            // from opening.\n            event.preventDefault();\n            event.stopPropagation();\n            setOpen(!open);\n            props.onOpenChange?.(!open);\n          }}\n          style={{\n            display: \"flex\",\n            justifyContent: \"center\",\n            alignItems: \"center\",\n          }}\n        >\n          {props.children}\n        </div>\n      </Components.Generic.Popover.Trigger>\n      <Components.Generic.Popover.Content\n        className={\"bn-emoji-picker-popover\"}\n        variant={\"panel-popover\"}\n      >\n        <Picker\n          perLine={7}\n          onClickOutside={() => {\n            setOpen(false);\n            props.onOpenChange?.(false);\n          }}\n          onEmojiSelect={(emoji: { native: string }) => {\n            props.onEmojiSelect(emoji);\n            setOpen(false);\n            props.onOpenChange?.(false);\n          }}\n          theme={blockNoteContext?.colorSchemePreference}\n        />\n      </Components.Generic.Popover.Content>\n    </Components.Generic.Popover.Root>\n  );\n};\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { User } from \"@blocknote/core/comments\";\nimport { useCallback, useMemo, useSyncExternalStore } from \"react\";\n\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\nexport function useUser(userId: string) {\n  return useUsers([userId]).get(userId);\n}\n\n/**\n * Bridges the UserStore to React using useSyncExternalStore.\n */\nexport function useUsers(userIds: string[]) {\n  const comments = useExtension(CommentsExtension);\n\n  const store = comments.userStore;\n\n  const getUpdatedSnapshot = useCallback(() => {\n    const map = new Map<string, User>();\n    for (const id of userIds) {\n      const user = store.getUser(id);\n      if (user) {\n        map.set(id, user);\n      }\n    }\n    return map;\n  }, [store, userIds]);\n\n  // this ref / memoworks around this error:\n  // https://react.dev/reference/react/useSyncExternalStore#im-getting-an-error-the-result-of-getsnapshot-should-be-cached\n  // however, might not be a good practice to work around it this way\n\n  // We need to use a memo instead of a ref to make sure the snapshot is updated when the userIds change\n  const ref = useMemo(() => {\n    return {\n      current: getUpdatedSnapshot(),\n    };\n  }, [getUpdatedSnapshot]);\n\n  // note: this is inefficient as it will trigger a re-render even if other users (not in userIds) are updated\n  const subscribe = useCallback(\n    (cb: () => void) => {\n      const ret = store.subscribe((_users) => {\n        // update ref when changed\n        ref.current = getUpdatedSnapshot();\n\n        // calling cb() will make sure `useSyncExternalStore` will fetch the latest snapshot (which is ref.current)\n        cb();\n      });\n      store.loadUsers(userIds);\n      return ret;\n    },\n    [store, getUpdatedSnapshot, userIds, ref],\n  );\n\n  return useSyncExternalStore(subscribe, () => ref.current!);\n}\n","import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { CommentData } from \"@blocknote/core/comments\";\nimport { useState } from \"react\";\n\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useUsers } from \"./useUsers.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\nexport const ReactionBadge = (props: {\n  comment: CommentData;\n  emoji: string;\n  onReactionSelect: (emoji: string) => void;\n}) => {\n  const Components = useComponentsContext()!;\n  const dict = useDictionary();\n\n  const comments = useExtension(CommentsExtension);\n\n  const reaction = props.comment.reactions.find(\n    (reaction) => reaction.emoji === props.emoji,\n  );\n  if (!reaction) {\n    throw new Error(\n      \"Trying to render reaction badge for non-existing reaction\",\n    );\n  }\n\n  const [userIds, setUserIds] = useState<string[]>([]);\n  const users = useUsers(userIds);\n\n  return (\n    <Components.Generic.Badge.Root\n      key={reaction.emoji}\n      className={mergeCSSClasses(\"bn-badge\", \"bn-comment-reaction\")}\n      text={reaction.userIds.length.toString()}\n      icon={reaction.emoji}\n      isSelected={comments.threadStore.auth.canDeleteReaction(\n        props.comment,\n        reaction.emoji,\n      )}\n      onClick={() => props.onReactionSelect(reaction.emoji)}\n      onMouseEnter={() => setUserIds(reaction.userIds)}\n      mainTooltip={dict.comments.reactions.reacted_by}\n      secondaryTooltip={`${Array.from(users.values())\n        .map((user) => user.username)\n        .join(\"\\n\")}`}\n    />\n  );\n};\n","\"use client\";\n\nimport { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport type { CommentData, ThreadData } from \"@blocknote/core/comments\";\nimport { MouseEvent, ReactNode, useCallback, useState } from \"react\";\nimport {\n  RiArrowGoBackFill,\n  RiCheckFill,\n  RiDeleteBinFill,\n  RiEditFill,\n  RiEmotionLine,\n  RiMoreFill,\n} from \"react-icons/ri\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { EmojiPicker } from \"./EmojiPicker.js\";\nimport { ReactionBadge } from \"./ReactionBadge.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\nimport { useUser } from \"./useUsers.js\";\n\nexport type CommentProps = {\n  comment: CommentData;\n  thread: ThreadData;\n  showResolveButton?: boolean;\n};\n\n/**\n * The Comment component displays a single comment with actions,\n * a reaction list and an editor when editing.\n *\n * It's generally used in the `Thread` component for comments that have already been created.\n *\n */\nexport const Comment = ({\n  comment,\n  thread,\n  showResolveButton,\n}: CommentProps) => {\n  // TODO: if REST API becomes popular, all interactions (click handlers) should implement a loading state and error state\n  // (or optimistic local updates)\n  const comments = useExtension(CommentsExtension);\n\n  const dict = useDictionary();\n\n  const commentEditor = useCreateBlockNote({\n    initialContent: comment.body,\n    trailingBlock: false,\n    dictionary: {\n      ...dict,\n      placeholders: {\n        emptyDocument: dict.placeholders.edit_comment,\n      },\n    },\n    schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n  });\n\n  const Components = useComponentsContext()!;\n\n  const [isEditing, setEditing] = useState(false);\n  const [emojiPickerOpen, setEmojiPickerOpen] = useState(false);\n\n  const threadStore = comments.threadStore;\n\n  const handleEdit = useCallback(() => {\n    setEditing(true);\n  }, []);\n\n  const onEditCancel = useCallback(() => {\n    commentEditor.replaceBlocks(commentEditor.document, comment.body);\n    setEditing(false);\n  }, [commentEditor, comment.body]);\n\n  const onEditSubmit = useCallback(\n    async (_event: MouseEvent) => {\n      await threadStore.updateComment({\n        commentId: comment.id,\n        comment: {\n          body: commentEditor.document,\n        },\n        threadId: thread.id,\n      });\n\n      setEditing(false);\n    },\n    [comment, thread.id, commentEditor, threadStore],\n  );\n\n  const onDelete = useCallback(async () => {\n    await threadStore.deleteComment({\n      commentId: comment.id,\n      threadId: thread.id,\n    });\n  }, [comment, thread.id, threadStore]);\n\n  const onReactionSelect = useCallback(\n    async (emoji: string) => {\n      if (threadStore.auth.canAddReaction(comment, emoji)) {\n        await threadStore.addReaction({\n          threadId: thread.id,\n          commentId: comment.id,\n          emoji,\n        });\n      } else if (threadStore.auth.canDeleteReaction(comment, emoji)) {\n        await threadStore.deleteReaction({\n          threadId: thread.id,\n          commentId: comment.id,\n          emoji,\n        });\n      }\n    },\n    [threadStore, comment, thread.id],\n  );\n\n  const onResolve = useCallback(async () => {\n    await threadStore.resolveThread({\n      threadId: thread.id,\n    });\n  }, [thread.id, threadStore]);\n\n  const onReopen = useCallback(async () => {\n    await threadStore.unresolveThread({\n      threadId: thread.id,\n    });\n  }, [thread.id, threadStore]);\n\n  const user = useUser(comment.userId);\n\n  if (!comment.body) {\n    return null;\n  }\n\n  let actions: ReactNode | undefined = undefined;\n  const canAddReaction = threadStore.auth.canAddReaction(comment);\n  const canDeleteComment = threadStore.auth.canDeleteComment(comment);\n  const canEditComment = threadStore.auth.canUpdateComment(comment);\n\n  const showResolveOrReopen =\n    showResolveButton &&\n    (thread.resolved\n      ? threadStore.auth.canUnresolveThread(thread)\n      : threadStore.auth.canResolveThread(thread));\n\n  if (!isEditing) {\n    actions = (\n      <Components.Generic.Toolbar.Root\n        className={mergeCSSClasses(\"bn-action-toolbar\", \"bn-comment-actions\")}\n        variant={\"action-toolbar\"}\n      >\n        {canAddReaction && (\n          <EmojiPicker\n            onEmojiSelect={(emoji: { native: string }) =>\n              onReactionSelect(emoji.native)\n            }\n            onOpenChange={setEmojiPickerOpen}\n          >\n            <Components.Generic.Toolbar.Button\n              key={\"add-reaction\"}\n              mainTooltip={dict.comments.actions.add_reaction}\n              variant=\"compact\"\n            >\n              <RiEmotionLine size={16} />\n            </Components.Generic.Toolbar.Button>\n          </EmojiPicker>\n        )}\n        {showResolveOrReopen &&\n          (thread.resolved ? (\n            <Components.Generic.Toolbar.Button\n              key={\"reopen\"}\n              mainTooltip=\"Re-open\"\n              variant=\"compact\"\n              onClick={onReopen}\n            >\n              <RiArrowGoBackFill size={16} />\n            </Components.Generic.Toolbar.Button>\n          ) : (\n            <Components.Generic.Toolbar.Button\n              key={\"resolve\"}\n              mainTooltip={dict.comments.actions.resolve}\n              variant=\"compact\"\n              onClick={onResolve}\n            >\n              <RiCheckFill size={16} />\n            </Components.Generic.Toolbar.Button>\n          ))}\n        {(canDeleteComment || canEditComment) && (\n          <Components.Generic.Menu.Root position={\"bottom-start\"}>\n            <Components.Generic.Menu.Trigger>\n              <Components.Generic.Toolbar.Button\n                key={\"more-actions\"}\n                mainTooltip={dict.comments.actions.more_actions}\n                variant=\"compact\"\n              >\n                <RiMoreFill size={16} />\n              </Components.Generic.Toolbar.Button>\n            </Components.Generic.Menu.Trigger>\n            <Components.Generic.Menu.Dropdown className={\"bn-menu-dropdown\"}>\n              {canEditComment && (\n                <Components.Generic.Menu.Item\n                  key={\"edit-comment\"}\n                  icon={<RiEditFill />}\n                  onClick={handleEdit}\n                >\n                  {dict.comments.actions.edit_comment}\n                </Components.Generic.Menu.Item>\n              )}\n              {canDeleteComment && (\n                <Components.Generic.Menu.Item\n                  key={\"delete-comment\"}\n                  icon={<RiDeleteBinFill />}\n                  onClick={onDelete}\n                >\n                  {dict.comments.actions.delete_comment}\n                </Components.Generic.Menu.Item>\n              )}\n            </Components.Generic.Menu.Dropdown>\n          </Components.Generic.Menu.Root>\n        )}\n      </Components.Generic.Toolbar.Root>\n    );\n  }\n\n  const timeString = comment.createdAt.toLocaleDateString(undefined, {\n    month: \"short\",\n    day: \"numeric\",\n  });\n\n  if (!comment.body) {\n    throw new Error(\"soft deletes are not yet supported\");\n  }\n\n  return (\n    <Components.Comments.Comment\n      authorInfo={user ?? \"loading\"}\n      timeString={timeString}\n      edited={comment.updatedAt.getTime() !== comment.createdAt.getTime()}\n      showActions={\"hover\"}\n      actions={actions}\n      className={\"bn-thread-comment\"}\n      emojiPickerOpen={emojiPickerOpen}\n    >\n      <CommentEditor\n        autoFocus={isEditing}\n        editor={commentEditor}\n        editable={isEditing}\n        actions={\n          comment.reactions.length > 0 || isEditing\n            ? ({ isEmpty }) => (\n                <>\n                  {comment.reactions.length > 0 && !isEditing && (\n                    <Components.Generic.Badge.Group\n                      className={mergeCSSClasses(\n                        \"bn-badge-group\",\n                        \"bn-comment-reactions\",\n                      )}\n                    >\n                      {comment.reactions.map((reaction) => (\n                        <ReactionBadge\n                          key={reaction.emoji}\n                          comment={comment}\n                          emoji={reaction.emoji}\n                          onReactionSelect={onReactionSelect}\n                        />\n                      ))}\n                      {canAddReaction && (\n                        <EmojiPicker\n                          onEmojiSelect={(emoji: { native: string }) =>\n                            onReactionSelect(emoji.native)\n                          }\n                          onOpenChange={setEmojiPickerOpen}\n                        >\n                          <Components.Generic.Badge.Root\n                            className={mergeCSSClasses(\n                              \"bn-badge\",\n                              \"bn-comment-add-reaction\",\n                            )}\n                            text={\"+\"}\n                            icon={<RiEmotionLine size={16} />}\n                            mainTooltip={dict.comments.actions.add_reaction}\n                          />\n                        </EmojiPicker>\n                      )}\n                    </Components.Generic.Badge.Group>\n                  )}\n                  {isEditing && (\n                    <Components.Generic.Toolbar.Root\n                      variant=\"action-toolbar\"\n                      className={mergeCSSClasses(\n                        \"bn-action-toolbar\",\n                        \"bn-comment-actions\",\n                      )}\n                    >\n                      <Components.Generic.Toolbar.Button\n                        mainTooltip={dict.comments.save_button_text}\n                        variant=\"compact\"\n                        onClick={onEditSubmit}\n                        isDisabled={isEmpty}\n                      >\n                        {dict.comments.save_button_text}\n                      </Components.Generic.Toolbar.Button>\n                      <Components.Generic.Toolbar.Button\n                        className={\"bn-button\"}\n                        mainTooltip={dict.comments.cancel_button_text}\n                        variant=\"compact\"\n                        onClick={onEditCancel}\n                      >\n                        {dict.comments.cancel_button_text}\n                      </Components.Generic.Toolbar.Button>\n                    </Components.Generic.Toolbar.Root>\n                  )}\n                </>\n              )\n            : undefined\n        }\n      />\n    </Components.Comments.Comment>\n  );\n};\n","import { ThreadData } from \"@blocknote/core/comments\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { Comment } from \"./Comment.js\";\nimport { useUsers } from \"./useUsers.js\";\n\nexport type CommentsProps = {\n  thread: ThreadData;\n  maxCommentsBeforeCollapse?: number;\n};\n\nexport const Comments = ({\n  thread,\n  maxCommentsBeforeCollapse,\n}: CommentsProps) => {\n  const Components = useComponentsContext()!;\n  const dict = useDictionary();\n  const users = useUsers(thread.resolvedBy ? [thread.resolvedBy] : []);\n\n  // Maps all comments to elements.\n  const comments = thread.comments.map((comment, index) => (\n    <Comment\n      key={comment.id + JSON.stringify(comment.body || \"{}\")}\n      thread={thread}\n      comment={comment}\n      showResolveButton={index === 0}\n    />\n  ));\n\n  // Adds \"resolved by\" comment if needed.\n  if (thread.resolved && thread.resolvedUpdatedAt && thread.resolvedBy) {\n    const resolvedByUser = users.get(thread.resolvedBy);\n    if (!resolvedByUser) {\n      throw new Error(\n        `User ${thread.resolvedBy} resolved thread ${thread.id}, but their data could not be found.`,\n      );\n    }\n\n    const resolvedCommentIndex =\n      thread.comments.findLastIndex(\n        (comment) =>\n          thread.resolvedUpdatedAt!.getTime() > comment.createdAt.getTime(),\n      ) + 1;\n\n    comments.splice(\n      resolvedCommentIndex,\n      0,\n      <Components.Comments.Comment\n        key={\"resolved-comment\"}\n        className={\"bn-thread-comment\"}\n        authorInfo={\n          (thread.resolvedBy && users.get(thread.resolvedBy)) || \"loading\"\n        }\n        timeString={thread.resolvedUpdatedAt.toLocaleDateString(undefined, {\n          month: \"short\",\n          day: \"numeric\",\n        })}\n        edited={false}\n        showActions={false}\n      >\n        <div className={\"bn-resolved-text\"}>\n          {dict.comments.sidebar.marked_as_resolved}\n        </div>\n      </Components.Comments.Comment>,\n    );\n  }\n\n  // Collapses replies if needed.\n  if (\n    maxCommentsBeforeCollapse &&\n    comments.length > maxCommentsBeforeCollapse\n  ) {\n    comments.splice(\n      1,\n      comments.length - 2,\n      <Components.Comments.ExpandSectionsPrompt\n        key={\"expand-prompt\"}\n        className={\"bn-thread-expand-prompt\"}\n      >\n        {dict.comments.sidebar.more_replies(thread.comments.length - 2)}\n      </Components.Comments.ExpandSectionsPrompt>,\n    );\n  }\n\n  return comments;\n};\n","import { mergeCSSClasses } from \"@blocknote/core\";\nimport { CommentsExtension } from \"@blocknote/core/comments\";\nimport { ThreadData } from \"@blocknote/core/comments\";\nimport { FocusEvent, useCallback } from \"react\";\n\nimport { useComponentsContext } from \"../../editor/ComponentsContext.js\";\nimport { useCreateBlockNote } from \"../../hooks/useCreateBlockNote.js\";\nimport { useExtension } from \"../../hooks/useExtension.js\";\nimport { useDictionary } from \"../../i18n/dictionary.js\";\nimport { CommentEditor } from \"./CommentEditor.js\";\nimport { Comments } from \"./Comments.js\";\nimport { defaultCommentEditorSchema } from \"./defaultCommentEditorSchema.js\";\n\nexport type ThreadProps = {\n  /**\n   * The thread to display - you can use the `useThreads` hook to retrieve a\n   * `Map` of all threads in the editor, mapped by their IDs.\n   */\n  thread: ThreadData;\n  /**\n   * A boolean flag for whether the thread is selected. Selected threads show an\n   * editor for replies, and add a `selected` CSS class to the thread.\n   */\n  selected?: boolean;\n  /**\n   * The text in the editor that the thread refers to. See the\n   * [`ThreadsSidebar`](https://github.com/TypeCellOS/BlockNote/tree/main/packages/react/src/components/Comments/ThreadsSidebar.tsx#L137)\n   * component to find out how to get this.\n   */\n  referenceText?: string;\n  /**\n   * The maximum number of comments that can be in a thread before the replies\n   * get collapsed.\n   */\n  maxCommentsBeforeCollapse?: number;\n  /**\n   * A function to call when the thread is focused.\n   */\n  onFocus?: (event: FocusEvent) => void;\n  /**\n   * A function to call when the thread is blurred.\n   */\n  onBlur?: (event: FocusEvent) => void;\n  /**\n   * The tab index for the thread.\n   */\n  tabIndex?: number;\n};\n\n/**\n * The Thread component displays a (main) comment with a list of replies (other comments).\n *\n * It also includes a composer to reply to the thread.\n */\nexport const Thread = ({\n  thread,\n  selected,\n  referenceText,\n  maxCommentsBeforeCollapse,\n  onFocus,\n  onBlur,\n  tabIndex,\n}: ThreadProps) => {\n  // TODO: if REST API becomes popular, all interactions (click handlers) should implement a loading state and error state\n  // (or optimistic local updates)\n\n  const Components = useComponentsContext()!;\n  const dict = useDictionary();\n\n  const comments = useExtension(CommentsExtension);\n\n  const newCommentEditor = useCreateBlockNote({\n    trailingBlock: false,\n    dictionary: {\n      ...dict,\n      placeholders: {\n        emptyDocument: dict.placeholders.comment_reply,\n      },\n    },\n    schema: comments.commentEditorSchema || defaultCommentEditorSchema,\n  });\n\n  const onNewCommentSave = useCallback(async () => {\n    await comments.threadStore.addComment({\n      comment: {\n        body: newCommentEditor.document,\n      },\n      threadId: thread.id,\n    });\n\n    // reset editor\n    newCommentEditor.removeBlocks(newCommentEditor.document);\n  }, [comments, newCommentEditor, thread.id]);\n\n  return (\n    <Components.Comments.Card\n      className={\"bn-thread\"}\n      headerText={referenceText}\n      onFocus={onFocus}\n      onBlur={onBlur}\n      selected={selected}\n      tabIndex={tabIndex}\n    >\n      <Components.Comments.CardSection className=\"bn-thread-comments\">\n        <Comments\n          thread={thread}\n          maxCommentsBeforeCollapse={\n            !selected ? maxCommentsBeforeCollapse || 5 : undefined\n          }\n        />\n      </Components.Comments.CardSection>\n      {selected && (\n        <Components.Comments.CardSection className={\"bn-thread-composer\"}>\n          <CommentEditor\n            autoFocus={false}\n            editable={true}\n            editor={newCommentEditor}\n            actions={({ isEmpty }) => {\n              if (isEmpty) {\n                return null;\n              }\n\n              return (\n                <Components.Generic.Toolbar.Root\n                  variant=\"action-toolbar\"\n                  className={mergeCSSClasses(\n                    \"bn-action-toolbar\",\n                    \"bn-comment-actions\",\n                  )}\n                >\n                  <Components.Generic.Toolbar.Button\n                    mainTooltip={dict.comments.save_button_text}\n                    variant=\"compact\"\n                    isDisabled={isEmpty}\n                    onClick={onNewCommentSave}\n                  >\n                    {dict.comments.save_button_text}\n                  </Components.Generic.Toolbar.Button>\n                </Components.Generic.Toolbar.Root>\n              );\n            }}\n          />\n        </Components.Comments.CardSection>\n      )}\n    </Components.Comments.Card>\n  );\n};\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { ThreadData } from \"@blocknote/core/comments\";\nimport { useCallback, useRef, useSyncExternalStore } from \"react\";\n\nimport { useExtension } from \"../../hooks/useExtension.js\";\n\n/**\n * Bridges the ThreadStore to React using useSyncExternalStore.\n */\nexport function useThreads() {\n  const comments = useExtension(CommentsExtension);\n\n  const store = comments.threadStore;\n\n  // this ref works around this error:\n  // https://react.dev/reference/react/useSyncExternalStore#im-getting-an-error-the-result-of-getsnapshot-should-be-cached\n  // however, might not be a good practice to work around it this way\n  const threadsRef = useRef<Map<string, ThreadData> | undefined>(undefined);\n\n  if (!threadsRef.current) {\n    threadsRef.current = store.getThreads();\n  }\n\n  const subscribe = useCallback(\n    (cb: () => void) => {\n      return store.subscribe((threads) => {\n        // update ref when changed\n        threadsRef.current = threads;\n        cb();\n      });\n    },\n    [store],\n  );\n\n  return useSyncExternalStore(subscribe, () => threadsRef.current!);\n}\n","import { CommentsExtension } from \"@blocknote/core/comments\";\nimport { flip, offset, shift } from \"@floating-ui/react\";\nimport { ComponentProps, FC, useMemo } from \"react\";\n\nimport { useBlockNoteEditor } from \"../../hooks/useBlockNoteEditor.js\";\nimport { useExtension, useExtensionState } from \"../../hooks/useExtension.js\";\nimport { FloatingUIOptions } from \"../Popovers/FloatingUIOptions.js\";\nimport { PositionPopover } from \"../Popovers/PositionPopover.js\";\nimport { Thread } from \"./Thread.js\";\nimport { useThreads } from \"./useThreads.js\";\n\n/**\n * This component is used to display a thread in a floating card.\n * It can be used when the user clicks on a thread / comment in the document.\n */\nexport default function FloatingThreadController(props: {\n  floatingThread?: FC<ComponentProps<typeof Thread>>;\n  floatingUIOptions?: FloatingUIOptions;\n}) {\n  const editor = useBlockNoteEditor<any, any, any>();\n\n  const comments = useExtension(CommentsExtension);\n  const selectedThread = useExtensionState(CommentsExtension, {\n    editor,\n    selector: (state) =>\n      state.selectedThreadId\n        ? {\n            id: state.selectedThreadId,\n            position: state.threadPositions.get(state.selectedThreadId),\n          }\n        : undefined,\n  });\n\n  const threads = useThreads();\n\n  const thread = useMemo(\n    () => (selectedThread ? threads.get(selectedThread.id) : undefined),\n    [selectedThread, threads],\n  );\n\n  const floatingUIOptions = useMemo<FloatingUIOptions>(\n    () => ({\n      ...props.floatingUIOptions,\n      useFloatingOptions: {\n        open: !!selectedThread,\n        // Needed as hooks like `useDismiss` call `onOpenChange` to change the\n        // open state.\n        onOpenChange: (open, _event, reason) => {\n          if (reason === \"escape-key\") {\n            editor.focus();\n          }\n\n          if (!open) {\n            comments.selectThread(undefined);\n          }\n        },\n        placement: \"bottom\",\n        middleware: [offset(10), shift(), flip()],\n        ...props.floatingUIOptions?.useFloatingOptions,\n      },\n      focusManagerProps: {\n        disabled: true,\n        ...props.floatingUIOptions?.focusManagerProps,\n      },\n      elementProps: {\n        style: {\n          zIndex: 30,\n        },\n        ...props.floatingUIOptions?.elementProps,\n      },\n    }),\n    [comments, editor, props.floatingUIOptions, selectedThread],\n  );\n\n  // nice to have improvements:\n  // - transition transform property so composer box animates when remote document is changed\n\n  const Component = props.floatingThread || Thread;\n\n  return (\n    <PositionPopover position={selectedThread?.position} {...floatingUIOptions}>\n      {thread && <Component thread={thread} selected={true} />}\n    </PositionPopover>\n  );\n}\n"],"mappings":"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"}