{
  "name": "solid-ui-code-block-view",
  "title": "solid-ui-code-block-view",
  "type": "registry:component",
  "description": "",
  "registryDependencies": [],
  "dependencies": [
    "beautiful-mermaid",
    "prosekit@^0.22.0"
  ],
  "files": [
    {
      "path": "registry/src/solid/ui/code-block-view/code-block-view.tsx",
      "type": "registry:component",
      "target": "components/editor/ui/code-block-view/code-block-view.tsx",
      "content": "import { renderMermaidSVG, THEMES } from 'beautiful-mermaid'\nimport { isCodeBlockPreviewHiddenDecoration, shikiBundledLanguagesInfo, type CodeBlockAttrs } from 'prosekit/extensions/code-block'\nimport { TextSelection } from 'prosekit/pm/state'\nimport type { SolidNodeViewProps } from 'prosekit/solid'\nimport { createMemo, For, Show, type JSX } from 'solid-js'\n\nexport default function CodeBlockView(props: SolidNodeViewProps): JSX.Element {\n  const attrs = () => props.node.attrs as CodeBlockAttrs\n  const language = () => attrs().language || ''\n  const hidePreview = () => props.decorations.some(isCodeBlockPreviewHiddenDecoration)\n  const showMermaidPreview = () => !hidePreview() && language() === 'mermaid'\n  let preRef: HTMLPreElement | undefined\n\n  const mermaidPreview = createMemo<{ svg: string | null; error: Error | null }>(() => {\n    if (language() !== 'mermaid') return { svg: null, error: null }\n    try {\n      return { svg: renderMermaidSVG(props.node.textContent, THEMES['tokyo-night']), error: null }\n    } catch (err) {\n      return { svg: null, error: err instanceof Error ? err : new Error(String(err)) }\n    }\n  })\n\n  const setLanguage = (lang: string) => {\n    const newAttrs: CodeBlockAttrs = { language: lang }\n    props.setAttrs(newAttrs)\n  }\n\n  const focusSource = (event: MouseEvent) => {\n    event.preventDefault()\n    const pos = props.getPos()\n    if (typeof pos !== 'number') return\n    const { state, dispatch } = props.view\n    const selection = TextSelection.near(state.doc.resolve(pos + 1), 1)\n    dispatch(state.tr.setSelection(selection))\n    props.view.focus()\n    preRef?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })\n  }\n\n  return (\n    <>\n      <div\n        class=\"relative mx-2 top-3 h-0 select-none overflow-visible text-xs data-preview:hidden\"\n        contentEditable={false}\n        data-preview={showMermaidPreview() ? '' : undefined}\n      >\n        <select\n          aria-label=\"Code block language\"\n          class=\"outline-unset focus:outline-unset relative box-border w-auto cursor-pointer select-none appearance-none rounded-sm border-none bg-transparent px-2 py-1 text-xs transition text-(--prosemirror-highlight) opacity-0 hover:opacity-80 [div[data-node-view-root]:hover_&]:opacity-50 hover:[div[data-node-view-root]:hover_&]:opacity-80\"\n          onChange={(event) => setLanguage(event.target.value)}\n          value={language()}\n        >\n          <option value=\"\">Plain Text</option>\n          <For each={shikiBundledLanguagesInfo}>\n            {(info) => (\n              <option value={info.id}>\n                {info.name}\n              </option>\n            )}\n          </For>\n        </select>\n      </div>\n      <pre\n        ref={(element) => {\n          props.contentRef(element)\n          preRef = element\n        }}\n        class=\"data-preview:hidden\"\n        data-preview={showMermaidPreview() ? '' : undefined}\n        data-language={language()}\n      ></pre>\n      <Show when={showMermaidPreview()}>\n        <div\n          aria-label=\"Edit source\"\n          class=\"block py-2 overflow-auto\"\n          contentEditable={false}\n          onMouseDown={focusSource}\n        >\n          <Show when={mermaidPreview().error}>\n            <pre>{mermaidPreview().error?.message}</pre>\n          </Show>\n          <Show when={mermaidPreview().svg}>\n            <div innerHTML={mermaidPreview().svg || ''}></div>\n          </Show>\n        </div>\n      </Show>\n    </>\n  )\n}\n"
    },
    {
      "path": "registry/src/solid/ui/code-block-view/index.ts",
      "type": "registry:component",
      "target": "components/editor/ui/code-block-view/index.ts",
      "content": "import type { Extension } from 'prosekit/core'\nimport { defineSolidNodeView, type SolidNodeViewComponent } from 'prosekit/solid'\n\nimport CodeBlockView from './code-block-view.tsx'\n\nexport function defineCodeBlockView(): Extension {\n  return defineSolidNodeView({\n    name: 'codeBlock',\n    contentAs: 'code',\n    component: CodeBlockView satisfies SolidNodeViewComponent,\n  })\n}\n"
    }
  ],
  "meta": {
    "hasIcons": false,
    "hidden": false,
    "story": "",
    "framework": "solid",
    "accumulatedFiles": [
      "registry/src/solid/ui/code-block-view/code-block-view.tsx",
      "registry/src/solid/ui/code-block-view/index.ts"
    ],
    "internalDependencies": []
  },
  "$schema": "https://ui.shadcn.com/schema/registry-item.json"
}
