{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "comment-docs",
  "title": "Comment",
  "description": "Documentation for Comment",
  "files": [
    {
      "path": "../../content/docs/(plugins)/(collaboration)/comment.mdx",
      "content": "---\ntitle: Comment\ndocs:\n  - route: https://pro.platejs.org/docs/examples/discussion\n    title: Plus\n  - route: /docs/components/comment-node\n    title: Comment Leaf\n  - route: /docs/components/comment-toolbar-button\n    title: Comment Toolbar Button\n  - route: /docs/components/block-discussion\n    title: Block Discussion\n---\n\n<ComponentPreview name=\"discussion-demo\" />\n\n<PackageInfo>\n\n## Features\n\n- **Text Comments:** Add comments as text marks with inline annotations\n- **Overlapping Comments:** Support multiple comments on the same text\n- **Draft Comments:** Create draft comments before finalizing\n- **State Tracking:** Track comment state and user interactions\n- **Discussion Integration:** Works with discussion plugin for complete collaboration\n\n</PackageInfo>\n\n## Kit Usage\n\n<Steps>\n\n### Installation\n\nThe fastest way to add comment functionality is with the `CommentKit`, which includes pre-configured `commentPlugin` and related components along with their [Plate UI](/docs/installation/plate-ui) components.\n\n<ComponentSource name=\"comment-kit\" />\n\n- [`CommentLeaf`](/docs/components/comment-node): Renders comment text marks\n- [`BlockDiscussion`](/docs/components/block-discussion): Renders discussion UI with comments integration\n\n### Add Kit\n\n```tsx\nimport { createPlateEditor } from 'platejs/react';\nimport { CommentKit } from '@/components/editor/plugins/comment-kit';\n\nconst editor = createPlateEditor({\n  plugins: [\n    // ...otherPlugins,\n    ...CommentKit,\n  ],\n});\n```\n\n</Steps>\n\n## Manual Usage\n\n<Steps>\n\n### Installation\n\n```bash\nnpm install @platejs/comment\n```\n\n### Extend Comment Plugin\n\nCreate the comment plugin with extended configuration for state management:\n\n```tsx\nimport { type ExtendConfig, type Path, isSlateString } from 'platejs';\nimport {\n  type BaseCommentConfig,\n  BaseCommentPlugin,\n  getDraftCommentKey,\n} from '@platejs/comment';\nimport { toTPlatePlugin } from 'platejs/react';\nimport { CommentLeaf } from '@/components/ui/comment-node';\n\ntype CommentConfig = ExtendConfig<\n  BaseCommentConfig,\n  {\n    activeId: string | null;\n    commentingBlock: Path | null;\n    hoverId: string | null;\n  }\n>;\n\nexport const commentPlugin = toTPlatePlugin<CommentConfig>(\n  BaseCommentPlugin,\n  ({ editor }) => ({\n    options: {\n      activeId: null,\n      commentingBlock: null,\n      hoverId: null,\n    },\n    render: {\n      node: CommentLeaf,\n    },\n  })\n);\n```\n\n- `options.activeId`: Currently active comment ID for visual highlighting\n- `options.commentingBlock`: Path of the block currently being commented\n- `options.hoverId`: Currently hovered comment ID for hover effects\n- `render.node`: Assigns [`CommentLeaf`](/docs/components/comment-node) to render comment text marks\n\n### Add Click Handler\n\nAdd click handling to manage active comment state:\n\n```tsx\nexport const commentPlugin = toTPlatePlugin<CommentConfig>(\n  BaseCommentPlugin,\n  ({ editor }) => ({\n    handlers: {\n      // Set active comment when clicking on comment marks\n      onClick: ({ api, event, setOption, type }) => {\n        let leaf = event.target as HTMLElement;\n        let isSet = false;\n\n        const unsetActiveComment = () => {\n          setOption('activeId', null);\n          isSet = true;\n        };\n\n        if (!isSlateString(leaf)) unsetActiveComment();\n\n        while (leaf.parentElement) {\n          if (leaf.classList.contains(`slate-${type}`)) {\n            const commentsEntry = api.comment.node();\n\n            if (!commentsEntry) {\n              unsetActiveComment();\n              break;\n            }\n\n            const id = api.comment.nodeId(commentsEntry[0]);\n            setOption('activeId', id ?? null);\n            isSet = true;\n            break;\n          }\n\n          leaf = leaf.parentElement;\n        }\n\n        if (!isSet) unsetActiveComment();\n      },\n    },\n    // ... previous options and render\n  })\n);\n```\n\nThe click handler tracks which comment is currently active:\n\n- **Detects comment clicks**: Traverses DOM to find comment elements\n- **Sets active state**: Updates `activeId` when clicking on comments\n- **Clears state**: Unsets `activeId` when clicking outside comments\n- **Visual feedback**: Enables hover/active styling in comment components\n\n### Extend Transforms\n\nExtend the `setDraft` transform for enhanced functionality:\n\n```tsx\nexport const commentPlugin = toTPlatePlugin<CommentConfig>(\n  BaseCommentPlugin,\n  ({ editor }) => ({\n    // ... previous configuration\n  })\n)\n  .extendTransforms(\n    ({\n      editor,\n      setOption,\n      tf: {\n        comment: { setDraft },\n      },\n    }) => ({\n      setDraft: () => {\n        if (editor.api.isCollapsed()) {\n          editor.tf.select(editor.api.block()![1]);\n        }\n\n        setDraft();\n\n        editor.tf.collapse();\n        setOption('activeId', getDraftCommentKey());\n        setOption('commentingBlock', editor.selection!.focus.path.slice(0, 1));\n      },\n    })\n  )\n  .configure({\n    node: { component: CommentLeaf },\n    shortcuts: {\n      setDraft: { keys: 'mod+shift+m' },\n    },\n  });\n```\n\n### Add Toolbar Button\n\nYou can add [`CommentToolbarButton`](/docs/components/comment-toolbar-button) to your [Toolbar](/docs/toolbar) to add comments on selected text.\n\n### Add Plugins\n\n```tsx\nimport { createPlateEditor } from 'platejs/react';\n\nconst editor = createPlateEditor({\n  plugins: [\n    // ...otherPlugins,\n    commentPlugin,\n  ],\n});\n```\n\n### Discussion Integration\n\nThe comment plugin works with the [discussion plugin](/docs/discussion) for complete collaboration:\n\n```tsx\nimport { discussionPlugin } from '@/components/editor/plugins/discussion-kit';\n\nconst editor = createPlateEditor({\n  plugins: [\n    // ...otherPlugins,\n    discussionPlugin,\n    commentPlugin,\n  ],\n});\n```\n\n</Steps>\n\n## Keyboard Shortcuts\n\n<KeyTable>\n  <KeyTableItem hotkey=\"Cmd + Shift + M\">\n    Add a comment on the selected text.\n  </KeyTableItem>\n</KeyTable>\n\n## Plate Plus\n\n<ComponentPreviewPro name=\"discussion-pro\" />\n\n## Plugins\n\n### `CommentPlugin`\n\nPlugin for creating and managing text comments with state tracking and discussion integration.\n\n<API name=\"CommentPlugin\">\n  <APIOptions>\n    <APIItem name=\"activeId\" type=\"string | null\">\n      Currently active comment ID for visual highlighting. Used internally to\n      track state.\n    </APIItem>\n    <APIItem name=\"commentingBlock\" type=\"Path | null\">\n      Path of the block currently being commented on.\n    </APIItem>\n    <APIItem name=\"hoverId\" type=\"string | null\">\n      Currently hovered comment ID for hover effects.\n    </APIItem>\n  </APIOptions>\n</API>\n\n## API\n\n### `api.comment.has`\n\nChecks if a comment with the given ID exists in the editor.\n\n<API name=\"has\">\n  <APIParameters>\n    <APIItem name=\"options\" type=\"{ id: string }\">\n      Options containing the comment ID to check.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"boolean\">Whether the comment exists.</APIReturns>\n</API>\n\n### `api.comment.node`\n\nGets a comment node entry.\n\n<API name=\"node\">\n  <APIOptions\n    type=\"EditorNodesOptions & { id?: string; isDraft?: boolean }\"\n    optional\n  >\n    Options for finding the node.\n  </APIOptions>\n  <APIReturns type=\"NodeEntry<TCommentText> | undefined\">\n    The comment node entry if found.\n  </APIReturns>\n</API>\n\n### `api.comment.nodeId`\n\nGets the ID of a comment from a leaf node.\n\n<API name=\"nodeId\">\n  <APIParameters>\n    <APIItem name=\"leaf\" type=\"TCommentText\">\n      The comment leaf node.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"string | undefined\">The comment ID if found.</APIReturns>\n</API>\n\n### `api.comment.nodes`\n\nGets all comment node entries matching the options.\n\n<API name=\"nodes\">\n  <APIOptions\n    type=\"EditorNodesOptions & { id?: string; isDraft?: boolean }\"\n    optional\n  >\n    Options for finding the nodes.\n  </APIOptions>\n  <APIReturns type=\"NodeEntry<TCommentText>[]\">\n    Array of comment node entries.\n  </APIReturns>\n</API>\n\n## Transforms\n\n### `tf.comment.removeMark`\n\nRemoves the comment mark from the current selection or a specified location.\n\n<API name=\"removeMark\" />\n\n### `tf.comment.setDraft`\n\nSets a draft comment mark at the current selection.\n\n<API name=\"setDraft\">\n  <APIOptions type=\"SetNodesOptions\" optional>\n    Options for setting the draft comment.\n  </APIOptions>\n</API>\n\n### `tf.comment.unsetMark`\n\nUnsets comment nodes with the specified ID from the editor.\n\n<API name=\"unsetMark\">\n<APIParameters>\n  <APIItem name=\"options\" type=\"{ id: string; transient?: boolean }\">\n    Options for unsetting comment marks.\n  </APIItem>\n</APIParameters>\n\n<APIOptions type=\"object\">\n  <APIItem name=\"id\" type=\"string\">\n    The comment ID to unset.\n  </APIItem>\n  <APIItem name=\"transient\" type=\"boolean\" optional>\n    When true, removes all AI comments at once.\n    - **Default:** `false`\n  </APIItem>\n</APIOptions>\n</API>\n\n## Utilities\n\n### `getCommentCount`\n\nGets the count of non-draft comments in a comment node.\n\n<API name=\"getCommentCount\">\n  <APIParameters>\n    <APIItem name=\"node\" type=\"TCommentText\">\n      The comment node.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"number\">The count of comments.</APIReturns>\n</API>\n\n### `getCommentKey`\n\nGenerates a comment key based on the provided ID.\n\n<API name=\"getCommentKey\">\n  <APIParameters>\n    <APIItem name=\"id\" type=\"string\">\n      The ID of the comment.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"string\">The generated comment key.</APIReturns>\n</API>\n\n### `getCommentKeyId`\n\nExtracts the comment ID from a comment key.\n\n<API name=\"getCommentKeyId\">\n  <APIParameters>\n    <APIItem name=\"key\" type=\"string\">\n      The comment key.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"string\">The extracted comment ID.</APIReturns>\n</API>\n\n### `getCommentKeys`\n\nReturns an array of comment keys present in the given node.\n\n<API name=\"getCommentKeys\">\n  <APIParameters>\n    <APIItem name=\"node\" type=\"TCommentText\">\n      The node to check for comment keys.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"string[]\">Array of comment keys.</APIReturns>\n</API>\n\n### `getDraftCommentKey`\n\nGets the key used for draft comments.\n\n<API name=\"getDraftCommentKey\">\n  <APIReturns type=\"string\">The draft comment key.</APIReturns>\n</API>\n\n### `isCommentKey`\n\nChecks if a given key is a comment key.\n\n<API name=\"isCommentKey\">\n  <APIParameters>\n    <APIItem name=\"key\" type=\"string\">\n      The key to check.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"boolean\">Whether the key is a comment key.</APIReturns>\n</API>\n\n### `isCommentNodeById`\n\nChecks if a given node is a comment with the specified ID.\n\n<API name=\"isCommentNodeById\">\n  <APIParameters>\n    <APIItem name=\"node\" type=\"TNode\">\n      The node to check.\n    </APIItem>\n    <APIItem name=\"id\" type=\"string\">\n      The ID of the comment.\n    </APIItem>\n  </APIParameters>\n  <APIReturns type=\"boolean\">\n    Whether the node is a comment with the specified ID.\n  </APIReturns>\n</API>\n\n## Types\n\n### `TCommentText`\n\nText nodes that can contain comments.\n\n<API name=\"TCommentText\">\n  <APIAttributes>\n    <APIItem name=\"comment\" type=\"boolean\" optional>\n      Whether this text node contains comments.\n    </APIItem>\n    <APIItem name=\"comment_<id>\" type=\"boolean\" optional>\n      Comment data keyed by comment ID. Multiple comments can exist in one text\n      node.\n    </APIItem>\n  </APIAttributes>\n</API>\n",
      "type": "registry:file",
      "target": "content/docs/plate/(plugins)/(collaboration)/comment.mdx"
    }
  ],
  "type": "registry:file"
}