{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "transforms",
  "dependencies": [
    "@platejs/callout",
    "@platejs/code-block",
    "@platejs/date",
    "@platejs/toc",
    "@platejs/layout",
    "@platejs/link",
    "@platejs/math",
    "@platejs/media",
    "@platejs/table"
  ],
  "files": [
    {
      "path": "src/registry/components/editor/transforms.ts",
      "content": "'use client';\n\nimport type { PlateEditor } from 'platejs/react';\n\nimport { insertCallout } from '@platejs/callout';\nimport { insertCodeBlock, toggleCodeBlock } from '@platejs/code-block';\nimport { insertCodeDrawing } from '@platejs/code-drawing';\nimport { insertDate } from '@platejs/date';\nimport { insertExcalidraw } from '@platejs/excalidraw';\nimport { insertFootnote } from '@platejs/footnote';\nimport { insertColumnGroup, toggleColumnGroup } from '@platejs/layout';\nimport { triggerFloatingLink } from '@platejs/link/react';\nimport { insertEquation, insertInlineEquation } from '@platejs/math';\nimport {\n  insertAudioPlaceholder,\n  insertFilePlaceholder,\n  insertMedia,\n  insertVideoPlaceholder,\n} from '@platejs/media';\nimport { SuggestionPlugin } from '@platejs/suggestion/react';\nimport { TablePlugin } from '@platejs/table/react';\nimport { insertToc } from '@platejs/toc';\nimport {\n  type NodeEntry,\n  type Path,\n  type TElement,\n  KEYS,\n  PathApi,\n} from 'platejs';\n\nconst ACTION_THREE_COLUMNS = 'action_three_columns';\nconst ACTION_FOOTNOTE = 'action_footnote';\n\nconst insertList = (editor: PlateEditor, type: string) => {\n  editor.tf.insertNodes(\n    editor.api.create.block({\n      indent: 1,\n      listStyleType: type,\n    }),\n    { select: true }\n  );\n};\n\nconst createBlockquote = (editor: PlateEditor) => ({\n  children: [editor.api.create.block({ type: KEYS.p })],\n  type: KEYS.blockquote,\n});\n\nconst selectBlockquoteStart = (editor: PlateEditor, path: Path) => {\n  const start = editor.api.start(path.concat([0]));\n\n  if (start) {\n    editor.tf.select(start);\n  }\n};\n\nconst insertBlockMap: Record<\n  string,\n  (editor: PlateEditor, type: string) => void\n> = {\n  [KEYS.listTodo]: insertList,\n  [KEYS.ol]: insertList,\n  [KEYS.ul]: insertList,\n  [ACTION_THREE_COLUMNS]: (editor) =>\n    insertColumnGroup(editor, { columns: 3, select: true }),\n  [KEYS.audio]: (editor) => insertAudioPlaceholder(editor, { select: true }),\n  [KEYS.callout]: (editor) => insertCallout(editor, { select: true }),\n  [KEYS.codeBlock]: (editor) => insertCodeBlock(editor, { select: true }),\n  [KEYS.codeDrawing]: (editor) =>\n    insertCodeDrawing(editor, {}, { select: true }),\n  [KEYS.equation]: (editor) => insertEquation(editor, { select: true }),\n  [KEYS.excalidraw]: (editor) => insertExcalidraw(editor, {}, { select: true }),\n  [KEYS.file]: (editor) => insertFilePlaceholder(editor, { select: true }),\n  [KEYS.img]: (editor) =>\n    insertMedia(editor, {\n      select: true,\n      type: KEYS.img,\n    }),\n  [KEYS.mediaEmbed]: (editor) =>\n    insertMedia(editor, {\n      select: true,\n      type: KEYS.mediaEmbed,\n    }),\n  [KEYS.table]: (editor) =>\n    editor.getTransforms(TablePlugin).insert.table({}, { select: true }),\n  [KEYS.toc]: (editor) => insertToc(editor, { select: true }),\n  [KEYS.video]: (editor) => insertVideoPlaceholder(editor, { select: true }),\n};\n\nconst insertInlineMap: Record<\n  string,\n  (editor: PlateEditor, type: string) => void\n> = {\n  [KEYS.date]: (editor) => insertDate(editor, { select: true }),\n  [ACTION_FOOTNOTE]: (editor) => insertFootnote(editor, { select: true }),\n  [KEYS.inlineEquation]: (editor) =>\n    insertInlineEquation(editor, '', { select: true }),\n  [KEYS.link]: (editor) => triggerFloatingLink(editor, { focused: true }),\n};\n\ntype InsertBlockOptions = {\n  upsert?: boolean;\n};\n\nexport const insertBlock = (\n  editor: PlateEditor,\n  type: string,\n  options: InsertBlockOptions = {}\n) => {\n  const { upsert = false } = options;\n\n  editor.tf.withoutNormalizing(() => {\n    const block = editor.api.block();\n\n    if (!block) return;\n\n    const [currentNode, path] = block;\n    const isCurrentBlockEmpty = editor.api.isEmpty(currentNode);\n    const currentBlockType = getBlockType(currentNode);\n\n    const isSameBlockType = type === currentBlockType;\n\n    if (upsert && isCurrentBlockEmpty && isSameBlockType) {\n      return;\n    }\n\n    if (type === KEYS.blockquote) {\n      const insertPath = PathApi.next(path);\n\n      editor.tf.insertNodes(createBlockquote(editor), { at: insertPath });\n\n      if (!isSameBlockType && isCurrentBlockEmpty) {\n        editor.getApi(SuggestionPlugin).suggestion.withoutSuggestions(() => {\n          editor.tf.removeNodes({ at: path });\n        });\n      }\n\n      selectBlockquoteStart(\n        editor,\n        isCurrentBlockEmpty && !isSameBlockType ? path : insertPath\n      );\n\n      return;\n    }\n    if (type in insertBlockMap) {\n      insertBlockMap[type](editor, type);\n    } else {\n      editor.tf.insertNodes(editor.api.create.block({ type }), {\n        at: PathApi.next(path),\n        select: true,\n      });\n    }\n\n    if (!isSameBlockType) {\n      editor.getApi(SuggestionPlugin).suggestion.withoutSuggestions(() => {\n        editor.tf.removeNodes({ previousEmptyBlock: true });\n      });\n    }\n  });\n};\n\nexport const insertInlineElement = (editor: PlateEditor, type: string) => {\n  if (insertInlineMap[type]) {\n    insertInlineMap[type](editor, type);\n  }\n};\n\nconst setList = (\n  editor: PlateEditor,\n  type: string,\n  entry: NodeEntry<TElement>\n) => {\n  editor.tf.setNodes(\n    editor.api.create.block({\n      indent: 1,\n      listStyleType: type,\n    }),\n    {\n      at: entry[1],\n    }\n  );\n};\n\nconst setBlockMap: Record<\n  string,\n  (editor: PlateEditor, type: string, entry: NodeEntry<TElement>) => void\n> = {\n  [KEYS.listTodo]: setList,\n  [KEYS.ol]: setList,\n  [KEYS.ul]: setList,\n  [ACTION_THREE_COLUMNS]: (editor) => toggleColumnGroup(editor, { columns: 3 }),\n  [KEYS.codeBlock]: (editor) => toggleCodeBlock(editor),\n};\n\nexport const setBlockType = (\n  editor: PlateEditor,\n  type: string,\n  { at }: { at?: Path } = {}\n) => {\n  editor.tf.withoutNormalizing(() => {\n    if (type === KEYS.blockquote) {\n      const target = at ?? editor.selection;\n\n      if (!target || editor.api.some({ at: target, match: { type } })) {\n        return;\n      }\n\n      editor.tf.toggleBlock(type, {\n        ...(at ? { at } : {}),\n        wrap: true,\n      });\n\n      return;\n    }\n\n    const setEntry = (entry: NodeEntry<TElement>) => {\n      const [node, path] = entry;\n\n      if (node[KEYS.listType]) {\n        editor.tf.unsetNodes([KEYS.listType, 'indent'], { at: path });\n      }\n      if (type in setBlockMap) {\n        return setBlockMap[type](editor, type, entry);\n      }\n      if (node.type !== type) {\n        editor.tf.setNodes({ type }, { at: path });\n      }\n    };\n\n    if (at) {\n      const entry = editor.api.node<TElement>(at);\n\n      if (entry) {\n        setEntry(entry);\n\n        return;\n      }\n    }\n\n    const entries = editor.api.blocks({ mode: 'lowest' });\n\n    entries.forEach((entry) => {\n      setEntry(entry);\n    });\n  });\n};\n\nexport const getBlockType = (block: TElement) => {\n  if (block[KEYS.listType]) {\n    if (block[KEYS.listType] === KEYS.ol) {\n      return KEYS.ol;\n    }\n    if (block[KEYS.listType] === KEYS.listTodo) {\n      return KEYS.listTodo;\n    }\n    return KEYS.ul;\n  }\n\n  return block.type;\n};\n",
      "type": "registry:component",
      "target": "@components/editor/transforms.ts"
    }
  ],
  "type": "registry:component"
}