@monaco-ai-editor/react 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +904 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +168 -0
- package/dist/index.d.ts +168 -0
- package/dist/index.js +870 -0
- package/dist/index.js.map +1 -0
- package/dist/vite/monacoAssetsPlugin.cjs +129 -0
- package/dist/vite/monacoAssetsPlugin.cjs.map +1 -0
- package/dist/vite/monacoAssetsPlugin.d.cts +36 -0
- package/dist/vite/monacoAssetsPlugin.d.ts +36 -0
- package/dist/vite/monacoAssetsPlugin.js +94 -0
- package/dist/vite/monacoAssetsPlugin.js.map +1 -0
- package/package.json +52 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/EditorPanel.tsx","../src/hooks/useOptionalCoordinator.ts","../src/context/internal.ts","../src/components/AiChatPanel.tsx","../src/components/Toolbar.tsx","../src/components/StatusBar.tsx","../src/components/MonacoAiEditor.tsx","../src/context/EditorCoordinator.tsx","../src/utils/configureMonaco.ts","../src/index.ts"],"sourcesContent":["import { type FC, useRef, useEffect, useState, useMemo } from 'react';\nimport Editor, { loader, type OnMount, type BeforeMount } from '@monaco-editor/react';\nimport type * as MonacoType from 'monaco-editor';\nimport {\n EditorController,\n registerSqlCompletion,\n registerAiInlineCompletion,\n registerAiCompletionCommand,\n type ApiConfig,\n type SqlSchema,\n type CompletionProvider,\n type PendingCompletion,\n} from '@monaco-ai-editor/core';\nimport { useOptionalCoordinator } from '../hooks/useOptionalCoordinator';\n\nexport interface EditorPanelProps {\n /** 受控/非受控通用:初始值(独立模式下使用) */\n value?: string;\n onChange?: (value: string) => void;\n language?: string;\n theme?: string;\n\n /** 高级:自定义 Monaco loader 路径(默认走 CDN) */\n vsPath?: string;\n\n /** SQL 表结构(启用 SQL 时) */\n sqlSchema?: SqlSchema;\n\n /**\n * 需要从内置 SQL 关键字/函数补全中排除的 label(大写不敏感)。\n * 用于让 completionProviders 中的自定义同名词条覆盖内置项,避免重复提示。\n */\n builtinSqlExcludeLabels?: string[];\n\n /** AI 配置(用于 Ctrl+Alt+L 触发的 AI 行内补全) */\n apiConfig?: ApiConfig | null;\n\n /** 自定义补全扩展 */\n completionProviders?: CompletionProvider[];\n\n /** Monaco 实例就绪回调(拿到 controller) */\n onMount?: (controller: EditorController) => void;\n\n /**\n * 右侧代码缩略图(minimap)配置。\n * - 传 `true`/`false` 快捷开关\n * - 传对象可细粒度自定义(仅覆盖指定字段,其余沿用默认值)\n * - 默认开启\n */\n minimap?: boolean | MonacoType.editor.IEditorMinimapOptions;\n\n /** 自定义 Monaco editor options */\n editorOptions?: MonacoType.editor.IStandaloneEditorConstructionOptions;\n\n /** AI 补全错误回调 */\n onAiError?: (message: string) => void;\n\n /** 容器样式类 */\n className?: string;\n\n /** 编辑器加载时的占位内容(覆盖 @monaco-editor/react 默认的 \"Loading...\") */\n loading?: React.ReactNode;\n}\n\n/**\n * Monaco 编辑器面板。\n * - 独立模式:通过 props 完全控制\n * - 联动模式:自动从 EditorCoordinator 继承配置,并向 bus 注册 controller\n */\nexport const EditorPanel: FC<EditorPanelProps> = ({\n value,\n onChange,\n language,\n theme,\n vsPath,\n sqlSchema,\n builtinSqlExcludeLabels,\n apiConfig: apiConfigProp,\n completionProviders,\n onMount,\n minimap,\n editorOptions,\n onAiError,\n className,\n loading,\n}) => {\n const coordinator = useOptionalCoordinator();\n\n // 合并 props 与 coordinator 配置(props 优先)\n const effectiveLanguage = language ?? coordinator?.editorState.language ?? 'typescript';\n const effectiveTheme = theme ?? coordinator?.editorState.theme ?? 'vs-dark';\n const effectiveApiConfig = apiConfigProp ?? coordinator?.apiConfig ?? null;\n const effectiveSqlSchema = sqlSchema ?? coordinator?.sqlSchema ?? {};\n const effectiveProviders = completionProviders ?? coordinator?.completionProviders ?? [];\n\n const controllerRef = useRef<EditorController | null>(null);\n const apiConfigRef = useRef<ApiConfig | null>(effectiveApiConfig);\n const pendingRef = useRef<PendingCompletion | null>(null);\n const [aiLoading, setAiLoading] = useState(false);\n const [aiError, setAiError] = useState<string | null>(null);\n const errorTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // 配置 loader 路径(中文语言包已在模块顶层配置)\n useEffect(() => {\n if (vsPath) {\n loader.config({ paths: { vs: vsPath } });\n }\n }, [vsPath]);\n\n useEffect(() => {\n apiConfigRef.current = effectiveApiConfig;\n }, [effectiveApiConfig]);\n\n const showAiError = (msg: string) => {\n if (errorTimerRef.current) clearTimeout(errorTimerRef.current);\n setAiError(msg);\n onAiError?.(msg);\n errorTimerRef.current = setTimeout(() => setAiError(null), 4000);\n };\n\n // SQL schema 通过 ref 注入到 core 的 SQL 补全\n const schemaRef = useRef<SqlSchema>(effectiveSqlSchema);\n useEffect(() => {\n schemaRef.current = effectiveSqlSchema;\n }, [effectiveSqlSchema]);\n\n // 内置 SQL 补全需要排除的 label(大写),通过 ref 支持动态更新\n const excludeLabelsRef = useRef<Set<string>>(\n new Set((builtinSqlExcludeLabels ?? []).map((l) => l.toUpperCase())),\n );\n useEffect(() => {\n excludeLabelsRef.current = new Set((builtinSqlExcludeLabels ?? []).map((l) => l.toUpperCase()));\n }, [builtinSqlExcludeLabels]);\n\n const handleBeforeMount: BeforeMount = (monaco) => {\n // 把 monaco 实例附加到 controller 备用\n (window as unknown as { __monaco_ai_monaco?: typeof monaco }).__monaco_ai_monaco = monaco;\n };\n\n const handleMount: OnMount = (editor, monaco) => {\n // 注册 SQL 补全(使用 core 的注册函数)\n registerSqlCompletion(monaco, schemaRef, excludeLabelsRef);\n // 注册 AI 内联幽灵文本提供者\n registerAiInlineCompletion(monaco, pendingRef);\n\n // 注册自定义 completionProviders\n for (const provider of effectiveProviders) {\n const langs = provider.languages ?? ['*'];\n for (const lang of langs) {\n monaco.languages.registerCompletionItemProvider(lang, {\n triggerCharacters: provider.triggerCharacters,\n provideCompletionItems: async (\n model: MonacoType.editor.ITextModel,\n position: MonacoType.Position,\n context: MonacoType.languages.CompletionContext,\n ) => {\n const ctx = {\n monaco,\n model,\n position,\n lineText: model.getLineContent(position.lineNumber),\n currentWord: model.getWordUntilPosition(position).word,\n fullText: model.getValue(),\n triggerCharacter: context.triggerCharacter,\n };\n if (provider.shouldTrigger && !provider.shouldTrigger(ctx)) {\n return { suggestions: [] };\n }\n return { suggestions: await provider.provide(ctx) };\n },\n });\n }\n }\n\n // 注册 AI 补全命令\n registerAiCompletionCommand(\n editor,\n () => apiConfigRef.current,\n pendingRef,\n setAiLoading,\n showAiError,\n );\n\n // 创建轻量 controller(包装现有 editor)\n const controller = createControllerFromEditor(editor, monaco);\n controllerRef.current = controller;\n\n // 更新光标、内容到 coordinator\n if (coordinator) {\n coordinator.setEditor(controller);\n coordinator.bus.registerEditor(controller);\n\n editor.onDidChangeCursorPosition((e) => {\n coordinator.patchEditorState({\n cursorLine: e.position.lineNumber,\n cursorColumn: e.position.column,\n });\n });\n editor.onDidChangeModelContent(() => {\n coordinator.patchEditorState({ value: editor.getValue() });\n });\n }\n\n onMount?.(controller);\n };\n\n // 卸载时清理\n useEffect(() => {\n return () => {\n if (errorTimerRef.current) clearTimeout(errorTimerRef.current);\n if (coordinator && controllerRef.current) {\n coordinator.setEditor(null);\n }\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const mergedOptions = useMemo<MonacoType.editor.IStandaloneEditorConstructionOptions>(\n () => {\n // 缩略图默认配置,使用方可通过 minimap prop 或 editorOptions.minimap 局部覆盖\n const defaultMinimap: MonacoType.editor.IEditorMinimapOptions = {\n enabled: true,\n side: 'right',\n showSlider: 'mouseover',\n renderCharacters: true,\n maxColumn: 120,\n };\n\n // 归一化 minimap prop:boolean -> { enabled },对象 -> 原样\n const minimapFromProp: MonacoType.editor.IEditorMinimapOptions | undefined =\n typeof minimap === 'boolean' ? { enabled: minimap } : minimap;\n\n // 深合并优先级:默认值 < minimap prop < editorOptions.minimap\n const mergedMinimap: MonacoType.editor.IEditorMinimapOptions = {\n ...defaultMinimap,\n ...minimapFromProp,\n ...editorOptions?.minimap,\n };\n\n return {\n fontSize: 14,\n scrollBeyondLastLine: false,\n automaticLayout: true,\n // 让 suggest/hover/find 等溢出浮层以 fixed 定位渲染到 body 层级,\n // 避免被祖先的 overflow:hidden 裁剪(如 tooltip 贴边被遮挡)\n fixedOverflowWidgets: true,\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n smoothScrolling: true,\n cursorBlinking: 'smooth',\n bracketPairColorization: { enabled: true },\n tabSize: 2,\n wordWrap: 'on',\n folding: true,\n formatOnPaste: true,\n formatOnType: false,\n suggestOnTriggerCharacters: true,\n quickSuggestions: { other: true, comments: false, strings: false },\n acceptSuggestionOnCommitCharacter: true,\n acceptSuggestionOnEnter: 'on',\n inlineSuggest: { enabled: true },\n tabCompletion: 'on',\n ...editorOptions,\n minimap: mergedMinimap,\n };\n },\n [minimap, editorOptions],\n );\n\n return (\n <div className={className} style={{ position: 'relative', flex: 1, height: '100%' }}>\n {aiLoading && (\n <div className=\"mae-ai-loading\" style={loadingStyle}>\n <span className=\"mae-spinner\" style={spinnerStyle} /> AI 补全中…\n </div>\n )}\n {aiError && (\n <div onClick={() => setAiError(null)} style={errorStyle} title=\"点击关闭\">\n {aiError}\n </div>\n )}\n <Editor\n height=\"100%\"\n language={effectiveLanguage}\n theme={effectiveTheme}\n value={value}\n loading={loading}\n onChange={(val) => onChange?.(val ?? '')}\n beforeMount={handleBeforeMount}\n onMount={handleMount}\n options={mergedOptions}\n />\n </div>\n );\n};\n\n// ── 辅助:把 @monaco-editor/react 创建的 editor 包装成 controller ──\nfunction createControllerFromEditor(\n editor: MonacoType.editor.IStandaloneCodeEditor,\n monaco: typeof MonacoType,\n): EditorController {\n // 直接构造一个轻量的 controller-like 对象,但保持 EditorController 接口\n const fake = Object.create(EditorController.prototype) as EditorController;\n // @ts-expect-error 私有字段写入\n fake.editor = editor;\n // @ts-expect-error 私有字段写入\n fake.monaco = monaco;\n // @ts-expect-error 私有字段写入\n fake.disposables = [];\n // @ts-expect-error 私有字段写入\n fake.pendingCompletionRef = { current: null };\n // @ts-expect-error 私有字段写入\n fake.customProviders = [];\n // 初始化 EventEmitter 内部 listeners 字段\n // @ts-expect-error 父类私有字段\n fake.listeners = {};\n return fake;\n}\n\nconst loadingStyle: React.CSSProperties = {\n position: 'absolute', bottom: 32, right: 16, zIndex: 10,\n display: 'flex', alignItems: 'center', gap: 6,\n borderRadius: 9999, border: '1px solid rgba(59,130,246,0.3)',\n background: 'rgba(17,24,39,0.9)', padding: '4px 12px',\n fontSize: 12, color: '#60a5fa',\n};\n\nconst spinnerStyle: React.CSSProperties = {\n display: 'inline-block', width: 12, height: 12,\n border: '2px solid rgba(96,165,250,0.3)', borderTopColor: '#60a5fa',\n borderRadius: '50%', animation: 'mae-spin 0.8s linear infinite',\n};\n\nconst errorStyle: React.CSSProperties = {\n position: 'absolute', bottom: 32, right: 16, zIndex: 10,\n maxWidth: 320, cursor: 'pointer',\n borderRadius: 8, border: '1px solid rgba(239,68,68,0.4)',\n background: 'rgba(17,24,39,0.95)', padding: '8px 12px',\n fontSize: 12, color: '#f87171', lineHeight: 1.5,\n};\n\nexport default EditorPanel;","import { useContext } from 'react';\nimport { EditorCoordinatorContext } from '../context/internal';\nimport type { EditorCoordinatorValue } from '../context/EditorCoordinator';\n\n/** 内部 hook:尝试读取协调器上下文,没有则返回 null(独立模式) */\nexport function useOptionalCoordinator(): EditorCoordinatorValue | null {\n return useContext(EditorCoordinatorContext);\n}","import { createContext } from 'react';\nimport type { EditorCoordinatorValue } from './EditorCoordinator';\n\n/** 内部共享 Context,让组件可选择性地读取协调器值 */\nexport const EditorCoordinatorContext = createContext<EditorCoordinatorValue | null>(null);","import {\n type FC,\n useState,\n useRef,\n useEffect,\n useCallback,\n type KeyboardEvent,\n} from 'react';\nimport { DiffEditor } from '@monaco-editor/react';\nimport {\n AiChatController,\n type ChatMessage,\n type ApiConfig,\n} from '@monaco-ai-editor/core';\nimport { useOptionalCoordinator } from '../hooks/useOptionalCoordinator';\n\nexport interface AiChatPanelProps {\n /** 独立模式:编辑器当前内容 */\n editorContent?: string;\n /** 独立模式:当前语言 */\n language?: string;\n /** 独立模式:插入代码回调 */\n onInsertCode?: (code: string) => void;\n /** 独立模式:替换全部代码回调 */\n onReplaceCode?: (code: string) => void;\n /** 关闭面板 */\n onClose?: () => void;\n /** AI 配置 */\n apiConfig?: ApiConfig;\n /** 设置保存后回调 */\n onApiConfigChange?: (config: ApiConfig) => void;\n /** 容器宽度(默认 320) */\n defaultWidth?: number;\n className?: string;\n}\n\ntype Part =\n | { type: 'text'; content: string }\n | { type: 'code'; lang: string; content: string };\n\ninterface DiffState {\n original: string;\n modified: string;\n language: string;\n}\n\nfunction parseContent(raw: string, isStreaming?: boolean): Part[] {\n const parts: Part[] = [];\n const blockRe = /```(\\w*)\\n?([\\s\\S]*?)```/g;\n let last = 0;\n let m: RegExpExecArray | null;\n while ((m = blockRe.exec(raw)) !== null) {\n if (m.index > last) parts.push({ type: 'text', content: raw.slice(last, m.index) });\n parts.push({ type: 'code', lang: m[1] || 'code', content: m[2].trimEnd() });\n last = m.index + m[0].length;\n }\n const remaining = raw.slice(last);\n if (remaining) {\n const idx = remaining.indexOf('```');\n if (idx !== -1) {\n if (idx > 0) parts.push({ type: 'text', content: remaining.slice(0, idx) });\n const block = remaining.slice(idx + 3);\n const lm = block.match(/^(\\w*)\\n?/);\n parts.push({ type: 'code', lang: lm?.[1] ?? '', content: block.slice(lm?.[0]?.length ?? 0) + (isStreaming ? '▋' : '') });\n } else {\n parts.push({ type: 'text', content: remaining + (isStreaming ? '▋' : '') });\n }\n } else if (isStreaming && raw.length > 0 && !raw.endsWith('```')) {\n parts.push({ type: 'text', content: '▋' });\n }\n return parts;\n}\n\nconst MessageContent: FC<{\n content: string; isStreaming?: boolean;\n onInsertCode?: (code: string) => void; onShowDiff?: (code: string, lang: string) => void;\n}> = ({ content, isStreaming, onInsertCode, onShowDiff }) => {\n const parts = parseContent(content, isStreaming);\n if (isStreaming && content === '') return <span style={{ animation: 'pulse 1s infinite', color: '#9ca3af' }}>▋</span>;\n return (\n <>\n {parts.map((p, i) =>\n p.type === 'code' ? (\n <div key={i} style={{ margin: '8px 0', borderRadius: 8, overflow: 'hidden', border: '1px solid rgb(75,85,99)' }}>\n <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', padding: '4px 12px', background: 'rgb(55,65,71)' }}>\n <span style={{ fontSize: 11, color: 'rgb(156,163,175)' }}>{p.lang}</span>\n <div style={{ display: 'flex', gap: 8 }}>\n <button onClick={() => navigator.clipboard.writeText(p.content)} style={codeBtnStyle}>复制</button>\n {onShowDiff && <button onClick={() => onShowDiff(p.content, p.lang)} style={{ ...codeBtnStyle, color: '#fbbf24' }}>差异</button>}\n {onInsertCode && <button onClick={() => onInsertCode(p.content)} style={{ ...codeBtnStyle, color: '#60a5fa' }}>插入</button>}\n </div>\n </div>\n <pre style={{ margin: 0, padding: 12, overflowX: 'auto', background: 'rgb(3,7,18)', fontSize: 12, lineHeight: 1.6, color: 'rgb(229,231,235)' }}>\n <code>{p.content}</code>\n </pre>\n </div>\n ) : (\n <span key={i} style={{ whiteSpace: 'pre-wrap', lineHeight: 1.6 }}>{p.content}</span>\n ),\n )}\n </>\n );\n};\n\nconst codeBtnStyle: React.CSSProperties = {\n fontSize: 11, color: 'rgb(156,163,175)', background: 'transparent',\n border: 'none', cursor: 'pointer', padding: 0,\n};\n\nconst MIN_WIDTH = 260;\nconst MAX_WIDTH = 720;\n\nexport const AiChatPanel: FC<AiChatPanelProps> = (props) => {\n const coordinator = useOptionalCoordinator();\n const [width, setWidth] = useState(props.defaultWidth ?? 320);\n const [messages, setMessages] = useState<ChatMessage[]>([]);\n const [input, setInput] = useState('');\n const [loading, setLoading] = useState(false);\n const [showSettings, setShowSettings] = useState(false);\n const [configDraft, setConfigDraft] = useState<ApiConfig>(props.apiConfig ?? coordinator?.apiConfig ?? { baseUrl: '', apiKey: '', model: '' });\n const [diffState, setDiffState] = useState<DiffState | null>(null);\n const messagesEndRef = useRef<HTMLDivElement>(null);\n const abortRef = useRef<AbortController | null>(null);\n const ctrlRef = useRef<AiChatController | null>(null);\n const isDragging = useRef(false);\n const dragStartX = useRef(0);\n const dragStartW = useRef(0);\n\n // 获取编辑器内容(联动或独立)\n const editorContent = props.editorContent ?? coordinator?.editor?.getValue() ?? '';\n const language = props.language ?? coordinator?.editorState.language;\n\n const effectiveApiConfig = props.apiConfig ?? coordinator?.apiConfig ?? configDraft;\n\n // 初始化 controller\n useEffect(() => {\n const ctrl = new AiChatController(effectiveApiConfig);\n ctrlRef.current = ctrl;\n\n const offAdd = ctrl.on('messageAdded', (msg) => setMessages((prev) => [...prev, msg]));\n const offUpd = ctrl.on('messageUpdated', (msg) =>\n setMessages((prev) => prev.map((m) => (m.id === msg.id ? msg : m))));\n const offClear = ctrl.on('cleared', () => setMessages([]));\n const offLoad = ctrl.on('loadingChange', ({ loading: l }) => setLoading(l));\n\n if (coordinator) coordinator.setChat(ctrl);\n\n return () => {\n offAdd(); offUpd(); offClear(); offLoad();\n ctrl.dispose();\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // 同步 API 配置变更\n useEffect(() => {\n if (ctrlRef.current) ctrlRef.current.setApiConfig(effectiveApiConfig);\n setConfigDraft(effectiveApiConfig);\n }, [effectiveApiConfig]);\n\n useEffect(() => {\n messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });\n }, [messages]);\n\n const handleSend = useCallback(() => {\n ctrlRef.current?.send(input, { editorContent, language });\n setInput('');\n }, [input, editorContent, language]);\n\n const handleKeyDown = (e: KeyboardEvent<HTMLTextAreaElement>) => {\n if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {\n e.preventDefault();\n handleSend();\n }\n };\n\n const handleStop = () => ctrlRef.current?.stop();\n const handleClear = () => ctrlRef.current?.clear();\n\n const handleSaveConfig = () => {\n if (coordinator?.onApiConfigChange) {\n coordinator.onApiConfigChange(configDraft);\n }\n if (props.onApiConfigChange) {\n props.onApiConfigChange(configDraft);\n }\n setShowSettings(false);\n };\n\n const handleAddEditorContext = () => {\n if (!editorContent) return;\n const snippet = `以下是当前编辑器中的${language ? ` ${language} ` : ''}代码:\\n\\`\\`\\`${language}\\n${editorContent}\\n\\`\\`\\``;\n setInput((prev) => (prev.trim() ? `${prev}\\n\\n${snippet}` : snippet));\n };\n\n const handleInsert = props.onInsertCode\n ? props.onInsertCode\n : (code: string) => coordinator?.bus?.insertToEditor(code);\n\n const handleReplace = props.onReplaceCode\n ? props.onReplaceCode\n : (code: string) => coordinator?.bus?.replaceEditor(code);\n\n const handleShowDiff = useCallback((aiCode: string, codeLang: string) => {\n setDiffState({ original: editorContent ?? '', modified: aiCode, language: codeLang || language || 'plaintext' });\n }, [editorContent, language]);\n\n const handleApplyDiff = () => {\n if (!diffState) return;\n if (handleReplace) handleReplace(diffState.modified);\n else if (handleInsert) handleInsert(diffState.modified);\n setDiffState(null);\n };\n\n const handleResizeMouseDown = (e: React.MouseEvent) => {\n e.preventDefault();\n isDragging.current = true;\n dragStartX.current = e.clientX;\n dragStartW.current = width;\n const onMove = (ev: MouseEvent) => {\n const next = Math.min(MAX_WIDTH, Math.max(MIN_WIDTH, dragStartW.current + (dragStartX.current - ev.clientX)));\n setWidth(next);\n };\n const onUp = () => {\n isDragging.current = false;\n document.removeEventListener('mousemove', onMove);\n document.removeEventListener('mouseup', onUp);\n document.body.style.cursor = '';\n };\n document.body.style.cursor = 'col-resize';\n document.addEventListener('mousemove', onMove);\n document.addEventListener('mouseup', onUp);\n };\n\n return (\n <div style={{ position: 'relative', display: 'flex', flexDirection: 'column', borderLeft: '1px solid rgb(55,65,81)', background: 'rgb(17,24,39)', width, height: '100%' }}>\n {/* 拖拽缩放 */}\n <div onMouseDown={handleResizeMouseDown} style={{ position: 'absolute', left: 0, top: 0, width: 4, height: '100%', cursor: 'col-resize', zIndex: 10 }} />\n\n {/* 头部 */}\n <div style={{ display: 'flex', alignItems: 'center', padding: '8px 12px', borderBottom: '1px solid rgb(55,65,81)' }}>\n <svg style={{ width: 16, height: 16, color: '#60a5fa', marginRight: 8 }} viewBox=\"0 0 20 20\" fill=\"currentColor\">\n <path d=\"M2 5a2 2 0 012-2h7a2 2 0 012 2v4a2 2 0 01-2 2H9l-3 3v-3H4a2 2 0 01-2-2V5z\" />\n <path d=\"M15 7v2a4 4 0 01-4 4H9.828l-1.766 1.767c.28.149.599.233.938.233h2l3 3v-3h2a2 2 0 002-2V9a2 2 0 00-2-2h-1z\" />\n </svg>\n <span style={{ flex: 1, fontSize: 13, fontWeight: 500, color: '#fff' }}>AI 对话</span>\n\n <button onClick={() => { setConfigDraft(effectiveApiConfig); setShowSettings((v) => !v); }} style={{ ...iconBtnStyle, color: showSettings ? '#60a5fa' : '#9ca3af' }} title=\"设置\">\n <svg style={{ width: 16, height: 16 }} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}>\n <path d=\"M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z\" />\n <circle cx=\"12\" cy=\"12\" r=\"3\" />\n </svg>\n </button>\n <button onClick={handleClear} style={iconBtnStyle} title=\"清空\"><svg style={{ width: 16, height: 16 }} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16\" /></svg></button>\n {props.onClose && <button onClick={props.onClose} style={iconBtnStyle} title=\"关闭\"><svg style={{ width: 16, height: 16 }} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2}><path d=\"M6 18L18 6M6 6l12 12\" /></svg></button>}\n </div>\n\n {/* 设置面板 */}\n {showSettings && (\n <div style={{ padding: 12, borderBottom: '1px solid rgb(55,65,81)', background: 'rgb(31,41,55)' }}>\n <div style={{ fontSize: 11, fontWeight: 600, color: '#d1d5db', marginBottom: 12 }}>API 配置</div>\n {(['baseUrl', 'apiKey', 'model'] as const).map((field) => (\n <div key={field}>\n <label style={{ display: 'block', fontSize: 11, color: '#9ca3af', marginBottom: 4 }}>\n {field === 'baseUrl' ? 'Base URL' : field === 'apiKey' ? 'API Key' : '模型'}\n </label>\n <input\n type={field === 'apiKey' ? 'password' : 'text'}\n value={configDraft[field]}\n onChange={(e) => setConfigDraft((p) => ({ ...p, [field]: e.target.value }))}\n placeholder={field === 'baseUrl' ? 'https://api.openai.com/v1' : field === 'model' ? 'gpt-4o-mini' : ''}\n style={inputStyle}\n />\n </div>\n ))}\n <div style={{ display: 'flex', gap: 8, marginTop: 12 }}>\n <button onClick={handleSaveConfig} style={{ flex: 1, padding: '6px 0', fontSize: 12, background: 'rgb(37,99,235)', color: '#fff', border: 'none', borderRadius: 4, cursor: 'pointer' }}>保存</button>\n <button onClick={() => setShowSettings(false)} style={{ flex: 1, padding: '6px 0', fontSize: 12, background: 'rgb(75,85,99)', color: '#fff', border: 'none', borderRadius: 4, cursor: 'pointer' }}>取消</button>\n </div>\n </div>\n )}\n\n {/* Diff 对比 */}\n {diffState && (\n <div style={{ flex: 1, display: 'flex', flexDirection: 'column', background: 'rgb(17,24,39)' }}>\n <div style={{ padding: '4px 8px', borderBottom: '1px solid rgb(55,65,81)', background: 'rgb(31,41,55)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>\n <span style={{ fontSize: 12, color: '#fff' }}>Diff 对比</span>\n <div style={{ display: 'flex', gap: 8 }}>\n <button onClick={handleApplyDiff} style={{ fontSize: 11, color: '#60a5fa', background: 'transparent', border: 'none', cursor: 'pointer' }}>应用更改</button>\n <button onClick={() => setDiffState(null)} style={{ fontSize: 11, color: '#9ca3af', background: 'transparent', border: 'none', cursor: 'pointer' }}>关闭</button>\n </div>\n </div>\n <DiffEditor\n height=\"100%\"\n language={diffState.language}\n original={diffState.original}\n modified={diffState.modified}\n theme=\"vs-dark\"\n />\n </div>\n )}\n\n {/* 消息列表 */}\n {!diffState && (\n <div style={{ flex: 1, overflowY: 'auto', padding: 12 }}>\n {messages.length === 0 && (\n <div style={{ display: 'flex', height: '100%', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', textAlign: 'center' }}>\n {!effectiveApiConfig.apiKey.trim() && (\n <div style={{ width: '100%', marginBottom: 16, padding: '8px 12px', borderRadius: 8, border: '1px solid rgba(250,204,21,0.4)', background: 'rgba(250,204,21,0.1)', textAlign: 'left' }}>\n <p style={{ marginBottom: 4, fontSize: 11, fontWeight: 600, color: '#fbbf24' }}>⚠️ 未配置 API Key</p>\n <p style={{ fontSize: 11, color: 'rgba(251,191,36,0.8)', lineHeight: 1.5 }}>请点击右上角 ⚙️ 按钮填写配置后开始对话</p>\n </div>\n )}\n <svg style={{ width: 40, height: 40, color: 'rgb(75,85,99)', marginBottom: 12 }} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}>\n <path d=\"M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z\" />\n </svg>\n {!loading && <p style={{ fontSize: 12, color: '#6b7280' }}>开始你的 AI 编程对话吧</p>}\n </div>\n )}\n {messages.map((msg) => (\n <div key={msg.id} style={{ marginBottom: 12, display: 'flex', flexDirection: 'column', alignItems: msg.role === 'user' ? 'flex-end' : 'flex-start' }}>\n <div style={{ maxWidth: '90%', padding: '8px 12px', borderRadius: 8, fontSize: 12, color: '#e5e7eb', background: msg.role === 'user' ? 'rgb(55,65,81)' : 'rgb(31,41,55)', lineHeight: 1.5 }}>\n {msg.role === 'assistant' ? (\n <MessageContent content={msg.content} isStreaming={msg.isStreaming} onInsertCode={handleInsert} onShowDiff={handleShowDiff} />\n ) : (\n <span style={{ whiteSpace: 'pre-wrap' }}>{msg.content}</span>\n )}\n </div>\n </div>\n ))}\n <div ref={messagesEndRef} />\n </div>\n )}\n\n {/* 输入区域 */}\n {!diffState && (\n <div style={{ padding: '8px 12px', borderTop: '1px solid rgb(55,65,81)' }}>\n <div style={{ display: 'flex', gap: 4, marginBottom: 4 }}>\n <button onClick={handleAddEditorContext} style={{ fontSize: 11, color: '#9ca3af', background: 'transparent', border: 'none', cursor: 'pointer' }} title=\"引用编辑器代码\">+ 引用代码</button>\n </div>\n <div style={{ display: 'flex', gap: 8 }}>\n <textarea\n value={input}\n onChange={(e) => setInput(e.target.value)}\n onKeyDown={handleKeyDown}\n placeholder=\"输入消息,Ctrl+Enter 发送...\"\n style={{ flex: 1, padding: '6px 8px', fontSize: 12, background: 'rgb(31,41,55)', color: '#e5e7eb', border: '1px solid rgb(75,85,99)', borderRadius: 4, outline: 'none', resize: 'none', minHeight: 32 }}\n rows={2}\n />\n {loading ? (\n <button onClick={handleStop} style={{ padding: '6px 12px', fontSize: 12, background: 'rgb(220,38,38)', color: '#fff', border: 'none', borderRadius: 4, cursor: 'pointer', whiteSpace: 'nowrap' }}>停止</button>\n ) : (\n <button onClick={handleSend} style={{ padding: '6px 12px', fontSize: 12, background: 'rgb(37,99,235)', color: '#fff', border: 'none', borderRadius: 4, cursor: 'pointer', whiteSpace: 'nowrap' }}>发送</button>\n )}\n </div>\n </div>\n )}\n </div>\n );\n};\n\nconst iconBtnStyle: React.CSSProperties = {\n padding: 4, color: '#9ca3af', background: 'transparent',\n border: 'none', cursor: 'pointer', display: 'flex',\n borderRadius: 4,\n};\n\nconst inputStyle: React.CSSProperties = {\n width: '100%', padding: '4px 8px', fontSize: 12,\n background: 'rgb(55,65,81)', color: 'rgb(229,231,235)',\n border: '1px solid rgb(75,85,99)', borderRadius: 4,\n outline: 'none', marginBottom: 8, boxSizing: 'border-box',\n};\n\nexport default AiChatPanel;","import { type FC } from 'react';\nimport { LANGUAGES, THEMES } from '@monaco-ai-editor/core';\n\nexport interface ToolbarProps {\n language?: string;\n theme?: string;\n onLanguageChange?: (lang: string) => void;\n onThemeChange?: (theme: string) => void;\n onFormat?: () => void;\n onToggleAiChat?: () => void;\n aiChatVisible?: boolean;\n className?: string;\n}\n\nexport const Toolbar: FC<ToolbarProps> = ({\n language,\n theme,\n onLanguageChange,\n onThemeChange,\n onFormat,\n onToggleAiChat,\n aiChatVisible,\n className,\n}) => {\n return (\n <div\n className={className}\n style={toolbarStyle}\n >\n <div style={labelStyle}>语言</div>\n <select\n value={language ?? 'typescript'}\n onChange={(e) => onLanguageChange?.(e.target.value)}\n style={selectStyle}\n >\n {LANGUAGES.map((lang) => (\n <option key={lang} value={lang}>\n {lang}\n </option>\n ))}\n </select>\n\n <div style={{ ...labelStyle, marginLeft: 16 }}>主题</div>\n <select\n value={theme ?? 'vs-dark'}\n onChange={(e) => onThemeChange?.(e.target.value)}\n style={selectStyle}\n >\n {THEMES.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n\n <div style={{ flex: 1 }} />\n\n {onToggleAiChat && (\n <button\n onClick={onToggleAiChat}\n style={{\n ...buttonStyle,\n background: aiChatVisible ? 'rgb(37,99,235)' : 'rgb(55,65,81)',\n }}\n >\n <svg\n style={{ width: 16, height: 16, marginRight: 4 }}\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n >\n <path d=\"M2 5a2 2 0 012-2h7a2 2 0 012 2v4a2 2 0 01-2 2H9l-3 3v-3H4a2 2 0 01-2-2V5z\" />\n <path d=\"M15 7v2a4 4 0 01-4 4H9.828l-1.766 1.767c.28.149.599.233.938.233h2l3 3v-3h2a2 2 0 002-2V9a2 2 0 00-2-2h-1z\" />\n </svg>\n AI\n </button>\n )}\n\n {onFormat && (\n <button onClick={onFormat} style={{ ...buttonStyle, marginLeft: 8 }}>\n 格式化\n </button>\n )}\n </div>\n );\n};\n\nconst toolbarStyle: React.CSSProperties = {\n display: 'flex', alignItems: 'center', padding: '8px 16px',\n background: 'rgb(31,41,55)', borderBottom: '1px solid rgb(55,65,81)',\n};\n\nconst labelStyle: React.CSSProperties = {\n fontSize: 13, color: 'rgb(156,163,175)',\n};\n\nconst selectStyle: React.CSSProperties = {\n marginLeft: 8, padding: '4px 8px', fontSize: 13,\n background: 'rgb(55,65,81)', color: 'rgb(229,231,235)',\n border: '1px solid rgb(75,85,99)', borderRadius: 4,\n outline: 'none',\n};\n\nconst buttonStyle: React.CSSProperties = {\n padding: '4px 12px', fontSize: 13, color: '#fff',\n background: 'rgb(55,65,81)', border: 'none', borderRadius: 4,\n cursor: 'pointer', display: 'flex', alignItems: 'center',\n};\n\nexport default Toolbar;\n","import { type FC } from 'react';\n\nexport interface StatusBarProps {\n language?: string;\n lineCount?: number;\n charCount?: number;\n cursorLine?: number;\n cursorColumn?: number;\n className?: string;\n}\n\nexport const StatusBar: FC<StatusBarProps> = ({\n language,\n lineCount = 0,\n charCount = 0,\n cursorLine = 1,\n cursorColumn = 1,\n className,\n}) => {\n return (\n <div className={className} style={statusBarStyle}>\n <span style={itemStyle}>Ln {cursorLine}, Col {cursorColumn}</span>\n <span style={dividerStyle}>|</span>\n <span style={itemStyle}>{lineCount} 行</span>\n <span style={dividerStyle}>|</span>\n <span style={itemStyle}>{charCount} 字符</span>\n <div style={{ flex: 1 }} />\n <span style={itemStyle}>{language?.toUpperCase() ?? ''}</span>\n <span style={dividerStyle}>|</span>\n <span style={itemStyle}>UTF-8</span>\n </div>\n );\n};\n\nconst statusBarStyle: React.CSSProperties = {\n display: 'flex', alignItems: 'center', gap: 12,\n padding: '0 16px', height: 22,\n fontSize: 11, color: '#fff',\n background: 'rgb(29,78,216)',\n};\n\nconst itemStyle: React.CSSProperties = {\n display: 'flex', alignItems: 'center',\n};\n\nconst dividerStyle: React.CSSProperties = {\n color: 'rgba(255,255,255,0.5)',\n};\n\nexport default StatusBar;\n","import { type FC, useCallback, useState } from 'react';\nimport type { ApiConfig, SqlSchema, CompletionProvider, EditorController } from '@monaco-ai-editor/core';\nimport { EditorCoordinator } from '../context/EditorCoordinator';\nimport { EditorPanel } from './EditorPanel';\nimport { AiChatPanel } from './AiChatPanel';\nimport { Toolbar } from './Toolbar';\nimport { StatusBar } from './StatusBar';\nimport { useEditorCoordinator } from '../context/EditorCoordinator';\n\nexport interface MonacoAiEditorProps {\n language?: string;\n theme?: string;\n value?: string;\n onChange?: (value: string) => void;\n apiConfig?: ApiConfig;\n onApiConfigChange?: (config: ApiConfig) => void;\n sqlSchema?: SqlSchema;\n completionProviders?: CompletionProvider[];\n vsPath?: string;\n showToolbar?: boolean;\n showStatusBar?: boolean;\n showAiChat?: boolean;\n className?: string;\n}\n\n/**\n * 预组合组件:编辑器 + 工具栏 + 状态栏 + AI 聊天面板,一行接入。\n * 内部自动用 EditorCoordinator 包裹,实现联动。\n */\nexport const MonacoAiEditor: FC<MonacoAiEditorProps> = ({\n language = 'typescript',\n theme = 'vs-dark',\n apiConfig,\n onApiConfigChange,\n sqlSchema,\n completionProviders,\n showAiChat: showAiChatProp = true,\n ...rest\n}) => {\n return (\n <EditorCoordinator\n language={language}\n theme={theme}\n apiConfig={apiConfig}\n sqlSchema={sqlSchema}\n completionProviders={completionProviders}\n onApiConfigChange={onApiConfigChange}\n >\n <MonacoAiEditorInner {...rest} showAiChat={showAiChatProp} />\n </EditorCoordinator>\n );\n};\n\nconst MonacoAiEditorInner: FC<{\n value?: string;\n onChange?: (v: string) => void;\n vsPath?: string;\n showToolbar?: boolean;\n showStatusBar?: boolean;\n showAiChat?: boolean;\n className?: string;\n}> = ({ value, onChange, vsPath, showToolbar = true, showStatusBar = true, showAiChat = true, className }) => {\n const coordinator = useEditorCoordinator();\n const [aiVisible, setAiVisible] = useState(showAiChat);\n\n const onLangChange = useCallback((lang: string) => {\n coordinator.editor?.setLanguage(lang);\n coordinator.patchEditorState({ language: lang });\n }, [coordinator]);\n\n const onThemeChange = useCallback((theme: string) => {\n coordinator.editor?.setTheme(theme);\n coordinator.patchEditorState({ theme });\n }, [coordinator]);\n\n const onFormat = useCallback(() => coordinator.editor?.format(), [coordinator]);\n\n const onEditorMount = useCallback((controller: EditorController) => {\n coordinator.setEditor(controller);\n }, [coordinator]);\n\n return (\n <div\n className={className}\n style={{ display: 'flex', flexDirection: 'column', height: '100%', background: 'rgb(17,24,39)' }}\n >\n {showToolbar && (\n <Toolbar\n language={coordinator.editorState.language}\n theme={coordinator.editorState.theme}\n onLanguageChange={onLangChange}\n onThemeChange={onThemeChange}\n onFormat={onFormat}\n onToggleAiChat={() => setAiVisible((v) => !v)}\n aiChatVisible={aiVisible}\n />\n )}\n <div style={{ flex: 1, display: 'flex', overflow: 'hidden' }}>\n <EditorPanel\n value={value}\n onChange={(v) => {\n onChange?.(v);\n coordinator.patchEditorState({ value: v });\n }}\n language={coordinator.editorState.language}\n theme={coordinator.editorState.theme}\n vsPath={vsPath}\n onMount={onEditorMount}\n />\n {aiVisible && <AiChatPanel onClose={() => setAiVisible(false)} />}\n </div>\n {showStatusBar && (\n <StatusBar\n language={coordinator.editorState.language}\n lineCount={coordinator.editorState.value.split('\\n').length}\n charCount={coordinator.editorState.value.length}\n cursorLine={coordinator.editorState.cursorLine}\n cursorColumn={coordinator.editorState.cursorColumn}\n />\n )}\n </div>\n );\n};\n\nexport default MonacoAiEditor;","import { type ReactNode, useContext, useCallback, useMemo, useRef, useState } from 'react';\nimport type { EditorSnapshot, ApiConfig, SqlSchema, CompletionProvider } from '@monaco-ai-editor/core';\nimport { EditorBus } from '@monaco-ai-editor/core';\nimport type { EditorController, AiChatController } from '@monaco-ai-editor/core';\nimport { EditorCoordinatorContext } from './internal';\n\nexport interface EditorCoordinatorValue {\n editor: EditorController | null;\n chat: AiChatController | null;\n editorState: EditorSnapshot;\n patchEditorState: (patch: Partial<EditorSnapshot>) => void;\n setEditor: (controller: EditorController | null) => void;\n setChat: (controller: AiChatController | null) => void;\n bus: EditorBus;\n apiConfig: ApiConfig | null;\n sqlSchema: SqlSchema;\n completionProviders: CompletionProvider[];\n onApiConfigChange?: (config: ApiConfig) => void;\n}\n\nexport interface EditorCoordinatorProps {\n children: ReactNode;\n language?: string;\n theme?: string;\n apiConfig?: ApiConfig;\n sqlSchema?: SqlSchema;\n completionProviders?: CompletionProvider[];\n onApiConfigChange?: (config: ApiConfig) => void;\n}\n\nexport function EditorCoordinator({\n children,\n language: initialLang,\n theme: initialTheme,\n apiConfig: initialApiConfig,\n sqlSchema,\n completionProviders = [],\n onApiConfigChange,\n}: EditorCoordinatorProps) {\n const busRef = useRef(new EditorBus());\n const [editor, setEditor] = useState<EditorController | null>(null);\n const [chat, setChat] = useState<AiChatController | null>(null);\n const [editorState, setEditorState] = useState<EditorSnapshot>({\n value: '',\n language: initialLang ?? 'typescript',\n theme: initialTheme ?? 'vs-dark',\n cursorLine: 1,\n cursorColumn: 1,\n });\n\n const patchEditorState = useCallback((patch: Partial<EditorSnapshot>) => {\n setEditorState((prev) => ({ ...prev, ...patch }));\n }, []);\n\n const value = useMemo<EditorCoordinatorValue>(\n () => ({\n editor,\n chat,\n editorState,\n patchEditorState,\n setEditor,\n setChat,\n bus: busRef.current,\n apiConfig: initialApiConfig ?? null,\n sqlSchema: sqlSchema ?? {},\n completionProviders,\n onApiConfigChange,\n }),\n [editor, chat, editorState, patchEditorState, initialApiConfig, sqlSchema, completionProviders, onApiConfigChange],\n );\n\n return (\n <EditorCoordinatorContext.Provider value={value}>\n {children}\n </EditorCoordinatorContext.Provider>\n );\n}\n\nexport function useEditorCoordinator(): EditorCoordinatorValue {\n const ctx = useContext(EditorCoordinatorContext);\n if (!ctx) throw new Error('useEditorCoordinator must be used within <EditorCoordinator>');\n return ctx;\n}","import { loader } from '@monaco-editor/react';\nimport { LOCALES, type Locale } from '@monaco-ai-editor/core';\n\nexport interface ConfigureMonacoOptions {\n /** UI 本地化语言,默认 'zh-cn'(中文) */\n locale?: Locale;\n /**\n * monaco-editor 的 vs 资源路径。\n * - 不传:自动使用 `${import.meta.env.BASE_URL}vs`(配合 monacoAssetsPlugin 插件)\n * - 传 CDN 或其他路径:覆盖默认行为\n */\n vsPath?: string;\n}\n\n/**\n * 配置 Monaco Editor 的 loader(资源路径 + UI 本地化语言)。\n *\n * 必须在 EditorPanel 首次渲染前调用(模块顶层或应用初始化时)。\n *\n * 默认使用本地 vs 路径,需在 vite.config.ts 中注册 `monacoAssetsPlugin()`。\n * 该插件会在 dev 时 serve node_modules/monaco-editor/min/vs 文件,\n * 并处理 monaco-editor 0.55.x NLS 文件名 `.js.js` → `.js` 的重映射。\n *\n * @example\n * // 默认:本地路径 + 中文(需配合 monacoAssetsPlugin)\n * configureMonaco({ locale: LOCALES.ZH_CN });\n *\n * // 使用 CDN + 英文\n * configureMonaco({ locale: LOCALES.EN, vsPath: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.55.1/min/vs' });\n */\nexport function configureMonaco(options: ConfigureMonacoOptions = {}): void {\n const { locale = LOCALES.ZH_CN, vsPath } = options;\n\n // 默认使用本地路径(配合 monacoAssetsPlugin 插件)\n const baseUrl = (import.meta.env?.BASE_URL ?? '/').replace(/\\/$/, '');\n const effectiveVsPath = vsPath ?? `${baseUrl}/vs`;\n\n const config: Parameters<typeof loader.config>[0] = {\n paths: { vs: effectiveVsPath },\n 'vs/nls': {\n availableLanguages: { '*': locale },\n },\n };\n\n loader.config(config);\n}\n","// ─── 公共组件 ─────────────────────────────────────────────────────────\nexport { EditorPanel, type EditorPanelProps } from './components/EditorPanel';\nexport { AiChatPanel, type AiChatPanelProps } from './components/AiChatPanel';\nexport { Toolbar, type ToolbarProps } from './components/Toolbar';\nexport { StatusBar, type StatusBarProps } from './components/StatusBar';\nexport { MonacoAiEditor, type MonacoAiEditorProps } from './components/MonacoAiEditor';\n\n// ─── Monaco 配置 ─────────────────────────────────────────────────────\nexport { configureMonaco, type ConfigureMonacoOptions } from './utils/configureMonaco';\n\n// ─── 协调器 ───────────────────────────────────────────────────────────\nexport {\n EditorCoordinator,\n useEditorCoordinator,\n type EditorCoordinatorProps,\n type EditorCoordinatorValue,\n} from './context/EditorCoordinator';\n\n// ─── 透传 core 的类型,避免使用方需要额外安装 core ────────────────────\nexport type {\n ApiConfig,\n SqlSchema,\n ChatMessage,\n EditorSnapshot,\n CompletionContext,\n CompletionProvider,\n PendingCompletion,\n EditorController,\n AiChatController,\n EditorBus,\n} from '@monaco-ai-editor/core';\n\nexport {\n LANGUAGES,\n THEMES,\n LOCALES,\n type Locale,\n SQL_KEYWORDS,\n SQL_FUNCTIONS,\n SQL_DATA_TYPES,\n} from '@monaco-ai-editor/core';"],"mappings":"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","names":["useState","useRef","useEffect","jsx","jsxs","useState","useRef","useEffect","jsx","jsxs","jsx","jsxs","useCallback","useState","useContext","useCallback","useMemo","useRef","useState","jsx","useRef","useState","useCallback","useMemo","useContext","jsx","jsxs","useState","useCallback","loader","LANGUAGES","THEMES","LOCALES"]}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/vite/monacoAssetsPlugin.ts
|
|
31
|
+
var monacoAssetsPlugin_exports = {};
|
|
32
|
+
__export(monacoAssetsPlugin_exports, {
|
|
33
|
+
monacoAssetsPlugin: () => monacoAssetsPlugin
|
|
34
|
+
});
|
|
35
|
+
module.exports = __toCommonJS(monacoAssetsPlugin_exports);
|
|
36
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
37
|
+
var import_node_fs = __toESM(require("fs"), 1);
|
|
38
|
+
function fixNlsModuleName(content) {
|
|
39
|
+
return content.replace(
|
|
40
|
+
/define\(("|')vs\/nls\.messages\.([^"']+)\.js\1/,
|
|
41
|
+
"define($1vs/nls.messages.$2$1"
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
function isNlsMessagesFile(fileName) {
|
|
45
|
+
return /^nls\.messages\..*\.js\.js$/.test(fileName);
|
|
46
|
+
}
|
|
47
|
+
var MIME_TYPES = {
|
|
48
|
+
".js": "text/javascript",
|
|
49
|
+
".css": "text/css",
|
|
50
|
+
".json": "application/json",
|
|
51
|
+
".ttf": "font/ttf",
|
|
52
|
+
".woff": "font/woff",
|
|
53
|
+
".woff2": "font/woff2",
|
|
54
|
+
".svg": "image/svg+xml",
|
|
55
|
+
".png": "image/png",
|
|
56
|
+
".gif": "image/gif",
|
|
57
|
+
".ico": "image/x-icon"
|
|
58
|
+
};
|
|
59
|
+
function monacoAssetsPlugin(options = {}) {
|
|
60
|
+
const vsDir = options.vsDir || import_node_path.default.resolve(process.cwd(), "node_modules/monaco-editor/min/vs");
|
|
61
|
+
return {
|
|
62
|
+
name: "monaco-assets",
|
|
63
|
+
configureServer(server) {
|
|
64
|
+
server.middlewares.use(
|
|
65
|
+
(req, res, next) => {
|
|
66
|
+
const url = req.url || "";
|
|
67
|
+
const match = url.match(/\/vs\/(.+)$/);
|
|
68
|
+
if (!match) return next();
|
|
69
|
+
let filePath = import_node_path.default.join(vsDir, match[1]);
|
|
70
|
+
let wasRemapped = false;
|
|
71
|
+
if (!import_node_fs.default.existsSync(filePath) && filePath.endsWith(".js")) {
|
|
72
|
+
const jsJsPath = `${filePath}.js`;
|
|
73
|
+
if (import_node_fs.default.existsSync(jsJsPath)) {
|
|
74
|
+
filePath = jsJsPath;
|
|
75
|
+
wasRemapped = true;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
if (import_node_fs.default.existsSync(filePath) && import_node_fs.default.statSync(filePath).isFile()) {
|
|
79
|
+
const ext = import_node_path.default.extname(filePath);
|
|
80
|
+
res.setHeader("Content-Type", MIME_TYPES[ext] ?? "application/octet-stream");
|
|
81
|
+
if (wasRemapped && isNlsMessagesFile(import_node_path.default.basename(filePath))) {
|
|
82
|
+
const content = import_node_fs.default.readFileSync(filePath, "utf-8");
|
|
83
|
+
res.end(fixNlsModuleName(content));
|
|
84
|
+
} else {
|
|
85
|
+
import_node_fs.default.createReadStream(filePath).pipe(res);
|
|
86
|
+
}
|
|
87
|
+
} else {
|
|
88
|
+
next();
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
},
|
|
93
|
+
closeBundle() {
|
|
94
|
+
const distVsDir = import_node_path.default.resolve(process.cwd(), "dist/vs");
|
|
95
|
+
if (!import_node_fs.default.existsSync(vsDir)) {
|
|
96
|
+
console.warn(`[monaco-assets] vs directory not found: ${vsDir}`);
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
copyDir(vsDir, distVsDir);
|
|
100
|
+
const files = import_node_fs.default.readdirSync(distVsDir);
|
|
101
|
+
for (const file of files) {
|
|
102
|
+
if (isNlsMessagesFile(file)) {
|
|
103
|
+
const oldPath = import_node_path.default.join(distVsDir, file);
|
|
104
|
+
const newPath = import_node_path.default.join(distVsDir, file.replace(/\.js\.js$/, ".js"));
|
|
105
|
+
const content = import_node_fs.default.readFileSync(oldPath, "utf-8");
|
|
106
|
+
import_node_fs.default.writeFileSync(newPath, fixNlsModuleName(content));
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
function copyDir(src, dest) {
|
|
113
|
+
import_node_fs.default.mkdirSync(dest, { recursive: true });
|
|
114
|
+
const entries = import_node_fs.default.readdirSync(src, { withFileTypes: true });
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
const srcPath = import_node_path.default.join(src, entry.name);
|
|
117
|
+
const destPath = import_node_path.default.join(dest, entry.name);
|
|
118
|
+
if (entry.isDirectory()) {
|
|
119
|
+
copyDir(srcPath, destPath);
|
|
120
|
+
} else {
|
|
121
|
+
import_node_fs.default.copyFileSync(srcPath, destPath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
126
|
+
0 && (module.exports = {
|
|
127
|
+
monacoAssetsPlugin
|
|
128
|
+
});
|
|
129
|
+
//# sourceMappingURL=monacoAssetsPlugin.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/vite/monacoAssetsPlugin.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/** connect 风格中间件类型(用于 Vite dev server) */\ntype Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;\n\nexport interface MonacoAssetsPluginOptions {\n /** monaco-editor 的 min/vs 目录路径,默认自动从 node_modules 解析 */\n vsDir?: string;\n}\n\n/**\n * 修正 NLS 文件内部的 AMD 模块名。\n *\n * monaco-editor 0.55.x 的 NLS 文件(如 `nls.messages.zh-cn.js.js`)内部\n * `define(\"vs/nls.messages.zh-cn.js\", ...)` 注册的模块名带 `.js` 后缀,\n * 但 `nls.messages-loader` 插件请求的模块名是 `vs/nls.messages.zh-cn`(不带 `.js`)。\n * 这个不匹配会导致 AMD loader 永远等不到模块加载完成,编辑器卡在 Loading 状态。\n *\n * 本函数将 `define(\"vs/nls.messages.<locale>.js\"` 修正为 `define(\"vs/nls.messages.<locale>\"`。\n */\nfunction fixNlsModuleName(content: string): string {\n return content.replace(\n /define\\((\"|')vs\\/nls\\.messages\\.([^\"']+)\\.js\\1/,\n 'define($1vs/nls.messages.$2$1',\n );\n}\n\n/** 判断是否为 NLS 消息文件(如 nls.messages.zh-cn.js.js) */\nfunction isNlsMessagesFile(fileName: string): boolean {\n return /^nls\\.messages\\..*\\.js\\.js$/.test(fileName);\n}\n\n/** vs 目录内常见静态资源的 MIME 类型(其余回退到 application/octet-stream) */\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'text/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.ttf': 'font/ttf',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Vite 插件:将 monaco-editor 的预构建 vs 资源暴露为静态文件。\n *\n * 解决三个问题:\n * 1. dev server 无法直接通过 /node_modules/... 访问 monaco-editor 文件\n * 2. monaco-editor 0.55.x 的 NLS 文件名带双 `.js.js` 后缀,\n * 而 RequireJS 请求的是 `.js`,需要做重映射\n * 3. NLS 文件内部 `define()` 注册的模块名带 `.js` 后缀,与 loader 请求的\n * 模块名不匹配,需重写内容修正模块名\n *\n * @example\n * // vite.config.ts\n * import { monacoAssetsPlugin } from '@monaco-ai-editor/react/vite';\n * export default defineConfig({\n * plugins: [react(), monacoAssetsPlugin()],\n * });\n */\nexport function monacoAssetsPlugin(options: MonacoAssetsPluginOptions = {}) {\n const vsDir =\n options.vsDir || path.resolve(process.cwd(), 'node_modules/monaco-editor/min/vs');\n\n return {\n name: 'monaco-assets',\n configureServer(server: { middlewares: { use: (m: Middleware) => void } }) {\n server.middlewares.use(\n (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const url = req.url || '';\n // 匹配 /vs/ 路径(兼容不同 base 前缀,如 /dns-ui/vs/、/vs/)\n const match = url.match(/\\/vs\\/(.+)$/);\n if (!match) return next();\n\n let filePath = path.join(vsDir, match[1]);\n let wasRemapped = false;\n\n // NLS 文件名重映射:请求 .js 但实际文件是 .js.js(monaco-editor 0.55.x 已知问题)\n if (!fs.existsSync(filePath) && filePath.endsWith('.js')) {\n const jsJsPath = `${filePath}.js`;\n if (fs.existsSync(jsJsPath)) {\n filePath = jsJsPath;\n wasRemapped = true;\n }\n }\n\n if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const ext = path.extname(filePath);\n res.setHeader('Content-Type', MIME_TYPES[ext] ?? 'application/octet-stream');\n\n // 重映射的 NLS 文件需修正内部模块名,否则 AMD loader 永远等不到模块\n if (wasRemapped && isNlsMessagesFile(path.basename(filePath))) {\n const content = fs.readFileSync(filePath, 'utf-8');\n res.end(fixNlsModuleName(content));\n } else {\n fs.createReadStream(filePath).pipe(res);\n }\n } else {\n next();\n }\n },\n );\n },\n closeBundle() {\n // 生产构建时复制 vs 目录到 dist/vs\n const distVsDir = path.resolve(process.cwd(), 'dist/vs');\n if (!fs.existsSync(vsDir)) {\n console.warn(`[monaco-assets] vs directory not found: ${vsDir}`);\n return;\n }\n copyDir(vsDir, distVsDir);\n\n // 重命名 NLS 文件并修正模块名:nls.messages.*.js.js -> nls.messages.*.js\n const files = fs.readdirSync(distVsDir);\n for (const file of files) {\n if (isNlsMessagesFile(file)) {\n const oldPath = path.join(distVsDir, file);\n const newPath = path.join(distVsDir, file.replace(/\\.js\\.js$/, '.js'));\n // 读取原文件,修正模块名后写入新文件名\n const content = fs.readFileSync(oldPath, 'utf-8');\n fs.writeFileSync(newPath, fixNlsModuleName(content));\n }\n }\n },\n };\n}\n\nfunction copyDir(src: string, dest: string) {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n"],"mappings":"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","names":["path","fs"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
|
|
3
|
+
/** connect 风格中间件类型(用于 Vite dev server) */
|
|
4
|
+
type Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
|
|
5
|
+
interface MonacoAssetsPluginOptions {
|
|
6
|
+
/** monaco-editor 的 min/vs 目录路径,默认自动从 node_modules 解析 */
|
|
7
|
+
vsDir?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Vite 插件:将 monaco-editor 的预构建 vs 资源暴露为静态文件。
|
|
11
|
+
*
|
|
12
|
+
* 解决三个问题:
|
|
13
|
+
* 1. dev server 无法直接通过 /node_modules/... 访问 monaco-editor 文件
|
|
14
|
+
* 2. monaco-editor 0.55.x 的 NLS 文件名带双 `.js.js` 后缀,
|
|
15
|
+
* 而 RequireJS 请求的是 `.js`,需要做重映射
|
|
16
|
+
* 3. NLS 文件内部 `define()` 注册的模块名带 `.js` 后缀,与 loader 请求的
|
|
17
|
+
* 模块名不匹配,需重写内容修正模块名
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // vite.config.ts
|
|
21
|
+
* import { monacoAssetsPlugin } from '@monaco-ai-editor/react/vite';
|
|
22
|
+
* export default defineConfig({
|
|
23
|
+
* plugins: [react(), monacoAssetsPlugin()],
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
declare function monacoAssetsPlugin(options?: MonacoAssetsPluginOptions): {
|
|
27
|
+
name: string;
|
|
28
|
+
configureServer(server: {
|
|
29
|
+
middlewares: {
|
|
30
|
+
use: (m: Middleware) => void;
|
|
31
|
+
};
|
|
32
|
+
}): void;
|
|
33
|
+
closeBundle(): void;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { type MonacoAssetsPluginOptions, monacoAssetsPlugin };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from 'node:http';
|
|
2
|
+
|
|
3
|
+
/** connect 风格中间件类型(用于 Vite dev server) */
|
|
4
|
+
type Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;
|
|
5
|
+
interface MonacoAssetsPluginOptions {
|
|
6
|
+
/** monaco-editor 的 min/vs 目录路径,默认自动从 node_modules 解析 */
|
|
7
|
+
vsDir?: string;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Vite 插件:将 monaco-editor 的预构建 vs 资源暴露为静态文件。
|
|
11
|
+
*
|
|
12
|
+
* 解决三个问题:
|
|
13
|
+
* 1. dev server 无法直接通过 /node_modules/... 访问 monaco-editor 文件
|
|
14
|
+
* 2. monaco-editor 0.55.x 的 NLS 文件名带双 `.js.js` 后缀,
|
|
15
|
+
* 而 RequireJS 请求的是 `.js`,需要做重映射
|
|
16
|
+
* 3. NLS 文件内部 `define()` 注册的模块名带 `.js` 后缀,与 loader 请求的
|
|
17
|
+
* 模块名不匹配,需重写内容修正模块名
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // vite.config.ts
|
|
21
|
+
* import { monacoAssetsPlugin } from '@monaco-ai-editor/react/vite';
|
|
22
|
+
* export default defineConfig({
|
|
23
|
+
* plugins: [react(), monacoAssetsPlugin()],
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
declare function monacoAssetsPlugin(options?: MonacoAssetsPluginOptions): {
|
|
27
|
+
name: string;
|
|
28
|
+
configureServer(server: {
|
|
29
|
+
middlewares: {
|
|
30
|
+
use: (m: Middleware) => void;
|
|
31
|
+
};
|
|
32
|
+
}): void;
|
|
33
|
+
closeBundle(): void;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export { type MonacoAssetsPluginOptions, monacoAssetsPlugin };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// src/vite/monacoAssetsPlugin.ts
|
|
2
|
+
import path from "path";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
function fixNlsModuleName(content) {
|
|
5
|
+
return content.replace(
|
|
6
|
+
/define\(("|')vs\/nls\.messages\.([^"']+)\.js\1/,
|
|
7
|
+
"define($1vs/nls.messages.$2$1"
|
|
8
|
+
);
|
|
9
|
+
}
|
|
10
|
+
function isNlsMessagesFile(fileName) {
|
|
11
|
+
return /^nls\.messages\..*\.js\.js$/.test(fileName);
|
|
12
|
+
}
|
|
13
|
+
var MIME_TYPES = {
|
|
14
|
+
".js": "text/javascript",
|
|
15
|
+
".css": "text/css",
|
|
16
|
+
".json": "application/json",
|
|
17
|
+
".ttf": "font/ttf",
|
|
18
|
+
".woff": "font/woff",
|
|
19
|
+
".woff2": "font/woff2",
|
|
20
|
+
".svg": "image/svg+xml",
|
|
21
|
+
".png": "image/png",
|
|
22
|
+
".gif": "image/gif",
|
|
23
|
+
".ico": "image/x-icon"
|
|
24
|
+
};
|
|
25
|
+
function monacoAssetsPlugin(options = {}) {
|
|
26
|
+
const vsDir = options.vsDir || path.resolve(process.cwd(), "node_modules/monaco-editor/min/vs");
|
|
27
|
+
return {
|
|
28
|
+
name: "monaco-assets",
|
|
29
|
+
configureServer(server) {
|
|
30
|
+
server.middlewares.use(
|
|
31
|
+
(req, res, next) => {
|
|
32
|
+
const url = req.url || "";
|
|
33
|
+
const match = url.match(/\/vs\/(.+)$/);
|
|
34
|
+
if (!match) return next();
|
|
35
|
+
let filePath = path.join(vsDir, match[1]);
|
|
36
|
+
let wasRemapped = false;
|
|
37
|
+
if (!fs.existsSync(filePath) && filePath.endsWith(".js")) {
|
|
38
|
+
const jsJsPath = `${filePath}.js`;
|
|
39
|
+
if (fs.existsSync(jsJsPath)) {
|
|
40
|
+
filePath = jsJsPath;
|
|
41
|
+
wasRemapped = true;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {
|
|
45
|
+
const ext = path.extname(filePath);
|
|
46
|
+
res.setHeader("Content-Type", MIME_TYPES[ext] ?? "application/octet-stream");
|
|
47
|
+
if (wasRemapped && isNlsMessagesFile(path.basename(filePath))) {
|
|
48
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
49
|
+
res.end(fixNlsModuleName(content));
|
|
50
|
+
} else {
|
|
51
|
+
fs.createReadStream(filePath).pipe(res);
|
|
52
|
+
}
|
|
53
|
+
} else {
|
|
54
|
+
next();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
},
|
|
59
|
+
closeBundle() {
|
|
60
|
+
const distVsDir = path.resolve(process.cwd(), "dist/vs");
|
|
61
|
+
if (!fs.existsSync(vsDir)) {
|
|
62
|
+
console.warn(`[monaco-assets] vs directory not found: ${vsDir}`);
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
copyDir(vsDir, distVsDir);
|
|
66
|
+
const files = fs.readdirSync(distVsDir);
|
|
67
|
+
for (const file of files) {
|
|
68
|
+
if (isNlsMessagesFile(file)) {
|
|
69
|
+
const oldPath = path.join(distVsDir, file);
|
|
70
|
+
const newPath = path.join(distVsDir, file.replace(/\.js\.js$/, ".js"));
|
|
71
|
+
const content = fs.readFileSync(oldPath, "utf-8");
|
|
72
|
+
fs.writeFileSync(newPath, fixNlsModuleName(content));
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function copyDir(src, dest) {
|
|
79
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
80
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
81
|
+
for (const entry of entries) {
|
|
82
|
+
const srcPath = path.join(src, entry.name);
|
|
83
|
+
const destPath = path.join(dest, entry.name);
|
|
84
|
+
if (entry.isDirectory()) {
|
|
85
|
+
copyDir(srcPath, destPath);
|
|
86
|
+
} else {
|
|
87
|
+
fs.copyFileSync(srcPath, destPath);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export {
|
|
92
|
+
monacoAssetsPlugin
|
|
93
|
+
};
|
|
94
|
+
//# sourceMappingURL=monacoAssetsPlugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/vite/monacoAssetsPlugin.ts"],"sourcesContent":["import path from 'node:path';\nimport fs from 'node:fs';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\n\n/** connect 风格中间件类型(用于 Vite dev server) */\ntype Middleware = (req: IncomingMessage, res: ServerResponse, next: () => void) => void;\n\nexport interface MonacoAssetsPluginOptions {\n /** monaco-editor 的 min/vs 目录路径,默认自动从 node_modules 解析 */\n vsDir?: string;\n}\n\n/**\n * 修正 NLS 文件内部的 AMD 模块名。\n *\n * monaco-editor 0.55.x 的 NLS 文件(如 `nls.messages.zh-cn.js.js`)内部\n * `define(\"vs/nls.messages.zh-cn.js\", ...)` 注册的模块名带 `.js` 后缀,\n * 但 `nls.messages-loader` 插件请求的模块名是 `vs/nls.messages.zh-cn`(不带 `.js`)。\n * 这个不匹配会导致 AMD loader 永远等不到模块加载完成,编辑器卡在 Loading 状态。\n *\n * 本函数将 `define(\"vs/nls.messages.<locale>.js\"` 修正为 `define(\"vs/nls.messages.<locale>\"`。\n */\nfunction fixNlsModuleName(content: string): string {\n return content.replace(\n /define\\((\"|')vs\\/nls\\.messages\\.([^\"']+)\\.js\\1/,\n 'define($1vs/nls.messages.$2$1',\n );\n}\n\n/** 判断是否为 NLS 消息文件(如 nls.messages.zh-cn.js.js) */\nfunction isNlsMessagesFile(fileName: string): boolean {\n return /^nls\\.messages\\..*\\.js\\.js$/.test(fileName);\n}\n\n/** vs 目录内常见静态资源的 MIME 类型(其余回退到 application/octet-stream) */\nconst MIME_TYPES: Record<string, string> = {\n '.js': 'text/javascript',\n '.css': 'text/css',\n '.json': 'application/json',\n '.ttf': 'font/ttf',\n '.woff': 'font/woff',\n '.woff2': 'font/woff2',\n '.svg': 'image/svg+xml',\n '.png': 'image/png',\n '.gif': 'image/gif',\n '.ico': 'image/x-icon',\n};\n\n/**\n * Vite 插件:将 monaco-editor 的预构建 vs 资源暴露为静态文件。\n *\n * 解决三个问题:\n * 1. dev server 无法直接通过 /node_modules/... 访问 monaco-editor 文件\n * 2. monaco-editor 0.55.x 的 NLS 文件名带双 `.js.js` 后缀,\n * 而 RequireJS 请求的是 `.js`,需要做重映射\n * 3. NLS 文件内部 `define()` 注册的模块名带 `.js` 后缀,与 loader 请求的\n * 模块名不匹配,需重写内容修正模块名\n *\n * @example\n * // vite.config.ts\n * import { monacoAssetsPlugin } from '@monaco-ai-editor/react/vite';\n * export default defineConfig({\n * plugins: [react(), monacoAssetsPlugin()],\n * });\n */\nexport function monacoAssetsPlugin(options: MonacoAssetsPluginOptions = {}) {\n const vsDir =\n options.vsDir || path.resolve(process.cwd(), 'node_modules/monaco-editor/min/vs');\n\n return {\n name: 'monaco-assets',\n configureServer(server: { middlewares: { use: (m: Middleware) => void } }) {\n server.middlewares.use(\n (req: IncomingMessage, res: ServerResponse, next: () => void) => {\n const url = req.url || '';\n // 匹配 /vs/ 路径(兼容不同 base 前缀,如 /dns-ui/vs/、/vs/)\n const match = url.match(/\\/vs\\/(.+)$/);\n if (!match) return next();\n\n let filePath = path.join(vsDir, match[1]);\n let wasRemapped = false;\n\n // NLS 文件名重映射:请求 .js 但实际文件是 .js.js(monaco-editor 0.55.x 已知问题)\n if (!fs.existsSync(filePath) && filePath.endsWith('.js')) {\n const jsJsPath = `${filePath}.js`;\n if (fs.existsSync(jsJsPath)) {\n filePath = jsJsPath;\n wasRemapped = true;\n }\n }\n\n if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) {\n const ext = path.extname(filePath);\n res.setHeader('Content-Type', MIME_TYPES[ext] ?? 'application/octet-stream');\n\n // 重映射的 NLS 文件需修正内部模块名,否则 AMD loader 永远等不到模块\n if (wasRemapped && isNlsMessagesFile(path.basename(filePath))) {\n const content = fs.readFileSync(filePath, 'utf-8');\n res.end(fixNlsModuleName(content));\n } else {\n fs.createReadStream(filePath).pipe(res);\n }\n } else {\n next();\n }\n },\n );\n },\n closeBundle() {\n // 生产构建时复制 vs 目录到 dist/vs\n const distVsDir = path.resolve(process.cwd(), 'dist/vs');\n if (!fs.existsSync(vsDir)) {\n console.warn(`[monaco-assets] vs directory not found: ${vsDir}`);\n return;\n }\n copyDir(vsDir, distVsDir);\n\n // 重命名 NLS 文件并修正模块名:nls.messages.*.js.js -> nls.messages.*.js\n const files = fs.readdirSync(distVsDir);\n for (const file of files) {\n if (isNlsMessagesFile(file)) {\n const oldPath = path.join(distVsDir, file);\n const newPath = path.join(distVsDir, file.replace(/\\.js\\.js$/, '.js'));\n // 读取原文件,修正模块名后写入新文件名\n const content = fs.readFileSync(oldPath, 'utf-8');\n fs.writeFileSync(newPath, fixNlsModuleName(content));\n }\n }\n },\n };\n}\n\nfunction copyDir(src: string, dest: string) {\n fs.mkdirSync(dest, { recursive: true });\n const entries = fs.readdirSync(src, { withFileTypes: true });\n for (const entry of entries) {\n const srcPath = path.join(src, entry.name);\n const destPath = path.join(dest, entry.name);\n if (entry.isDirectory()) {\n copyDir(srcPath, destPath);\n } else {\n fs.copyFileSync(srcPath, destPath);\n }\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@monaco-ai-editor/react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React adapter for monaco-ai-editor core — standalone or coordinated editor & chat panels.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
},
|
|
15
|
+
"./vite": {
|
|
16
|
+
"import": "./dist/vite/monacoAssetsPlugin.js",
|
|
17
|
+
"require": "./dist/vite/monacoAssetsPlugin.cjs"
|
|
18
|
+
},
|
|
19
|
+
"./style.css": "./dist/style.css"
|
|
20
|
+
},
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"files": [
|
|
25
|
+
"dist"
|
|
26
|
+
],
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@monaco-editor/react": "^4.7.0"
|
|
29
|
+
},
|
|
30
|
+
"peerDependencies": {
|
|
31
|
+
"monaco-editor": ">=0.40.0",
|
|
32
|
+
"react": ">=18",
|
|
33
|
+
"react-dom": ">=18",
|
|
34
|
+
"@monaco-ai-editor/core": "^0.1.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/node": "^26.0.0",
|
|
38
|
+
"@types/react": "^19.2.14",
|
|
39
|
+
"@types/react-dom": "^19.2.3",
|
|
40
|
+
"monaco-editor": "^0.55.1",
|
|
41
|
+
"react": "^19.2.5",
|
|
42
|
+
"react-dom": "^19.2.5",
|
|
43
|
+
"tsup": "^8.3.0",
|
|
44
|
+
"typescript": "^5.6.0",
|
|
45
|
+
"@monaco-ai-editor/core": "0.1.0"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup",
|
|
49
|
+
"dev": "tsup --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit"
|
|
51
|
+
}
|
|
52
|
+
}
|