{"version":3,"sources":["../src/components/editors/BlockNoteEditor.tsx","../src/components/editors/BlockNoteEditorFormattingToolbar.tsx"],"sourcesContent":["\"use client\";\n\nimport { BlockNoteSchema, defaultInlineContentSpecs, filterSuggestionItems, PartialBlock } from \"@blocknote/core\";\nimport { en as coreEn } from \"@blocknote/core/locales\";\nimport {\n  createReactInlineContentSpec,\n  DefaultReactSuggestionItem,\n  getDefaultReactSlashMenuItems,\n  SuggestionMenuController,\n  SuggestionMenuProps,\n  useBlockNoteEditor,\n  useCreateBlockNote,\n  useExtension,\n  useExtensionState,\n} from \"@blocknote/react\";\nimport { BlockNoteView } from \"@blocknote/shadcn\";\nimport \"@blocknote/shadcn/style.css\";\nimport {\n  AIExtension,\n  AIMenuController,\n  getAISlashMenuItems,\n  getDefaultAIMenuItems,\n  PromptSuggestionMenu,\n  useAIDictionary,\n} from \"@blocknote/xl-ai\";\nimport { en as aiEn } from \"@blocknote/xl-ai/locales\";\nimport \"@blocknote/xl-ai/style.css\";\nimport { DefaultChatTransport } from \"ai\";\nimport {\n  CheckIcon,\n  LanguagesIcon,\n  LayoutTemplateIcon,\n  SparklesIcon,\n  TypeIcon,\n  WandSparklesIcon,\n  XIcon,\n} from \"lucide-react\";\nimport { useTranslations } from \"next-intl\";\nimport { useTheme } from \"next-themes\";\nimport React, { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { getPublicApiUrl } from \"../../client/config\";\nimport { getClientToken } from \"../../client/token\";\nimport { useCurrentUserContext } from \"../../contexts\";\nimport { S3Interface } from \"../../features/s3/data\";\nimport { S3Service } from \"../../features/s3/data/s3.service\";\nimport { UserInterface } from \"../../features/user/data\";\nimport { useI18nLocale } from \"../../i18n/config\";\nimport { Button } from \"../../shadcnui\";\nimport { BlockNoteDiffUtil, BlockNoteWordDiffRendererUtil, cn } from \"../../utils\";\nimport { errorToast } from \"../errors\";\nimport { BlockNoteEditorFormattingToolbar } from \"./BlockNoteEditorFormattingToolbar\";\nimport { BlockNoteEditorMentionHoverCard } from \"./BlockNoteEditorMentionHoverCard\";\nimport {\n  createMentionInlineContentSpec,\n  type MentionNameResolver,\n  type MentionResolveFn,\n} from \"./BlockNoteEditorMentionInlineContent\";\nimport { BlockNoteEditorMentionSuggestionMenu } from \"./BlockNoteEditorSuggestionMenuController\";\n\nexport type BlockNoteAiConfig = {\n  endpoint: string;\n  entityType: string;\n  entityId?: string;\n};\n\nexport type BlockNoteEditorProps = {\n  id: string;\n  type: string;\n  initialContent?: PartialBlock[];\n  onChange?: (content: any, isEmpty: boolean, hasUnresolvedDiff: boolean) => void;\n  size?: \"sm\" | \"md\";\n  className?: string;\n  markdownContent?: string;\n  diffContent?: PartialBlock[];\n  placeholder?: string;\n  bordered?: boolean;\n  inlineContentSpecs?: Record<string, any>;\n  renderOverlays?: (editor: any) => React.ReactNode;\n  enableMentions?: boolean;\n  disableMentions?: boolean;\n  mentionSearchFn?: (\n    query: string,\n    params?: Record<string, string>,\n  ) => Promise<import(\"./BlockNoteEditorSuggestionMenuController\").MentionItem[]>;\n  mentionSearchParams?: Record<string, string>;\n  mentionResolveFn?: MentionResolveFn;\n  suggestionMenuComponent?: React.FC<SuggestionMenuProps<DefaultReactSuggestionItem>>;\n  mentionNameResolver?: MentionNameResolver;\n  onWarmMentions?: (blocks: PartialBlock[]) => void;\n  aiConfig?: BlockNoteAiConfig;\n  // When the editor is inside a bounded flex column (parent gives it a real\n  // height via flex-1+min-h-0), set this so `.bn-container` shrinks to that\n  // height and scrolls internally. Without it the editor grows to fit its\n  // content and pushes the surrounding form to scroll instead.\n  stretch?: boolean;\n  // Gates AI on top of `aiConfig` (credit availability, etc.). Defaults to\n  // true so existing callers that only pass `aiConfig` are unaffected. When\n  // false, no AI extension is created, the AI toolbar button and AI slash\n  // items are hidden, and the editor falls back to the plain slash menu.\n  aiEnabled?: boolean;\n};\n\nfunction isBlockEmpty(block: any): boolean {\n  if (!block || typeof block !== \"object\") return true;\n  if (block.type !== \"paragraph\") return false;\n  if (Array.isArray(block.children) && block.children.length > 0 && !isDocumentEmpty(block.children)) {\n    return false;\n  }\n  if (Array.isArray(block.content)) {\n    for (const inline of block.content) {\n      if (typeof inline === \"string\") {\n        if (inline.trim()) return false;\n      } else if (inline && typeof inline === \"object\") {\n        if (inline.type !== \"text\") return false;\n        if (typeof inline.text === \"string\" && inline.text.trim()) return false;\n      }\n    }\n  } else if (typeof block.content === \"string\" && block.content.trim()) {\n    return false;\n  }\n  return true;\n}\n\nfunction isDocumentEmpty(blocks: any[]): boolean {\n  if (!Array.isArray(blocks) || blocks.length === 0) return true;\n  return blocks.every(isBlockEmpty);\n}\n\nconst createDiffActionsInlineContentSpec = (\n  handleAcceptChange: (diffId: string) => void,\n  handleRejectChange: (diffId: string) => void,\n) => {\n  return createReactInlineContentSpec(\n    {\n      type: \"diffActions\",\n      propSchema: {\n        diffIds: {\n          default: \"\",\n        },\n      },\n      content: \"none\",\n    },\n    {\n      render: (props) => {\n        const diffIds = props.inlineContent.props.diffIds;\n\n        return (\n          <span className=\"diff-actions-container mx-2 inline-flex items-center gap-1 align-middle\">\n            <Button\n              title=\"Accept change\"\n              onClick={(e) => {\n                e.preventDefault();\n                e.stopPropagation();\n                diffIds.split(\",\").forEach((id: string) => handleAcceptChange(id.trim()));\n              }}\n            >\n              <CheckIcon className=\"text-success h-3 w-3\" />\n            </Button>\n            <Button\n              title=\"Reject change\"\n              className=\"mx-2 p-0\"\n              onClick={(e) => {\n                e.preventDefault();\n                e.stopPropagation();\n                diffIds.split(\",\").forEach((id: string) => handleRejectChange(id.trim()));\n              }}\n            >\n              <XIcon className=\"text-destructive h-3 w-3\" />\n            </Button>\n          </span>\n        );\n      },\n    },\n  );\n};\n\n/**\n * Custom AI menu wrapper. Surfaces our backend-driven action items\n * (Improve Writing, Fix Spelling) above the free-form prompt input.\n *\n * Why a custom wrapper instead of `<AIMenu items={…}>` with the BlockNote\n * defaults: BlockNote's `PromptSuggestionMenu` hijacks Enter to pick the\n * highlighted item whenever `items.length > 0`. We gate items on\n *   - status === \"user-input\"\n *   - editor has a selection\n *   - prompt input is empty\n * so the moment the user types, items disappear and Enter falls back to\n * free-form submission. Outside `user-input` (review / error states) we\n * keep BlockNote's default review buttons (accept/revert/retry/cancel).\n *\n * Each custom item passes a `type` discriminator on `chatRequestOptions.body`.\n * That field flows through `chat.sendMessage(msg, opts)` to the transport's\n * `prepareSendMessagesRequest({messages, body})` (see types.ts in\n * `@blocknote/xl-ai` — `ChatRequestOptions = Parameters<Chat[\"sendMessage\"]>[1]`).\n * The backend dispatcher reads `body.type` and routes to a per-type handler\n * with its own canonical prompt. NO prompt text lives in this file.\n */\nfunction NarrAIMenu() {\n  const editor = useBlockNoteEditor();\n  const ai = useExtension(AIExtension);\n  const dict = useAIDictionary();\n  const status = useExtensionState(AIExtension, {\n    selector: (s) => (s.aiMenuState !== \"closed\" ? s.aiMenuState.status : \"closed\"),\n  });\n  const [prompt, setPrompt] = useState(\"\");\n  // Set by items that pre-fill the input (Translate) so handleSubmit knows\n  // which `type` to attach when the user submits the captured text. Cleared\n  // after submit or on status change.\n  const pendingTypeRef = useRef<string | null>(null);\n\n  useEffect(() => {\n    if (status === \"ai-writing\" || status === \"user-reviewing\" || status === \"error\" || status === \"closed\") {\n      setPrompt(\"\");\n      pendingTypeRef.current = null;\n    }\n  }, [status]);\n\n  // Selection-edit ops operate per-block. If the user's selection only\n  // covers part of a block (cursor mid-paragraph dragged to mid-next), the\n  // rewrite would silently replace the WHOLE containing blocks — beyond\n  // what the user highlighted. Expand the selection to whole-block bounds\n  // BEFORE invokeAI so the user sees exactly what will be rewritten.\n  const expandSelectionToBlocks = useCallback(() => {\n    const sel = editor.getSelection?.();\n    const blocks = (sel as any)?.blocks;\n    if (!Array.isArray(blocks) || blocks.length === 0) return;\n    const first = blocks[0];\n    const last = blocks[blocks.length - 1];\n    try {\n      (editor as any).setSelection?.(first, last);\n    } catch {\n      // If BlockNote's setSelection signature changes, fail silently — the\n      // backend still operates per-block, so we just lose the visual hint.\n    }\n  }, [editor]);\n\n  const items = useMemo(() => {\n    // Outside user-input (reviewing / error), use BlockNote's default\n    // review buttons (accept/revert/retry/cancel). Need to wrap onItemClick\n    // because the default items expect a setPrompt argument.\n    if (status !== \"user-input\") {\n      return getDefaultAIMenuItems(editor, status).map((item) => ({\n        ...item,\n        onItemClick: () => item.onItemClick(setPrompt),\n      }));\n    }\n    const hasSelection = editor.getSelection() !== undefined;\n    const hasTyped = prompt.trim().length > 0;\n    // Once the user starts typing, hide all items so Enter submits the\n    // free-form (or pending-type) prompt instead of being hijacked.\n    if (hasTyped) return [];\n\n    // Generate from Template is shown in BOTH contexts (with and without\n    // selection) because it operates on the whole document — it ignores any\n    // active selection and runs the per-section template-fill flow. Listed\n    // first so it's the default-highlighted item.\n    const generateFromTemplate = {\n      key: \"generate_from_template\",\n      title: \"Generate from Template\",\n      aliases: [\"generate\", \"template\", \"fill\"],\n      icon: <LayoutTemplateIcon size={18} />,\n      size: \"small\" as const,\n      onItemClick: () => {\n        void ai.invokeAI({\n          userPrompt: \"fill-template\",\n          useSelection: false,\n          chatRequestOptions: { body: { type: \"fill-template\" } },\n        });\n      },\n    };\n\n    if (hasSelection) {\n      // Selection-edit items + the always-available Generate from Template.\n      // Each selection item invokes ai.invokeAI with chatRequestOptions\n      // carrying the `type` body field. The userPrompt is a short tag — the\n      // backend ignores it and uses the canonical prompt for the type instead.\n      return [\n        generateFromTemplate,\n        {\n          key: \"improve_writing\",\n          title: \"Improve Writing\",\n          aliases: [\"improve\", \"rewrite\", \"polish\"],\n          icon: <SparklesIcon size={18} />,\n          size: \"small\" as const,\n          onItemClick: () => {\n            expandSelectionToBlocks();\n            void ai.invokeAI({\n              userPrompt: \"improve-writing\",\n              useSelection: true,\n              chatRequestOptions: { body: { type: \"improve-writing\" } },\n            });\n          },\n        },\n        {\n          key: \"fix_spelling\",\n          title: \"Fix Spelling\",\n          aliases: [\"spelling\", \"grammar\", \"typo\"],\n          icon: <TypeIcon size={18} />,\n          size: \"small\" as const,\n          onItemClick: () => {\n            expandSelectionToBlocks();\n            void ai.invokeAI({\n              userPrompt: \"fix-spelling\",\n              useSelection: true,\n              chatRequestOptions: { body: { type: \"fix-spelling\" } },\n            });\n          },\n        },\n        {\n          key: \"translate\",\n          title: \"Translate…\",\n          aliases: [\"translate\", \"language\"],\n          icon: <LanguagesIcon size={18} />,\n          size: \"small\" as const,\n          // Pre-fills the input with a placeholder. User appends/replaces\n          // with the target language and submits via Enter. handleSubmit\n          // reads pendingTypeRef and forwards `type: \"translate\"`. We\n          // expand the selection now so the user sees the scope before\n          // typing the language — handleSubmit doesn't re-expand.\n          onItemClick: () => {\n            expandSelectionToBlocks();\n            pendingTypeRef.current = \"translate\";\n            setPrompt(\"Translate to \");\n          },\n        },\n        {\n          key: \"simplify\",\n          title: \"Simplify\",\n          aliases: [\"simplify\", \"easier\", \"plain\"],\n          icon: <WandSparklesIcon size={18} />,\n          size: \"small\" as const,\n          onItemClick: () => {\n            expandSelectionToBlocks();\n            void ai.invokeAI({\n              userPrompt: \"simplify\",\n              useSelection: true,\n              chatRequestOptions: { body: { type: \"simplify\" } },\n            });\n          },\n        },\n      ];\n    }\n\n    // No selection (the /ai slash menu path): just Generate from Template.\n    // Free-form typing still works — once the user types, items hide and\n    // Enter submits with no type (backend defaults to fill-template).\n    return [generateFromTemplate];\n  }, [editor, status, prompt, ai, expandSelectionToBlocks]);\n\n  const handleSubmit = useCallback(\n    async (userPrompt: string) => {\n      if (!userPrompt.trim()) return;\n      const pendingType = pendingTypeRef.current;\n      pendingTypeRef.current = null;\n      const body = pendingType ? { type: pendingType } : undefined;\n      await ai.invokeAI({\n        userPrompt,\n        useSelection: editor.getSelection() !== undefined,\n        ...(body ? { chatRequestOptions: { body } } : {}),\n      });\n    },\n    [ai, editor],\n  );\n\n  const placeholder =\n    status === \"thinking\"\n      ? dict.ai_menu.status.thinking\n      : status === \"ai-writing\"\n        ? dict.ai_menu.status.editing\n        : status === \"error\"\n          ? dict.ai_menu.status.error\n          : dict.ai_menu.input_placeholder;\n\n  const disabled = status === \"thinking\" || status === \"ai-writing\";\n\n  return (\n    <PromptSuggestionMenu\n      items={items}\n      onManualPromptSubmit={handleSubmit}\n      promptText={prompt}\n      onPromptTextChange={setPrompt}\n      placeholder={placeholder}\n      disabled={disabled}\n      icon={\n        <div className=\"bn-combobox-icon\">\n          <SparklesIcon size={16} />\n        </div>\n      }\n    />\n  );\n}\n\nexport default function BlockNoteEditor({\n  id,\n  type,\n  initialContent,\n  onChange,\n  size,\n  className,\n  markdownContent,\n  diffContent,\n  placeholder,\n  bordered,\n  inlineContentSpecs,\n  renderOverlays,\n  enableMentions,\n  disableMentions,\n  mentionSearchFn,\n  mentionSearchParams,\n  mentionResolveFn,\n  suggestionMenuComponent,\n  mentionNameResolver,\n  onWarmMentions,\n  aiConfig,\n  stretch,\n  aiEnabled = true,\n}: BlockNoteEditorProps): React.JSX.Element {\n  const t = useTranslations();\n  const locale = useI18nLocale();\n  const { resolvedTheme } = useTheme();\n  const { company } = useCurrentUserContext<UserInterface>();\n\n  const [acceptedChanges, setAcceptedChanges] = useState<Set<string>>(new Set());\n  const [rejectedChanges, setRejectedChanges] = useState<Set<string>>(new Set());\n\n  const editorRef = useRef<HTMLDivElement>(null);\n\n  // Ensure side menu buttons don't trigger form submission\n  useEffect(() => {\n    if (!editorRef.current) return;\n    const setButtonTypes = () => {\n      editorRef.current?.querySelectorAll(\".bn-side-menu button\").forEach((btn) => {\n        if (!btn.getAttribute(\"type\")) {\n          btn.setAttribute(\"type\", \"button\");\n        }\n      });\n    };\n    const observer = new MutationObserver(setButtonTypes);\n    observer.observe(editorRef.current, { childList: true, subtree: true });\n    return () => observer.disconnect();\n  }, []);\n\n  const handleAcceptChange = useCallback((diffId: string) => {\n    setAcceptedChanges((prev) => new Set([...prev, diffId]));\n    setRejectedChanges((prev) => {\n      const newSet = new Set(prev);\n      newSet.delete(diffId);\n      return newSet;\n    });\n  }, []);\n\n  const handleRejectChange = useCallback((diffId: string) => {\n    setRejectedChanges((prev) => new Set([...prev, diffId]));\n    setAcceptedChanges((prev) => {\n      const newSet = new Set(prev);\n      newSet.delete(diffId);\n      return newSet;\n    });\n  }, []);\n\n  const DiffActionsInlineContent = useMemo(\n    () => createDiffActionsInlineContentSpec(handleAcceptChange, handleRejectChange),\n    [handleAcceptChange, handleRejectChange],\n  );\n\n  const mentionSpec = useMemo(\n    () => createMentionInlineContentSpec(mentionResolveFn, disableMentions, mentionNameResolver),\n    [disableMentions, mentionResolveFn, mentionNameResolver],\n  );\n\n  const schema = useMemo(\n    () =>\n      BlockNoteSchema.create({\n        inlineContentSpecs: {\n          ...defaultInlineContentSpecs,\n          diffActions: DiffActionsInlineContent,\n          mention: mentionSpec,\n          ...inlineContentSpecs,\n        },\n      } as any),\n    [DiffActionsInlineContent, mentionSpec, inlineContentSpecs],\n  );\n\n  const docRef = useRef<{ getDoc: () => any[] }>({ getDoc: () => [] });\n  // Selection getter used by the AI transport to attach `selectionBlocks` to\n  // the outgoing request metadata. Populated in a useEffect once the editor\n  // instance exists; reads the current BlockNote selection on every send.\n  const selectionRef = useRef<{ getSelectedBlocks: () => any[] }>({ getSelectedBlocks: () => [] });\n\n  const companyId = company?.id;\n  const aiExtension = useMemo(() => {\n    if (!aiConfig || !aiEnabled) return undefined;\n    const base = getPublicApiUrl();\n    const url = new URL(aiConfig.endpoint, base.endsWith(\"/\") ? base : base + \"/\").toString();\n    return AIExtension({\n      transport: new DefaultChatTransport({\n        api: url,\n        credentials: \"include\",\n        headers: async () => {\n          const headers: Record<string, string> = { \"x-language\": locale };\n          const token = await getClientToken();\n          if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n          if (companyId) headers[\"x-companyid\"] = companyId;\n          return headers;\n        },\n        prepareSendMessagesRequest: ({ messages, body }: any) => {\n          let lastUserIdx = -1;\n          for (let i = messages.length - 1; i >= 0; i--) {\n            if (messages[i]?.role === \"user\") {\n              lastUserIdx = i;\n              break;\n            }\n          }\n          const selectedBlocks = selectionRef.current.getSelectedBlocks();\n          const augmented = messages.map((m: any, i: number) =>\n            i === lastUserIdx\n              ? {\n                  ...m,\n                  metadata: {\n                    ...(m.metadata ?? {}),\n                    entityType: aiConfig.entityType,\n                    entityId: aiConfig.entityId,\n                    blocks: docRef.current.getDoc(),\n                    selectionBlocks: selectedBlocks,\n                  },\n                }\n              : m,\n          );\n          return { body: { ...(body ?? {}), messages: augmented } };\n        },\n      }),\n    });\n  }, [aiConfig, aiEnabled, companyId, locale]);\n\n  const uploadImage = useCallback(\n    async (file: File): Promise<string> => {\n      if (!company) {\n        errorToast({\n          title: t(`common.errors.upload`),\n          error: t(`common.errors.upload_description`),\n        });\n        throw new Error(t(`common.errors.upload`));\n      }\n\n      const fileType = file.type;\n      const key = `companies/${company.id}/${type}/${id}/${file.name}`;\n\n      const s3: S3Interface = await S3Service.getPreSignedUrl({\n        key: key,\n        contentType: fileType,\n        isPublic: true,\n      });\n\n      await fetch(s3.url, {\n        method: \"PUT\",\n        headers: s3.headers,\n        body: file,\n      });\n\n      const signedImage: S3Interface = await S3Service.getSignedUrl({\n        key: key,\n        isPublic: true,\n      });\n\n      return signedImage.url;\n    },\n    [company, id, t],\n  );\n\n  // Utility: Remove trailing empty blocks for read-only display\n  const removeTrailingEmptyBlocks = useCallback(\n    (blocks: PartialBlock[]): PartialBlock[] => {\n      if (!blocks || blocks.length === 0) return blocks;\n\n      // Only remove trailing empty blocks in read-only mode\n      if (onChange !== undefined) return blocks;\n\n      const result = [...blocks];\n\n      // Remove trailing empty paragraph blocks, but keep at least one block\n      while (result.length > 1) {\n        const lastBlock = result[result.length - 1];\n\n        // Check if it's an empty paragraph\n        const isEmptyParagraph =\n          lastBlock.type === \"paragraph\" &&\n          (!lastBlock.content ||\n            lastBlock.content.length === 0 ||\n            (Array.isArray(lastBlock.content) && lastBlock.content.every((c: any) => !c.text || c.text.trim() === \"\")));\n\n        if (isEmptyParagraph) {\n          result.pop();\n        } else {\n          break;\n        }\n      }\n\n      return result;\n    },\n    [onChange],\n  );\n\n  const processedContent = useMemo(() => {\n    if (diffContent && initialContent) {\n      try {\n        const diffResult = BlockNoteDiffUtil.diff(initialContent, diffContent);\n        const renderedDiff = BlockNoteWordDiffRendererUtil.renderWordDiffs(\n          diffResult.blocks,\n          handleAcceptChange,\n          handleRejectChange,\n          acceptedChanges,\n          rejectedChanges,\n        );\n        return removeTrailingEmptyBlocks(renderedDiff);\n      } catch (_error) {\n        return initialContent && Array.isArray(initialContent) && initialContent.length > 0\n          ? removeTrailingEmptyBlocks(initialContent)\n          : [];\n      }\n    }\n\n    if (!initialContent) {\n      return [];\n    }\n\n    if (!Array.isArray(initialContent)) {\n      return [];\n    }\n\n    return initialContent.length > 0 ? removeTrailingEmptyBlocks(initialContent) : [];\n  }, [\n    initialContent,\n    diffContent,\n    handleAcceptChange,\n    handleRejectChange,\n    acceptedChanges,\n    rejectedChanges,\n    removeTrailingEmptyBlocks,\n  ]);\n\n  const validatedInitialContent = useMemo(() => {\n    if (processedContent && Array.isArray(processedContent) && processedContent.length > 0) {\n      const validatedContent = processedContent.filter((block) => {\n        if (!block || typeof block !== \"object\") return false;\n        if (!(block as any).type) return false;\n        return true;\n      });\n      return validatedContent.length > 0 ? (validatedContent as PartialBlock[]) : undefined;\n    }\n    return undefined;\n  }, [processedContent]);\n\n  const editor = useCreateBlockNote(\n    useMemo(\n      () => ({\n        placeholders: {\n          emptyDocument: placeholder || t(`common.blocknote.placeholder`),\n        },\n        schema,\n        initialContent: validatedInitialContent,\n        uploadFile: uploadImage,\n        extensions: aiExtension ? [aiExtension] : undefined,\n        dictionary: aiExtension ? { ...coreEn, ai: aiEn } : undefined,\n      }),\n      [placeholder, t, schema, validatedInitialContent, uploadImage, aiExtension],\n    ),\n  );\n\n  // Tracks the hash of the document the editor itself just emitted via onChange.\n  // The sync effect below uses it to skip replaceBlocks when the parent's\n  // initialContent is just an echo of our own emission (form-controlled flow).\n  const lastEmittedHashRef = useRef<string | null>(null);\n\n  const handleChange = useCallback(async () => {\n    if (!onChange) return;\n    const newBlocks = editor.document;\n    lastEmittedHashRef.current = JSON.stringify(newBlocks);\n    const isEmpty = isDocumentEmpty(newBlocks);\n\n    function hasUnresolvedDiffsRecursive(block: any): boolean {\n      if (!block || typeof block !== \"object\") return false;\n      let diffId = undefined;\n      if (block.props && block.props.diffId) diffId = block.props.diffId;\n      if (!diffId && block.attrs && block.attrs.diffId) diffId = block.attrs.diffId;\n      if (diffId && !acceptedChanges.has(diffId) && !rejectedChanges.has(diffId)) {\n        return true;\n      }\n\n      if (block.content) {\n        const contentArr = Array.isArray(block.content) ? block.content : [block.content];\n        for (const inline of contentArr) {\n          if (inline && typeof inline === \"object\") {\n            if (inline.type === \"diffActions\" && inline.props && inline.props.diffIds) {\n              const ids =\n                typeof inline.props.diffIds === \"string\" ? inline.props.diffIds.split(\",\") : inline.props.diffIds;\n              for (const id of ids) {\n                const trimmed = (id || \"\").toString().trim();\n                if (trimmed && !acceptedChanges.has(trimmed) && !rejectedChanges.has(trimmed)) {\n                  return true;\n                }\n              }\n            }\n            if (inline.props && inline.props.diffId) {\n              const diffIdInline = inline.props.diffId;\n              if (diffIdInline && !acceptedChanges.has(diffIdInline) && !rejectedChanges.has(diffIdInline)) {\n                return true;\n              }\n            }\n            if (inline.children && Array.isArray(inline.children)) {\n              for (const child of inline.children) {\n                if (hasUnresolvedDiffsRecursive(child)) return true;\n              }\n            }\n          }\n        }\n      }\n      if (Array.isArray(block.children)) {\n        for (const child of block.children) {\n          if (hasUnresolvedDiffsRecursive(child)) return true;\n        }\n      }\n      return false;\n    }\n\n    let hasUnresolvedDiff = false;\n    if (Array.isArray(newBlocks)) {\n      hasUnresolvedDiff = newBlocks.some((block: any) => hasUnresolvedDiffsRecursive(block));\n    }\n\n    onChange(newBlocks, isEmpty, hasUnresolvedDiff);\n  }, [editor, onChange, id, acceptedChanges, rejectedChanges]);\n\n  // Utility: deep equality for arrays of blocks\n  const areBlocksEqual = (a: any[], b: any[]): boolean => {\n    return JSON.stringify(a) === JSON.stringify(b);\n  };\n\n  // Only initialize from markdownContent once per value, and only if different\n  const hasInitializedFromMarkdown = useRef<string | null>(null);\n  useEffect(() => {\n    const updateContent = async (markdown: string) => {\n      const blocks = await editor.tryParseMarkdownToBlocks(markdown);\n      if (!areBlocksEqual(blocks, editor.document)) {\n        editor.replaceBlocks(editor.document, blocks);\n      }\n    };\n\n    if (markdownContent && hasInitializedFromMarkdown.current !== markdownContent) {\n      hasInitializedFromMarkdown.current = markdownContent;\n      updateContent(markdownContent).then(() => handleChange());\n    }\n  }, [markdownContent, editor]);\n\n  // Update editor content when diff content changes, but only if different\n  // Prevent unnecessary replaceBlocks calls that reset scroll/cursor.\n  const previousContentHashRef = useRef<string | null>(null);\n  useEffect(() => {\n    if (!processedContent || !editor) return;\n    const hash = JSON.stringify(processedContent);\n    if (previousContentHashRef.current === hash) return; // no changes\n    // Skip replaceBlocks when the new initialContent is just an echo of what\n    // the editor itself emitted. Without this, a form-controlled parent\n    // (FormBlockNote) round-trips field.value back as initialContent on every\n    // keystroke and triggers replaceBlocks, which resets the cursor and can\n    // strip just-inserted inline content like mentions.\n    if (lastEmittedHashRef.current === hash) {\n      previousContentHashRef.current = hash;\n      return;\n    }\n    const currentHash = JSON.stringify(editor.document);\n    if (currentHash === hash) {\n      previousContentHashRef.current = hash;\n      return; // already in sync\n    }\n    editor.replaceBlocks(editor.document, processedContent as PartialBlock[]);\n    previousContentHashRef.current = hash;\n  }, [processedContent, editor]);\n\n  useEffect(() => {\n    if (!onWarmMentions || !initialContent || !Array.isArray(initialContent) || initialContent.length === 0) return;\n    onWarmMentions(initialContent);\n  }, [onWarmMentions, initialContent]);\n\n  useEffect(() => {\n    docRef.current.getDoc = () => editor?.document ?? [];\n    selectionRef.current.getSelectedBlocks = () => {\n      const sel = editor?.getSelection?.();\n      const blocks = (sel as any)?.blocks;\n      return Array.isArray(blocks) ? blocks : [];\n    };\n  }, [editor]);\n\n  // Handle audio received from whisper transcription\n  const _handleAudioReceived = useCallback(\n    (message: string) => {\n      try {\n        // Ensure the editor has focus\n        const editorElement = editorRef.current?.querySelector('[contenteditable=\"true\"]') as HTMLElement;\n        if (editorElement && document.activeElement !== editorElement) {\n          editorElement.focus();\n        }\n\n        // Insert the transcribed text at the current cursor position\n        editor.insertInlineContent(message);\n      } catch (error) {\n        console.error(\"Error inserting transcribed text:\", error);\n        // Fallback: try to insert at the end of the document\n        try {\n          const blocks = editor.document;\n          if (blocks.length > 0) {\n            const lastBlock = blocks[blocks.length - 1];\n            editor.setTextCursorPosition(lastBlock.id, \"end\");\n            editor.insertInlineContent(message);\n          }\n        } catch (fallbackError) {\n          console.error(\"Fallback insertion also failed:\", fallbackError);\n        }\n      }\n    },\n    [editor],\n  );\n\n  return (\n    <div\n      ref={editorRef}\n      className={cn(\n        bordered ? \"rounded-md border border-input bg-input/20 dark:bg-input/30\" : \"\",\n        \"flex flex-col w-full\",\n        // Pin BlockNote's font-size so it doesn't jump from 14→16px when the\n        // xl-ai AIMenu mounts. The shadcn theme sets `.bn-default-styles {\n        // font-size: 16px }` explicitly; outside AI mode the form's text-sm\n        // wins via cascade, but ForkYDocExtension re-evaluates the style\n        // context on AI activation and the explicit 16px takes over.\n        \"[&_.bn-default-styles]:!text-sm\",\n        className,\n      )}\n    >\n      <BlockNoteView\n        editor={editor}\n        onChange={handleChange}\n        editable={onChange !== undefined}\n        formattingToolbar={false}\n        slashMenu={!aiConfig || !aiEnabled}\n        // Follow the app theme: hardcoding \"light\" leaves dark (light-theme)\n        // text on the dark card, which is nearly unreadable in dark mode.\n        theme={resolvedTheme === \"dark\" ? \"dark\" : \"light\"}\n        // `className` is applied by BlockNote to both the main `.bn-container`\n        // AND `editor.portalElement` (the floating-UI portal root). Gate `p-4`\n        // on `.bn-container` so it doesn't add padding to the empty portal\n        // element and produce a phantom scrollbar on the wrapper.\n        className={cn(\n          \"BlockNoteView flex-1\",\n          onChange && \"[&.bn-container]:p-4\",\n          // In stretch mode the parent chain caps our height via flex; without\n          // these two classes the `.bn-container` keeps `min-height: auto`\n          // (its content's intrinsic height) and pushes the bordered wrapper\n          // — and the surrounding EditorSheet form — to scroll instead of\n          // scrolling internally.\n          onChange && stretch && \"[&.bn-container]:min-h-0 [&.bn-container]:overflow-y-auto\",\n          size === \"sm\" && \"small\",\n        )}\n      >\n        <BlockNoteEditorFormattingToolbar showAI={!!aiConfig && aiEnabled} />\n        {enableMentions && mentionSearchFn && (\n          <BlockNoteEditorMentionSuggestionMenu\n            editor={editor}\n            mentionSearchFn={mentionSearchFn}\n            mentionSearchParams={mentionSearchParams}\n            suggestionMenuComponent={suggestionMenuComponent}\n          />\n        )}\n        {renderOverlays?.(editor)}\n        {enableMentions && mentionResolveFn && (\n          <BlockNoteEditorMentionHoverCard containerRef={editorRef} mentionResolveFn={mentionResolveFn} />\n        )}\n        {aiConfig && aiEnabled && (\n          <SuggestionMenuController\n            triggerCharacter=\"/\"\n            getItems={async (query: string) =>\n              filterSuggestionItems([...getDefaultReactSlashMenuItems(editor), ...getAISlashMenuItems(editor)], query)\n            }\n          />\n        )}\n        {aiConfig && aiEnabled && <AIMenuController aiMenu={() => <NarrAIMenu />} />}\n      </BlockNoteView>\n    </div>\n  );\n}\n","\"use client\";\n\nimport {\n  BasicTextStyleButton,\n  BlockTypeSelect,\n  CreateLinkButton,\n  FileCaptionButton,\n  FileReplaceButton,\n  FormattingToolbar,\n  FormattingToolbarController,\n  TextAlignButton,\n} from \"@blocknote/react\";\nimport { AIToolbarButton } from \"@blocknote/xl-ai\";\n\nexport function BlockNoteEditorFormattingToolbar({ showAI = false }: { showAI?: boolean }) {\n  return (\n    <FormattingToolbarController\n      formattingToolbar={() => (\n        <FormattingToolbar>\n          <BlockTypeSelect key={\"blockTypeSelect\"} />\n\n          <FileCaptionButton key={\"fileCaptionButton\"} />\n          <FileReplaceButton key={\"replaceFileButton\"} />\n\n          <BasicTextStyleButton basicTextStyle={\"bold\"} key={\"boldStyleButton\"} />\n          <BasicTextStyleButton basicTextStyle={\"italic\"} key={\"italicStyleButton\"} />\n          <BasicTextStyleButton basicTextStyle={\"underline\"} key={\"underlineStyleButton\"} />\n          <BasicTextStyleButton basicTextStyle={\"strike\"} key={\"strikeStyleButton\"} />\n\n          <TextAlignButton textAlignment={\"left\"} key={\"textAlignLeftButton\"} />\n          <TextAlignButton textAlignment={\"center\"} key={\"textAlignCenterButton\"} />\n          <TextAlignButton textAlignment={\"right\"} key={\"textAlignRightButton\"} />\n\n          <CreateLinkButton key={\"createLinkButton\"} />\n\n          {showAI ? <AIToolbarButton key={\"aiToolbarButton\"} /> : null}\n        </FormattingToolbar>\n      )}\n    />\n  );\n}\n"],"mappings":"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","names":["jsx","jsxs","id"]}