@sciexpr/vue 0.2.0 → 0.2.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/composables/useFormulaRender.ts","../src/components/Formula.vue","../src/composables/useFormulaEditor.ts","../src/composables/useAutocomplete.ts","../src/composables/useAIProvider.ts","../src/components/Toolbar.vue","../src/components/LivePreview.vue","../src/components/AutocompleteDropdown.vue","../src/components/FormulaEditor.vue","../src/components/SymbolPanel.vue","../src/components/ElementTable.vue","../src/composables/useShortcuts.ts"],"sourcesContent":["// @sciexpr/vue — useFormulaRender Composable\r\n// ============================================================================\r\n\r\nimport { ref, watch, onMounted, shallowRef, type Ref } from 'vue';\r\nimport type { ExpressionRoot } from '@sciexpr/core';\r\nimport {\r\n KatexRenderer,\r\n UnicodeRenderer,\r\n MathMLRenderer,\r\n LatexReverseRenderer,\r\n type RenderOptions,\r\n type RenderError,\r\n} from '@sciexpr/renderer';\r\nimport { ParserRegistry } from '@sciexpr/parser';\r\n\r\n/**\r\n * 公式渲染 composable\r\n *\r\n * 将 LaTeX 源码渲染为 HTML / MathML / Unicode。\r\n *\r\n * @example\r\n * ```ts\r\n * const { html, error, render } = useFormulaRender({\r\n * source: ref('\\\\frac{1}{2}'),\r\n * displayMode: true,\r\n * });\r\n * ```\r\n */\r\nexport function useFormulaRender(options: {\r\n source: Ref<string>;\r\n displayMode?: boolean;\r\n katexRenderer?: KatexRenderer;\r\n renderOptions?: RenderOptions;\r\n}) {\r\n const html = ref('');\r\n const mathml = ref('');\r\n const unicode = ref('');\r\n const error = ref<RenderError | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n const katexRenderer = options.katexRenderer ?? new KatexRenderer();\r\n const unicodeRenderer = new UnicodeRenderer();\r\n const mathmlRenderer = new MathMLRenderer();\r\n\r\n function render(source: string): void {\r\n try {\r\n const ast = parser.parse(source, { hint: 'auto' });\r\n if (!ast || ast.children.length === 0) {\r\n html.value = '';\r\n error.value = null;\r\n return;\r\n }\r\n\r\n // Render HTML via KaTeX\r\n const htmlResult = katexRenderer.render(ast, {\r\n displayMode: options.displayMode,\r\n ...options.renderOptions,\r\n });\r\n html.value = htmlResult.value;\r\n if (htmlResult.warnings?.length) {\r\n // Non-blocking warnings — could expose via warn ref\r\n }\r\n\r\n // Render MathML\r\n mathml.value = mathmlRenderer.render(ast).value;\r\n\r\n // Render Unicode\r\n unicode.value = unicodeRenderer.render(ast).value;\r\n\r\n error.value = null;\r\n } catch (err) {\r\n error.value = {\r\n message: err instanceof Error ? err.message : String(err),\r\n };\r\n html.value = '';\r\n }\r\n }\r\n\r\n // Watch for source changes\r\n watch(options.source, (newSource) => {\r\n render(newSource);\r\n }, { immediate: true });\r\n\r\n return {\r\n html,\r\n mathml,\r\n unicode,\r\n error,\r\n render,\r\n };\r\n}\r\n\r\n/**\r\n * Formula 渲染专用\r\n * 简化版的 useFormulaRender,只返回 HTML\r\n */\r\nexport function useFormula(options: {\r\n source: Ref<string>;\r\n displayMode?: Ref<boolean>;\r\n}) {\r\n const html = ref('');\r\n const error = ref<RenderError | null>(null);\r\n const ast = shallowRef<ExpressionRoot | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n const katexRenderer = new KatexRenderer();\r\n\r\n function render(source: string): void {\r\n try {\r\n const parsed = parser.parse(source, { hint: 'auto' });\r\n ast.value = parsed;\r\n\r\n if (!parsed || parsed.children.length === 0) {\r\n html.value = '';\r\n error.value = null;\r\n return;\r\n }\r\n\r\n const result = katexRenderer.render(parsed, {\r\n displayMode: options.displayMode?.value ?? false,\r\n });\r\n html.value = result.value;\r\n error.value = null;\r\n } catch (err) {\r\n error.value = {\r\n message: err instanceof Error ? err.message : String(err),\r\n };\r\n html.value = source;\r\n }\r\n }\r\n\r\n watch([options.source, options.displayMode ?? ref(false)], ([src]) => {\r\n render(src!);\r\n }, { immediate: true });\r\n\r\n return { html, error, ast, render };\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { ref, useSlots, type Ref } from 'vue';\r\nimport { useFormula } from '../composables/useFormulaRender';\r\n\r\n/**\r\n * Formula — 纯公式渲染组件\r\n *\r\n * 支持三种输入方式:\r\n * 1. source prop: <Formula source=\"\\frac{1}{2}\" />\r\n * 2. default slot: <Formula>\\frac{1}{2}</Formula>\r\n * 3. ast prop (未来): <Formula :ast=\"astRoot\" />\r\n *\r\n * @example\r\n * ```vue\r\n * <Formula source=\"\\frac{x^2 + y^2}{\\sqrt{z}}\" display-mode />\r\n * <Formula>E = mc^2</Formula>\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n source?: string;\r\n displayMode?: boolean;\r\n throwOnError?: boolean;\r\n className?: string;\r\n fallbackText?: string;\r\n}>(), {\r\n source: '',\r\n displayMode: false,\r\n throwOnError: false,\r\n className: '',\r\n fallbackText: '',\r\n});\r\n\r\nconst slots = useSlots();\r\nconst slotContent = slots.default?.()?.[0]?.children as string | undefined;\r\n\r\n// Use slot content if source prop is empty\r\nconst effectiveSource = ref(props.source || slotContent || '') as Ref<string>;\r\n\r\nconst { html, error } = useFormula({\r\n source: effectiveSource,\r\n displayMode: ref(props.displayMode),\r\n});\r\n</script>\r\n\r\n<template>\r\n <span\r\n :class=\"['sciexpr-formula', props.className, {\r\n 'sciexpr-display': props.displayMode,\r\n 'sciexpr-error': error,\r\n }]\"\r\n :data-source=\"effectiveSource\"\r\n >\r\n <span v-if=\"error\" class=\"sciexpr-formula-error\" :title=\"error.message\">\r\n {{ fallbackText || effectiveSource }}\r\n </span>\r\n <span v-else v-html=\"html\" class=\"sciexpr-formula-content\" />\r\n </span>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-formula {\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n\r\n.sciexpr-formula.sciexpr-display {\r\n display: block;\r\n text-align: center;\r\n margin: 1em 0;\r\n}\r\n\r\n.sciexpr-formula-error {\r\n color: #d93025;\r\n font-family: 'Courier New', monospace;\r\n font-size: 0.9em;\r\n padding: 2px 6px;\r\n background: #fce8e6;\r\n border-radius: 4px;\r\n border: 1px solid #f5c6cb;\r\n}\r\n\r\n.sciexpr-formula-content :deep(.katex) {\r\n font-size: 1.1em;\r\n}\r\n\r\n.sciexpr-formula.sciexpr-display :deep(.katex) {\r\n font-size: 1.21em;\r\n}\r\n</style>\r\n","// @sciexpr/vue — useFormulaEditor Composable\r\n// ============================================================================\r\n\r\nimport { ref, watch, computed, type Ref, type ComputedRef } from 'vue';\r\nimport type { ExpressionRoot } from '@sciexpr/core';\r\nimport { ParserRegistry } from '@sciexpr/parser';\r\nimport type { RenderError, RenderOptions } from '@sciexpr/renderer';\r\nimport type { AutocompleteConfig, ToolbarConfig } from '../types';\r\n\r\n/**\r\n * 公式编辑器核心 composable\r\n *\r\n * 管理编辑器状态:值、光标位置、补全、解析、验证。\r\n *\r\n * @example\r\n * ```ts\r\n * const {\r\n * value, html, cursor, ast, error,\r\n * insertText, handleInput, getCompletions,\r\n * } = useFormulaEditor({ initialValue: '' });\r\n * ```\r\n */\r\nexport function useFormulaEditor(options: {\r\n initialValue?: string;\r\n displayMode?: boolean;\r\n autocomplete?: AutocompleteConfig;\r\n renderOptions?: RenderOptions;\r\n}) {\r\n const value = ref(options.initialValue ?? '');\r\n const cursor = ref(0);\r\n const html = ref('');\r\n const error = ref<RenderError | null>(null);\r\n const ast = ref<ExpressionRoot | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n\r\n // ==========================================================================\r\n // Input Handling\r\n // ==========================================================================\r\n\r\n function handleInput(newValue: string, newCursor?: number): void {\r\n value.value = newValue;\r\n if (newCursor !== undefined) {\r\n cursor.value = newCursor;\r\n }\r\n }\r\n\r\n /** 在光标位置插入文本 */\r\n function insertText(text: string): void {\r\n const before = value.value.slice(0, cursor.value);\r\n const after = value.value.slice(cursor.value);\r\n value.value = before + text + after;\r\n cursor.value += text.length;\r\n }\r\n\r\n /** 用 LaTeX 模板包裹选中文本 */\r\n function wrapSelection(before: string, after: string): void {\r\n const val = value.value;\r\n // For simplicity, wrap the whole current value\r\n value.value = before + val + after;\r\n cursor.value = value.value.length;\r\n }\r\n\r\n // ==========================================================================\r\n // Parsing & Validation\r\n // ==========================================================================\r\n\r\n function parse(): ExpressionRoot | null {\r\n try {\r\n const result = parser.parse(value.value, { hint: 'auto' });\r\n ast.value = result;\r\n return result;\r\n } catch {\r\n ast.value = null;\r\n return null;\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Computed\r\n // ==========================================================================\r\n\r\n const isEmpty = computed(() => value.value.trim().length === 0);\r\n const latexSource = computed(() => value.value);\r\n\r\n return {\r\n // State\r\n value,\r\n cursor,\r\n html,\r\n ast,\r\n error,\r\n // Computed\r\n isEmpty,\r\n latexSource,\r\n // Actions\r\n handleInput,\r\n insertText,\r\n wrapSelection,\r\n parse,\r\n };\r\n}\r\n","// @sciexpr/vue — useAutocomplete Composable\r\n// ============================================================================\r\n\r\nimport { ref, type Ref } from 'vue';\r\nimport type { CompletionItem, CompletionContext } from '@sciexpr/ai';\r\nimport { AIPipeline } from '@sciexpr/ai';\r\nimport { ExpressionKind } from '@sciexpr/core';\r\nimport type { AutocompleteConfig } from '../types';\r\n\r\n/**\r\n * 自动补全 composable\r\n *\r\n * 管理公式编辑器的自动补全状态和交互。\r\n *\r\n * @example\r\n * ```ts\r\n * const { suggestions, visible, query, trigger } = useAutocomplete({\r\n * config: { enabled: true, minTriggerLength: 2 },\r\n * pipeline: aiPipeline,\r\n * });\r\n * ```\r\n */\r\nexport function useAutocomplete(options: {\r\n config?: AutocompleteConfig;\r\n pipeline?: AIPipeline | null;\r\n}) {\r\n const suggestions = ref<CompletionItem[]>([]);\r\n const visible = ref(false);\r\n const selectedIndex = ref(0);\r\n const query = ref('');\r\n\r\n const pipeline = options.pipeline ?? new AIPipeline();\r\n const config = options.config ?? { enabled: true, minTriggerLength: 2, maxItems: 10 };\r\n\r\n /** 触发补全 */\r\n async function trigger(input: string, cursorPos: number): Promise<void> {\r\n if (!config.enabled) {\r\n visible.value = false;\r\n return;\r\n }\r\n\r\n const token = extractToken(input, cursorPos);\r\n if (!token || token.length < (config.minTriggerLength ?? 2)) {\r\n visible.value = false;\r\n return;\r\n }\r\n\r\n query.value = token;\r\n\r\n const context: CompletionContext = {\r\n currentInput: input,\r\n cursorPosition: cursorPos,\r\n expressionType: ExpressionKind.Math,\r\n };\r\n\r\n const result = await pipeline.getCompletions(context);\r\n suggestions.value = result.items.slice(0, config.maxItems ?? 10);\r\n visible.value = suggestions.value.length > 0;\r\n selectedIndex.value = 0;\r\n }\r\n\r\n /** 选择补全项 */\r\n function select(item: CompletionItem): string {\r\n visible.value = false;\r\n return item.text;\r\n }\r\n\r\n /** 键盘导航 */\r\n function moveSelection(direction: 'up' | 'down'): void {\r\n if (direction === 'up') {\r\n selectedIndex.value = Math.max(0, selectedIndex.value - 1);\r\n } else {\r\n selectedIndex.value = Math.min(suggestions.value.length - 1, selectedIndex.value + 1);\r\n }\r\n }\r\n\r\n /** 关闭补全 */\r\n function close(): void {\r\n visible.value = false;\r\n suggestions.value = [];\r\n }\r\n\r\n return {\r\n suggestions,\r\n visible,\r\n selectedIndex,\r\n query,\r\n trigger,\r\n select,\r\n moveSelection,\r\n close,\r\n };\r\n}\r\n\r\n/** 提取光标前的 token */\r\nfunction extractToken(input: string, cursor: number): string {\r\n const before = input.slice(0, cursor);\r\n // Extract \\command token\r\n const backslashIdx = before.lastIndexOf('\\\\');\r\n if (backslashIdx !== -1) {\r\n const afterSlash = before.slice(backslashIdx);\r\n const match = afterSlash.match(/^\\\\[a-zA-Z]*$/);\r\n if (match) return match[0];\r\n }\r\n // Extract plain text token\r\n const match = before.match(/([a-zA-Z_]+)$/);\r\n return match ? match[1]! : '';\r\n}\r\n","// @sciexpr/vue — useAIProvider Composable\r\n// ============================================================================\r\n\r\nimport { inject, provide, type InjectionKey } from 'vue';\r\nimport type { IAICompletionProvider, IKnowledgeBaseProvider, IAINormalizerProvider, IAIFormatterProvider } from '@sciexpr/ai';\r\nimport { AIPipeline, BuiltinCompletionProvider, BuiltinKnowledgeBase, BuiltinNormalizer, BuiltinFormatter } from '@sciexpr/ai';\r\nimport type { AIPipelineConfig } from '@sciexpr/ai';\r\n\r\n/** AI Provider 注入 token */\r\nexport const AI_PIPELINE_KEY: InjectionKey<AIPipeline> = Symbol('sciexpr-ai-pipeline');\r\n\r\n/**\r\n * AI Provider 注入 composable\r\n *\r\n * 在 Vue 组件树的顶层提供 AI Provider 配置,\r\n * 所有子组件中的 FormulaEditor 自动获取 AI 能力。\r\n *\r\n * @example\r\n * ```ts\r\n * // App.vue setup\r\n * const { provideAI } = useAIProvider();\r\n * provideAI({\r\n * completionProvider: new MyOpenAIProvider(),\r\n * knowledgeBaseProvider: new MyKBProvider(),\r\n * });\r\n * ```\r\n */\r\nexport function useAIProvider(config?: AIPipelineConfig) {\r\n const pipeline = config ? new AIPipeline(config) : inject(AI_PIPELINE_KEY, null);\r\n\r\n /** 在当前组件树提供 AI Pipeline */\r\n function provideAI(aiConfig: AIPipelineConfig): void {\r\n const p = new AIPipeline(aiConfig);\r\n provide(AI_PIPELINE_KEY, p);\r\n }\r\n\r\n /** 设置补全提供者 */\r\n function setCompletionProvider(provider: IAICompletionProvider): void {\r\n if (pipeline) {\r\n // Create new pipeline with the provider\r\n provide(AI_PIPELINE_KEY, new AIPipeline({ completionProvider: provider }));\r\n }\r\n }\r\n\r\n /** 设置知识库提供者 */\r\n function setKnowledgeBase(provider: IKnowledgeBaseProvider): void {\r\n if (pipeline) {\r\n provide(AI_PIPELINE_KEY, new AIPipeline({ knowledgeBaseProvider: provider }));\r\n }\r\n }\r\n\r\n return {\r\n pipeline,\r\n provideAI,\r\n setCompletionProvider,\r\n setKnowledgeBase,\r\n };\r\n}\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue';\r\n\r\n/**\r\n * Toolbar — 公式工具栏组件\r\n *\r\n * 提供常用 LaTeX 命令的快捷按钮。\r\n * 支持内置分类和自定义命令。\r\n *\r\n * @example\r\n * ```vue\r\n * <Toolbar @insert=\"(latex) => editor.insertText(latex)\" />\r\n * <Toolbar :categories=\"['fraction', 'symbol']\" @insert=\"onInsert\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n categories?: ('fraction' | 'script' | 'radical' | 'symbol' | 'matrix' | 'chemistry' | 'greek')[];\r\n disabled?: boolean;\r\n compact?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n/** 内置工具栏命令 */\r\ninterface ToolbarCategoryItem {\r\n id: string;\r\n label: string;\r\n icon?: string;\r\n commands: ToolbarCommandItem[];\r\n}\r\n\r\ninterface ToolbarCommandItem {\r\n latex: string;\r\n label: string;\r\n description: string;\r\n}\r\n\r\nconst commandCategories: ToolbarCategoryItem[] = [\r\n {\r\n id: 'fraction', label: 'Fraction & Script', icon: '📐',\r\n commands: [\r\n { latex: '\\\\frac{}{}', label: '⅟', description: 'Fraction' },\r\n { latex: '^{}', label: 'x²', description: 'Superscript' },\r\n { latex: '_{}', label: 'x₂', description: 'Subscript' },\r\n { latex: '^{}_{}', label: 'x²₁', description: 'Both scripts' },\r\n ],\r\n },\r\n {\r\n id: 'radical', label: 'Radicals', icon: '√',\r\n commands: [\r\n { latex: '\\\\sqrt{}', label: '√x', description: 'Square root' },\r\n { latex: '\\\\sqrt[3]{}', label: '∛x', description: 'Cube root' },\r\n { latex: '\\\\sqrt[n]{}', label: 'ⁿ√x', description: 'Nth root' },\r\n ],\r\n },\r\n {\r\n id: 'symbol', label: 'Operators', icon: '∑',\r\n commands: [\r\n { latex: '\\\\sum_{}^{}', label: '∑', description: 'Summation' },\r\n { latex: '\\\\prod_{}^{}', label: '∏', description: 'Product' },\r\n { latex: '\\\\int_{}^{}', label: '∫', description: 'Integral' },\r\n { latex: '\\\\lim_{x \\\\to }{}', label: 'lim', description: 'Limit' },\r\n { latex: '\\\\infty', label: '∞', description: 'Infinity' },\r\n { latex: '\\\\partial', label: '∂', description: 'Partial derivative' },\r\n ],\r\n },\r\n {\r\n id: 'greek', label: 'Greek', icon: 'α',\r\n commands: [\r\n { latex: '\\\\alpha', label: 'α', description: 'Alpha' },\r\n { latex: '\\\\beta', label: 'β', description: 'Beta' },\r\n { latex: '\\\\gamma', label: 'γ', description: 'Gamma' },\r\n { latex: '\\\\delta', label: 'δ', description: 'Delta' },\r\n { latex: '\\\\theta', label: 'θ', description: 'Theta' },\r\n { latex: '\\\\lambda', label: 'λ', description: 'Lambda' },\r\n { latex: '\\\\mu', label: 'μ', description: 'Mu' },\r\n { latex: '\\\\pi', label: 'π', description: 'Pi' },\r\n { latex: '\\\\sigma', label: 'σ', description: 'Sigma' },\r\n { latex: '\\\\phi', label: 'φ', description: 'Phi' },\r\n { latex: '\\\\omega', label: 'ω', description: 'Omega' },\r\n ],\r\n },\r\n {\r\n id: 'matrix', label: 'Matrix', icon: '▦',\r\n commands: [\r\n { latex: '\\\\begin{pmatrix} & \\\\\\\\ & \\\\end{pmatrix}', label: '( )', description: 'pmatrix' },\r\n { latex: '\\\\begin{bmatrix} & \\\\\\\\ & \\\\end{bmatrix}', label: '[ ]', description: 'bmatrix' },\r\n { latex: '\\\\begin{vmatrix} & \\\\\\\\ & \\\\end{vmatrix}', label: '| |', description: 'vmatrix' },\r\n ],\r\n },\r\n {\r\n id: 'chemistry', label: 'Chemistry', icon: '⚗',\r\n commands: [\r\n { latex: '\\\\ce{H2O}', label: 'H₂O', description: 'Water' },\r\n { latex: '\\\\ce{->}', label: '→', description: 'Reaction arrow' },\r\n { latex: '\\\\ce{<=>}', label: '⇌', description: 'Equilibrium' },\r\n { latex: '^{n+}', label: 'ⁿ⁺', description: 'Charge' },\r\n ],\r\n },\r\n];\r\n\r\nfunction insertCommand(latex: string): void {\r\n emit('insert', latex);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-toolbar', { 'sciexpr-toolbar-compact': compact }]\" role=\"toolbar\" aria-label=\"Formula toolbar\">\r\n <template v-for=\"cat in commandCategories\" :key=\"cat.id\">\r\n <div\r\n v-if=\"!categories || categories.includes(cat.id as any)\"\r\n :class=\"['sciexpr-toolbar-group', { 'sciexpr-toolbar-group-compact': compact }]\"\r\n >\r\n <span v-if=\"!compact\" class=\"sciexpr-toolbar-group-label\">\r\n {{ cat.icon }} {{ cat.label }}\r\n </span>\r\n <button\r\n v-for=\"cmd in cat.commands\"\r\n :key=\"cmd.latex\"\r\n :class=\"['sciexpr-toolbar-btn', { 'sciexpr-toolbar-btn-compact': compact }]\"\r\n :title=\"cmd.description\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertCommand(cmd.latex)\"\r\n >\r\n <slot :name=\"`btn-${cmd.label}`\" :command=\"cmd\">\r\n {{ cmd.label }}\r\n </slot>\r\n </button>\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-toolbar {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 4px;\r\n padding: 8px;\r\n background: #f8f9fa;\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px 8px 0 0;\r\n border-bottom: none;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-toolbar-compact {\r\n padding: 4px;\r\n gap: 2px;\r\n}\r\n\r\n.sciexpr-toolbar-group {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 0 6px;\r\n border-right: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-toolbar-group:last-child {\r\n border-right: none;\r\n}\r\n\r\n.sciexpr-toolbar-group-compact {\r\n padding: 0 2px;\r\n}\r\n\r\n.sciexpr-toolbar-group-label {\r\n font-size: 0.75em;\r\n color: #6c757d;\r\n margin-right: 4px;\r\n white-space: nowrap;\r\n}\r\n\r\n.sciexpr-toolbar-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 28px;\r\n height: 28px;\r\n padding: 2px 6px;\r\n border: 1px solid #ced4da;\r\n border-radius: 4px;\r\n background: #fff;\r\n color: #212529;\r\n font-size: 0.85em;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n cursor: pointer;\r\n transition: all 0.15s ease;\r\n}\r\n\r\n.sciexpr-toolbar-btn:hover:not(:disabled) {\r\n background: #e9ecef;\r\n border-color: #adb5bd;\r\n transform: translateY(-1px);\r\n}\r\n\r\n.sciexpr-toolbar-btn:active:not(:disabled) {\r\n background: #dee2e6;\r\n transform: translateY(0);\r\n}\r\n\r\n.sciexpr-toolbar-btn:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-toolbar-btn-compact {\r\n min-width: 24px;\r\n height: 24px;\r\n font-size: 0.75em;\r\n padding: 1px 4px;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, type Ref } from 'vue';\r\nimport { useFormula } from '../composables/useFormulaRender';\r\n\r\n/**\r\n * LivePreview — 公式实时预览组件\r\n *\r\n * 接收 LaTeX 源码,实时渲染为 HTML 预览。\r\n *\r\n * @example\r\n * ```vue\r\n * <LivePreview :source=\"latexCode\" display-mode />\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n source: string;\r\n displayMode?: boolean;\r\n showSource?: boolean;\r\n}>(), {\r\n displayMode: false,\r\n showSource: false,\r\n});\r\n\r\nconst sourceRef = ref(props.source) as Ref<string>;\r\nconst displayRef = ref(props.displayMode) as Ref<boolean>;\r\n\r\nimport { watch } from 'vue';\r\nwatch(() => props.source, (v) => { sourceRef.value = v; });\r\nwatch(() => props.displayMode, (v) => { displayRef.value = v; });\r\n\r\nconst { html, error } = useFormula({\r\n source: sourceRef,\r\n displayMode: displayRef,\r\n});\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-preview', { 'sciexpr-preview-display': displayMode }]\">\r\n <div v-if=\"error\" class=\"sciexpr-preview-error\">\r\n <span class=\"sciexpr-preview-error-icon\">⚠</span>\r\n <span>{{ error.message }}</span>\r\n </div>\r\n <div v-else-if=\"html\" class=\"sciexpr-preview-render\">\r\n <span v-html=\"html\" />\r\n </div>\r\n <div v-else class=\"sciexpr-preview-empty\">\r\n <span class=\"sciexpr-preview-empty-text\">Preview</span>\r\n </div>\r\n\r\n <div v-if=\"showSource && source\" class=\"sciexpr-preview-source\">\r\n <code>{{ source }}</code>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-preview {\r\n border: 1px solid #dee2e6;\r\n border-radius: 0 0 8px 8px;\r\n min-height: 60px;\r\n padding: 16px;\r\n background: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.sciexpr-preview-display {\r\n min-height: 80px;\r\n}\r\n\r\n.sciexpr-preview-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #d93025;\r\n font-size: 0.85em;\r\n font-family: 'Courier New', monospace;\r\n}\r\n\r\n.sciexpr-preview-error-icon {\r\n font-size: 1.2em;\r\n}\r\n\r\n.sciexpr-preview-render {\r\n overflow-x: auto;\r\n max-width: 100%;\r\n}\r\n\r\n.sciexpr-preview-empty {\r\n color: #adb5bd;\r\n font-size: 0.9em;\r\n font-style: italic;\r\n}\r\n\r\n.sciexpr-preview-source {\r\n margin-top: 8px;\r\n padding: 6px 10px;\r\n background: #f8f9fa;\r\n border-radius: 4px;\r\n font-size: 0.8em;\r\n font-family: 'Courier New', monospace;\r\n color: #6c757d;\r\n border-top: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-preview :deep(.katex) {\r\n font-size: 1.1em;\r\n}\r\n\r\n.sciexpr-preview-display :deep(.katex) {\r\n font-size: 1.21em;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { inject, type Ref } from 'vue';\r\nimport type { CompletionItem } from '@sciexpr/ai';\r\nimport { AI_PIPELINE_KEY } from '../composables/useAIProvider';\r\n\r\n/**\r\n * AutocompleteDropdown — 自动补全下拉组件\r\n *\r\n * 显示公式编辑器的补全候选项列表,支持键盘导航。\r\n *\r\n * @example\r\n * ```vue\r\n * <AutocompleteDropdown\r\n * :items=\"suggestions\"\r\n * :visible=\"showAutocomplete\"\r\n * :selected-index=\"selectedIdx\"\r\n * @select=\"onSelect\"\r\n * />\r\n * ```\r\n */\r\ndefineProps<{\r\n items: CompletionItem[];\r\n visible: boolean;\r\n selectedIndex: number;\r\n position?: { top: number; left: number };\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n select: [item: CompletionItem];\r\n close: [];\r\n}>();\r\n\r\nconst pipeline = inject(AI_PIPELINE_KEY, null);\r\n\r\nfunction selectItem(item: CompletionItem): void {\r\n emit('select', item);\r\n}\r\n\r\nfunction getCategoryColor(category: string): string {\r\n const map: Record<string, string> = {\r\n symbol: '#0d6efd',\r\n command: '#6f42c1',\r\n template: '#198754',\r\n correction: '#fd7e14',\r\n formula: '#d63384',\r\n };\r\n return map[category] ?? '#6c757d';\r\n}\r\n</script>\r\n\r\n<template>\r\n <Teleport to=\"body\">\r\n <div\r\n v-if=\"visible && items.length > 0\"\r\n class=\"sciexpr-autocomplete\"\r\n :style=\"position ? { top: position.top + 'px', left: position.left + 'px' } : {}\"\r\n role=\"listbox\"\r\n >\r\n <div\r\n v-for=\"(item, index) in items\"\r\n :key=\"`${item.text}-${index}`\"\r\n :class=\"['sciexpr-autocomplete-item', { selected: index === selectedIndex }]\"\r\n role=\"option\"\r\n :aria-selected=\"index === selectedIndex\"\r\n @click=\"selectItem(item)\"\r\n @mouseenter=\"$emit('select', item)\"\r\n >\r\n <span\r\n class=\"sciexpr-autocomplete-category\"\r\n :style=\"{ background: getCategoryColor(item.category) }\"\r\n >\r\n {{ item.category }}\r\n </span>\r\n <span class=\"sciexpr-autocomplete-label\">{{ item.label }}</span>\r\n <span v-if=\"item.description\" class=\"sciexpr-autocomplete-desc\">\r\n {{ item.description }}\r\n </span>\r\n <span v-if=\"pipeline\" class=\"sciexpr-autocomplete-source\">\r\n {{ item.previewHtml ? 'AI' : '' }}\r\n </span>\r\n </div>\r\n </div>\r\n </Teleport>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-autocomplete {\r\n position: fixed;\r\n z-index: 10000;\r\n min-width: 220px;\r\n max-width: 360px;\r\n max-height: 240px;\r\n overflow-y: auto;\r\n background: #fff;\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\r\n padding: 4px;\r\n}\r\n\r\n.sciexpr-autocomplete-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 10px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n font-size: 0.85em;\r\n transition: background 0.1s ease;\r\n}\r\n\r\n.sciexpr-autocomplete-item:hover,\r\n.sciexpr-autocomplete-item.selected {\r\n background: #e7f1ff;\r\n}\r\n\r\n.sciexpr-autocomplete-category {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 1px 6px;\r\n border-radius: 4px;\r\n color: #fff;\r\n font-size: 0.7em;\r\n font-weight: 500;\r\n text-transform: uppercase;\r\n white-space: nowrap;\r\n}\r\n\r\n.sciexpr-autocomplete-label {\r\n font-weight: 500;\r\n color: #212529;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n font-family: 'Courier New', monospace;\r\n font-size: 0.95em;\r\n}\r\n\r\n.sciexpr-autocomplete-desc {\r\n color: #6c757d;\r\n font-size: 0.8em;\r\n margin-left: auto;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 80px;\r\n}\r\n\r\n.sciexpr-autocomplete-source {\r\n font-size: 0.65em;\r\n color: #adb5bd;\r\n font-style: italic;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, watch, computed, nextTick, type ComponentPublicInstance } from 'vue';\r\nimport { useFormulaEditor } from '../composables/useFormulaEditor';\r\nimport { useAutocomplete } from '../composables/useAutocomplete';\r\nimport { useAIProvider } from '../composables/useAIProvider';\r\nimport Toolbar from './Toolbar.vue';\r\nimport LivePreview from './LivePreview.vue';\r\nimport AutocompleteDropdown from './AutocompleteDropdown.vue';\r\nimport type { ToolbarConfig, AutocompleteConfig } from '../types';\r\n\r\n/**\r\n * FormulaEditor — 公式编辑器核心组件\r\n *\r\n * 一个功能完整的 LaTeX / 化学式编辑器,包含:\r\n * - 工具栏快捷插入\r\n * - 实时预览\r\n * - 自动补全 (AI + 本地)\r\n * - 键盘快捷键\r\n *\r\n * @example\r\n * ```vue\r\n * <FormulaEditor v-model=\"formula\" display-mode />\r\n * <FormulaEditor :value=\"latex\" @change=\"onFormulaChange\" />\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n value?: string;\r\n displayMode?: boolean;\r\n readonly?: boolean;\r\n placeholder?: string;\r\n toolbar?: ToolbarConfig;\r\n autocomplete?: AutocompleteConfig;\r\n showPreview?: boolean;\r\n showToolbar?: boolean;\r\n rows?: number;\r\n}>(), {\r\n value: '',\r\n displayMode: false,\r\n readonly: false,\r\n placeholder: 'Type LaTeX or chemical formula...',\r\n showPreview: true,\r\n showToolbar: true,\r\n rows: 3,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n 'update:value': [value: string];\r\n 'change': [value: string];\r\n 'error': [error: Error];\r\n}>();\r\n\r\n// ==========================================================================\r\n// State\r\n// ==========================================================================\r\n\r\nconst textareaRef = ref<HTMLTextAreaElement | null>(null);\r\nconst editorRef = ref<HTMLDivElement | null>(null);\r\nconst dropdownPosition = ref({ top: 0, left: 0 });\r\n\r\n// Auto-select the inner value (model or prop)\r\nconst localValue = ref(props.value);\r\nwatch(() => props.value, (v) => { localValue.value = v; });\r\n\r\n// Editor core\r\nconst editor = useFormulaEditor({ initialValue: localValue.value });\r\n\r\n// AI Pipeline (injected from parent)\r\nconst { pipeline } = useAIProvider();\r\n\r\n// Autocomplete\r\nconst autocomplete = useAutocomplete({\r\n config: props.autocomplete,\r\n pipeline: pipeline,\r\n});\r\n\r\n// ==========================================================================\r\n// Handlers\r\n// ==========================================================================\r\n\r\nfunction handleInput(e: Event): void {\r\n const target = e.target as HTMLTextAreaElement;\r\n const newValue = target.value;\r\n const cursorPos = target.selectionStart;\r\n\r\n localValue.value = newValue;\r\n editor.value.value = newValue;\r\n editor.cursor.value = cursorPos;\r\n\r\n emit('update:value', newValue);\r\n emit('change', newValue);\r\n\r\n // Trigger autocomplete\r\n autocomplete.trigger(newValue, cursorPos);\r\n\r\n // Update dropdown position\r\n updateDropdownPosition();\r\n}\r\n\r\nfunction handleKeydown(e: KeyboardEvent): void {\r\n if (autocomplete.visible.value) {\r\n if (e.key === 'ArrowDown') {\r\n e.preventDefault();\r\n autocomplete.moveSelection('down');\r\n return;\r\n }\r\n if (e.key === 'ArrowUp') {\r\n e.preventDefault();\r\n autocomplete.moveSelection('up');\r\n return;\r\n }\r\n if (e.key === 'Enter' || e.key === 'Tab') {\r\n e.preventDefault();\r\n const selected = autocomplete.suggestions.value[autocomplete.selectedIndex.value];\r\n if (selected) {\r\n insertCompletion(selected.text);\r\n }\r\n return;\r\n }\r\n if (e.key === 'Escape') {\r\n autocomplete.close();\r\n return;\r\n }\r\n }\r\n\r\n // Built-in shortcuts\r\n if (e.ctrlKey || e.metaKey) {\r\n if (e.key === 'b') {\r\n e.preventDefault();\r\n wrapSelection('\\\\mathbf{', '}');\r\n }\r\n if (e.key === '/') {\r\n e.preventDefault();\r\n insertText('\\\\frac{}{}');\r\n }\r\n }\r\n}\r\n\r\nfunction handleToolbarInsert(latex: string): void {\r\n insertText(latex);\r\n}\r\n\r\nfunction handleAutocompleteSelect(item: any): void {\r\n insertCompletion(item.text);\r\n}\r\n\r\nfunction insertText(text: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const start = ta.selectionStart;\r\n const end = ta.selectionEnd;\r\n const before = localValue.value.slice(0, start);\r\n const after = localValue.value.slice(end);\r\n\r\n localValue.value = before + text + after;\r\n emit('update:value', localValue.value);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = start + text.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n autocomplete.close();\r\n });\r\n}\r\n\r\nfunction insertCompletion(text: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const cursor = ta.selectionStart;\r\n const before = localValue.value.slice(0, cursor);\r\n\r\n // Find the token start to replace\r\n const backslashIdx = before.lastIndexOf('\\\\');\r\n let replaceStart: number;\r\n if (backslashIdx !== -1 && cursor - backslashIdx < 30) {\r\n replaceStart = backslashIdx;\r\n } else {\r\n const wordMatch = before.match(/([a-zA-Z_]+)$/);\r\n replaceStart = wordMatch ? cursor - wordMatch[0].length : cursor;\r\n }\r\n\r\n const after = localValue.value.slice(cursor);\r\n localValue.value = localValue.value.slice(0, replaceStart) + text + after;\r\n emit('update:value', localValue.value);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = replaceStart + text.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n autocomplete.close();\r\n });\r\n}\r\n\r\nfunction wrapSelection(before: string, after: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const start = ta.selectionStart;\r\n const end = ta.selectionEnd;\r\n const selected = localValue.value.slice(start, end) || '';\r\n\r\n const newValue = localValue.value.slice(0, start) + before + selected + after + localValue.value.slice(end);\r\n localValue.value = newValue;\r\n emit('update:value', newValue);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = start + before.length + selected.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n });\r\n}\r\n\r\nfunction updateDropdownPosition(): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const rect = ta.getBoundingClientRect();\r\n const cursorPos = ta.selectionStart;\r\n\r\n // Rough estimation of cursor position\r\n const lineHeight = 20;\r\n const charWidth = 8;\r\n const textBeforeCursor = localValue.value.slice(0, cursorPos);\r\n const lines = textBeforeCursor.split('\\n');\r\n const lastLineLen = lines[lines.length - 1]!.length;\r\n\r\n dropdownPosition.value = {\r\n top: rect.top + lines.length * lineHeight + 24 + window.scrollY,\r\n left: rect.left + lastLineLen * charWidth + window.scrollX,\r\n };\r\n}\r\n\r\n// ==========================================================================\r\n// Computed\r\n// ==========================================================================\r\n\r\nconst hasContent = computed(() => localValue.value.trim().length > 0);\r\n</script>\r\n\r\n<template>\r\n <div ref=\"editorRef\" :class=\"['sciexpr-editor', { 'sciexpr-editor-display': displayMode }]\">\r\n <!-- Toolbar -->\r\n <Toolbar\r\n v-if=\"showToolbar && !readonly\"\r\n :categories=\"toolbar?.categories\"\r\n @insert=\"handleToolbarInsert\"\r\n />\r\n\r\n <!-- Input Area -->\r\n <div class=\"sciexpr-editor-input-wrap\">\r\n <textarea\r\n ref=\"textareaRef\"\r\n v-model=\"localValue\"\r\n :class=\"['sciexpr-editor-textarea', {\r\n 'sciexpr-editor-textarea-display': displayMode,\r\n 'sciexpr-editor-textarea-readonly': readonly,\r\n }]\"\r\n :placeholder=\"placeholder\"\r\n :readonly=\"readonly\"\r\n :rows=\"rows\"\r\n :aria-label=\"'Formula input'\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\"\r\n @input=\"handleInput\"\r\n @keydown=\"handleKeydown\"\r\n @focus=\"updateDropdownPosition\"\r\n />\r\n </div>\r\n\r\n <!-- Autocomplete Dropdown -->\r\n <AutocompleteDropdown\r\n :items=\"autocomplete.suggestions.value\"\r\n :visible=\"autocomplete.visible.value\"\r\n :selected-index=\"autocomplete.selectedIndex.value\"\r\n :position=\"dropdownPosition\"\r\n @select=\"handleAutocompleteSelect\"\r\n @close=\"autocomplete.close()\"\r\n />\r\n\r\n <!-- Live Preview -->\r\n <LivePreview\r\n v-if=\"showPreview\"\r\n :source=\"localValue\"\r\n :display-mode=\"displayMode\"\r\n :show-source=\"false\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-editor {\r\n display: flex;\r\n flex-direction: column;\r\n border-radius: 8px;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n}\r\n\r\n.sciexpr-editor-input-wrap {\r\n position: relative;\r\n}\r\n\r\n.sciexpr-editor-textarea {\r\n width: 100%;\r\n padding: 12px;\r\n border: 1px solid #dee2e6;\r\n border-top: none;\r\n font-family: 'Courier New', 'Consolas', monospace;\r\n font-size: 0.95em;\r\n line-height: 1.6;\r\n resize: vertical;\r\n outline: none;\r\n box-sizing: border-box;\r\n transition: border-color 0.15s ease;\r\n min-height: 60px;\r\n}\r\n\r\n.sciexpr-editor-textarea:focus {\r\n border-color: #86b7fe;\r\n box-shadow: inset 0 0 0 2px rgba(13, 110, 253, 0.1);\r\n}\r\n\r\n.sciexpr-editor-textarea-display {\r\n font-size: 1.05em;\r\n text-align: center;\r\n}\r\n\r\n.sciexpr-editor-textarea-readonly {\r\n background: #f8f9fa;\r\n cursor: default;\r\n}\r\n\r\n.sciexpr-editor-display .sciexpr-editor-textarea {\r\n border-radius: 0;\r\n}\r\n\r\n.sciexpr-editor :deep(.sciexpr-toolbar) {\r\n border-radius: 8px 8px 0 0;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue';\r\n\r\n/**\r\n * SymbolPanel — 符号选择面板\r\n *\r\n * 提供分类浏览的数学/化学符号库,点击即可插入。\r\n *\r\n * @example\r\n * ```vue\r\n * <SymbolPanel @insert=\"(latex) => editor.insertText(latex)\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n disabled?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n/** 符号分类 */\r\ninterface SymbolGroup {\r\n id: string;\r\n label: string;\r\n symbols: { latex: string; unicode: string; name: string }[];\r\n}\r\n\r\nconst symbolGroups: SymbolGroup[] = [\r\n {\r\n id: 'greek-lower', label: 'Greek Lowercase',\r\n symbols: [\r\n { latex: '\\\\alpha', unicode: 'α', name: 'alpha' },\r\n { latex: '\\\\beta', unicode: 'β', name: 'beta' },\r\n { latex: '\\\\gamma', unicode: 'γ', name: 'gamma' },\r\n { latex: '\\\\delta', unicode: 'δ', name: 'delta' },\r\n { latex: '\\\\epsilon', unicode: 'ε', name: 'epsilon' },\r\n { latex: '\\\\zeta', unicode: 'ζ', name: 'zeta' },\r\n { latex: '\\\\eta', unicode: 'η', name: 'eta' },\r\n { latex: '\\\\theta', unicode: 'θ', name: 'theta' },\r\n { latex: '\\\\iota', unicode: 'ι', name: 'iota' },\r\n { latex: '\\\\kappa', unicode: 'κ', name: 'kappa' },\r\n { latex: '\\\\lambda', unicode: 'λ', name: 'lambda' },\r\n { latex: '\\\\mu', unicode: 'μ', name: 'mu' },\r\n { latex: '\\\\nu', unicode: 'ν', name: 'nu' },\r\n { latex: '\\\\xi', unicode: 'ξ', name: 'xi' },\r\n { latex: '\\\\pi', unicode: 'π', name: 'pi' },\r\n { latex: '\\\\rho', unicode: 'ρ', name: 'rho' },\r\n { latex: '\\\\sigma', unicode: 'σ', name: 'sigma' },\r\n { latex: '\\\\tau', unicode: 'τ', name: 'tau' },\r\n { latex: '\\\\phi', unicode: 'φ', name: 'phi' },\r\n { latex: '\\\\chi', unicode: 'χ', name: 'chi' },\r\n { latex: '\\\\psi', unicode: 'ψ', name: 'psi' },\r\n { latex: '\\\\omega', unicode: 'ω', name: 'omega' },\r\n ],\r\n },\r\n {\r\n id: 'greek-upper', label: 'Greek Uppercase',\r\n symbols: [\r\n { latex: '\\\\Gamma', unicode: 'Γ', name: 'Gamma' },\r\n { latex: '\\\\Delta', unicode: 'Δ', name: 'Delta' },\r\n { latex: '\\\\Theta', unicode: 'Θ', name: 'Theta' },\r\n { latex: '\\\\Lambda', unicode: 'Λ', name: 'Lambda' },\r\n { latex: '\\\\Xi', unicode: 'Ξ', name: 'Xi' },\r\n { latex: '\\\\Pi', unicode: 'Π', name: 'Pi' },\r\n { latex: '\\\\Sigma', unicode: 'Σ', name: 'Sigma' },\r\n { latex: '\\\\Upsilon', unicode: 'Υ', name: 'Upsilon' },\r\n { latex: '\\\\Phi', unicode: 'Φ', name: 'Phi' },\r\n { latex: '\\\\Psi', unicode: 'Ψ', name: 'Psi' },\r\n { latex: '\\\\Omega', unicode: 'Ω', name: 'Omega' },\r\n ],\r\n },\r\n {\r\n id: 'operators', label: 'Operators & Relations',\r\n symbols: [\r\n { latex: '\\\\times', unicode: '×', name: 'times' },\r\n { latex: '\\\\div', unicode: '÷', name: 'divide' },\r\n { latex: '\\\\cdot', unicode: '·', name: 'dot' },\r\n { latex: '\\\\pm', unicode: '±', name: 'plus-minus' },\r\n { latex: '\\\\mp', unicode: '∓', name: 'minus-plus' },\r\n { latex: '\\\\leq', unicode: '≤', name: 'leq' },\r\n { latex: '\\\\geq', unicode: '≥', name: 'geq' },\r\n { latex: '\\\\neq', unicode: '≠', name: 'neq' },\r\n { latex: '\\\\approx', unicode: '≈', name: 'approx' },\r\n { latex: '\\\\equiv', unicode: '≡', name: 'equiv' },\r\n { latex: '\\\\sim', unicode: '∼', name: 'sim' },\r\n { latex: '\\\\propto', unicode: '∝', name: 'propto' },\r\n { latex: '\\\\ll', unicode: '≪', name: 'll' },\r\n { latex: '\\\\gg', unicode: '≫', name: 'gg' },\r\n ],\r\n },\r\n {\r\n id: 'arrows', label: 'Arrows',\r\n symbols: [\r\n { latex: '\\\\to', unicode: '→', name: 'to' },\r\n { latex: '\\\\rightarrow', unicode: '→', name: 'rightarrow' },\r\n { latex: '\\\\leftarrow', unicode: '←', name: 'leftarrow' },\r\n { latex: '\\\\Rightarrow', unicode: '⇒', name: 'Rightarrow' },\r\n { latex: '\\\\Leftarrow', unicode: '⇐', name: 'Leftarrow' },\r\n { latex: '\\\\Leftrightarrow', unicode: '⇔', name: 'Leftrightarrow' },\r\n { latex: '\\\\mapsto', unicode: '↦', name: 'mapsto' },\r\n { latex: '\\\\uparrow', unicode: '↑', name: 'uparrow' },\r\n { latex: '\\\\downarrow', unicode: '↓', name: 'downarrow' },\r\n ],\r\n },\r\n {\r\n id: 'misc', label: 'Misc',\r\n symbols: [\r\n { latex: '\\\\infty', unicode: '∞', name: 'infinity' },\r\n { latex: '\\\\partial', unicode: '∂', name: 'partial' },\r\n { latex: '\\\\nabla', unicode: '∇', name: 'nabla' },\r\n { latex: '\\\\forall', unicode: '∀', name: 'forall' },\r\n { latex: '\\\\exists', unicode: '∃', name: 'exists' },\r\n { latex: '\\\\emptyset', unicode: '∅', name: 'emptyset' },\r\n { latex: '\\\\neg', unicode: '¬', name: 'neg' },\r\n { latex: '\\\\angle', unicode: '∠', name: 'angle' },\r\n { latex: '\\\\triangle', unicode: '△', name: 'triangle' },\r\n { latex: '\\\\square', unicode: '□', name: 'square' },\r\n { latex: '\\\\circ', unicode: '∘', name: 'circle' },\r\n { latex: '\\\\star', unicode: '★', name: 'star' },\r\n ],\r\n },\r\n {\r\n id: 'chemistry', label: 'Chemistry',\r\n symbols: [\r\n { latex: '\\\\ce{H2O}', unicode: 'H₂O', name: 'Water' },\r\n { latex: '\\\\ce{CO2}', unicode: 'CO₂', name: 'Carbon dioxide' },\r\n { latex: '\\\\ce{->}', unicode: '→', name: 'Arrow right' },\r\n { latex: '\\\\ce{<-}', unicode: '←', name: 'Arrow left' },\r\n { latex: '\\\\ce{<=>}', unicode: '⇌', name: 'Equilibrium' },\r\n { latex: '\\\\ce{<->}', unicode: '⇄', name: 'Resonance' },\r\n { latex: '\\\\ce{->[H2O]}', unicode: '→[H₂O]', name: 'With condition' },\r\n ],\r\n },\r\n];\r\n\r\nconst activeTab = ref(symbolGroups[0]!.id);\r\nconst searchQuery = ref('');\r\n\r\nconst filteredGroups = computed(() => {\r\n if (!searchQuery.value) return symbolGroups;\r\n const q = searchQuery.value.toLowerCase();\r\n return symbolGroups\r\n .map(g => ({\r\n ...g,\r\n symbols: g.symbols.filter(\r\n s => s.name.toLowerCase().includes(q) || s.latex.toLowerCase().includes(q)\r\n ),\r\n }))\r\n .filter(g => g.symbols.length > 0);\r\n});\r\n\r\nfunction insertSymbol(latex: string): void {\r\n emit('insert', latex);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"sciexpr-symbol-panel\">\r\n <div class=\"sciexpr-symbol-search\">\r\n <input\r\n v-model=\"searchQuery\"\r\n type=\"text\"\r\n class=\"sciexpr-symbol-search-input\"\r\n placeholder=\"Search symbols...\"\r\n />\r\n </div>\r\n\r\n <div class=\"sciexpr-symbol-tabs\">\r\n <button\r\n v-for=\"group in symbolGroups\"\r\n :key=\"group.id\"\r\n :class=\"['sciexpr-symbol-tab', { active: activeTab === group.id }]\"\r\n @click=\"activeTab = group.id\"\r\n type=\"button\"\r\n >\r\n {{ group.label }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"sciexpr-symbol-grid\">\r\n <template v-if=\"searchQuery\">\r\n <template v-for=\"group in filteredGroups\" :key=\"group.id\">\r\n <button\r\n v-for=\"sym in group.symbols\"\r\n :key=\"sym.latex\"\r\n :class=\"['sciexpr-symbol-btn', { 'sciexpr-symbol-btn-disabled': disabled }]\"\r\n :title=\"`${sym.name} — ${sym.latex}`\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertSymbol(sym.latex)\"\r\n >\r\n <span class=\"sciexpr-symbol-unicode\">{{ sym.unicode }}</span>\r\n <span class=\"sciexpr-symbol-name\">{{ sym.name }}</span>\r\n </button>\r\n </template>\r\n </template>\r\n <template v-else>\r\n <template v-for=\"group in symbolGroups\" :key=\"group.id\">\r\n <template v-if=\"activeTab === group.id\">\r\n <button\r\n v-for=\"sym in group.symbols\"\r\n :key=\"sym.latex\"\r\n :class=\"['sciexpr-symbol-btn', { 'sciexpr-symbol-btn-disabled': disabled }]\"\r\n :title=\"`${sym.name} — ${sym.latex}`\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertSymbol(sym.latex)\"\r\n >\r\n <span class=\"sciexpr-symbol-unicode\">{{ sym.unicode }}</span>\r\n <span class=\"sciexpr-symbol-name\">{{ sym.name }}</span>\r\n </button>\r\n </template>\r\n </template>\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-symbol-panel {\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n background: #fff;\r\n overflow: hidden;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-symbol-search {\r\n padding: 8px;\r\n border-bottom: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-symbol-search-input {\r\n width: 100%;\r\n padding: 6px 10px;\r\n border: 1px solid #ced4da;\r\n border-radius: 6px;\r\n font-size: 0.85em;\r\n outline: none;\r\n box-sizing: border-box;\r\n}\r\n\r\n.sciexpr-symbol-search-input:focus {\r\n border-color: #86b7fe;\r\n box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15);\r\n}\r\n\r\n.sciexpr-symbol-tabs {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 0;\r\n border-bottom: 1px solid #dee2e6;\r\n background: #f8f9fa;\r\n}\r\n\r\n.sciexpr-symbol-tab {\r\n padding: 6px 10px;\r\n border: none;\r\n background: none;\r\n font-size: 0.78em;\r\n color: #6c757d;\r\n cursor: pointer;\r\n border-bottom: 2px solid transparent;\r\n transition: all 0.15s ease;\r\n}\r\n\r\n.sciexpr-symbol-tab:hover {\r\n color: #212529;\r\n background: #e9ecef;\r\n}\r\n\r\n.sciexpr-symbol-tab.active {\r\n color: #0d6efd;\r\n border-bottom-color: #0d6efd;\r\n font-weight: 500;\r\n}\r\n\r\n.sciexpr-symbol-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));\r\n gap: 4px;\r\n padding: 8px;\r\n max-height: 280px;\r\n overflow-y: auto;\r\n}\r\n\r\n.sciexpr-symbol-btn {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 6px 4px;\r\n border: 1px solid transparent;\r\n border-radius: 6px;\r\n background: #f8f9fa;\r\n cursor: pointer;\r\n transition: all 0.12s ease;\r\n}\r\n\r\n.sciexpr-symbol-btn:hover:not(:disabled) {\r\n background: #e7f1ff;\r\n border-color: #b6d4fe;\r\n}\r\n\r\n.sciexpr-symbol-btn:active:not(:disabled) {\r\n background: #cfe2ff;\r\n}\r\n\r\n.sciexpr-symbol-btn-disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-symbol-unicode {\r\n font-size: 1.3em;\r\n line-height: 1.2;\r\n}\r\n\r\n.sciexpr-symbol-name {\r\n font-size: 0.65em;\r\n color: #6c757d;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 100%;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue';\r\n\r\n/**\r\n * ElementTable — 交互式化学元素周期表\r\n *\r\n * 点击元素即可插入其 LaTeX 表示。\r\n *\r\n * @example\r\n * ```vue\r\n * <ElementTable @insert=\"(latex) => editor.insertText(latex)\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n disabled?: boolean;\r\n compact?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n// ==========================================================================\r\n// Element grid layout (simplified periodic table)\r\n// ==========================================================================\r\n\r\ninterface ElementCell {\r\n symbol: string;\r\n name: string;\r\n atomicNumber: number;\r\n row: number;\r\n col: number;\r\n block: 's' | 'p' | 'd' | 'f';\r\n}\r\n\r\nconst ELEMENTS: ElementCell[] = [\r\n // Row 1\r\n { symbol: 'H', name: 'Hydrogen', atomicNumber: 1, row: 1, col: 1, block: 's' },\r\n { symbol: 'He', name: 'Helium', atomicNumber: 2, row: 1, col: 18, block: 's' },\r\n // Row 2\r\n { symbol: 'Li', name: 'Lithium', atomicNumber: 3, row: 2, col: 1, block: 's' },\r\n { symbol: 'Be', name: 'Beryllium', atomicNumber: 4, row: 2, col: 2, block: 's' },\r\n { symbol: 'B', name: 'Boron', atomicNumber: 5, row: 2, col: 13, block: 'p' },\r\n { symbol: 'C', name: 'Carbon', atomicNumber: 6, row: 2, col: 14, block: 'p' },\r\n { symbol: 'N', name: 'Nitrogen', atomicNumber: 7, row: 2, col: 15, block: 'p' },\r\n { symbol: 'O', name: 'Oxygen', atomicNumber: 8, row: 2, col: 16, block: 'p' },\r\n { symbol: 'F', name: 'Fluorine', atomicNumber: 9, row: 2, col: 17, block: 'p' },\r\n { symbol: 'Ne', name: 'Neon', atomicNumber: 10, row: 2, col: 18, block: 'p' },\r\n // Row 3\r\n { symbol: 'Na', name: 'Sodium', atomicNumber: 11, row: 3, col: 1, block: 's' },\r\n { symbol: 'Mg', name: 'Magnesium', atomicNumber: 12, row: 3, col: 2, block: 's' },\r\n { symbol: 'Al', name: 'Aluminium', atomicNumber: 13, row: 3, col: 13, block: 'p' },\r\n { symbol: 'Si', name: 'Silicon', atomicNumber: 14, row: 3, col: 14, block: 'p' },\r\n { symbol: 'P', name: 'Phosphorus', atomicNumber: 15, row: 3, col: 15, block: 'p' },\r\n { symbol: 'S', name: 'Sulfur', atomicNumber: 16, row: 3, col: 16, block: 'p' },\r\n { symbol: 'Cl', name: 'Chlorine', atomicNumber: 17, row: 3, col: 17, block: 'p' },\r\n { symbol: 'Ar', name: 'Argon', atomicNumber: 18, row: 3, col: 18, block: 'p' },\r\n // Row 4\r\n { symbol: 'K', name: 'Potassium', atomicNumber: 19, row: 4, col: 1, block: 's' },\r\n { symbol: 'Ca', name: 'Calcium', atomicNumber: 20, row: 4, col: 2, block: 's' },\r\n // Transition metals (simplified)\r\n { symbol: 'Cr', name: 'Chromium', atomicNumber: 24, row: 4, col: 6, block: 'd' },\r\n { symbol: 'Mn', name: 'Manganese', atomicNumber: 25, row: 4, col: 7, block: 'd' },\r\n { symbol: 'Fe', name: 'Iron', atomicNumber: 26, row: 4, col: 8, block: 'd' },\r\n { symbol: 'Co', name: 'Cobalt', atomicNumber: 27, row: 4, col: 9, block: 'd' },\r\n { symbol: 'Ni', name: 'Nickel', atomicNumber: 28, row: 4, col: 10, block: 'd' },\r\n { symbol: 'Cu', name: 'Copper', atomicNumber: 29, row: 4, col: 11, block: 'd' },\r\n { symbol: 'Zn', name: 'Zinc', atomicNumber: 30, row: 4, col: 12, block: 'd' },\r\n // P-block continued\r\n { symbol: 'Br', name: 'Bromine', atomicNumber: 35, row: 4, col: 17, block: 'p' },\r\n // Row 5\r\n { symbol: 'Ag', name: 'Silver', atomicNumber: 47, row: 5, col: 11, block: 'd' },\r\n { symbol: 'Au', name: 'Gold', atomicNumber: 79, row: 5, col: 11, block: 'd' },\r\n { symbol: 'Hg', name: 'Mercury', atomicNumber: 80, row: 5, col: 12, block: 'd' },\r\n { symbol: 'I', name: 'Iodine', atomicNumber: 53, row: 5, col: 17, block: 'p' },\r\n // Row 6\r\n { symbol: 'Pt', name: 'Platinum', atomicNumber: 78, row: 6, col: 10, block: 'd' },\r\n { symbol: 'Pb', name: 'Lead', atomicNumber: 82, row: 6, col: 14, block: 'p' },\r\n];\r\n\r\nconst GRID_COLS = 18;\r\nconst GRID_ROWS = 6;\r\n\r\nconst grid = computed<(ElementCell | null)[][]>(() => {\r\n const result: (ElementCell | null)[][] = [];\r\n for (let r = 0; r < GRID_ROWS; r++) {\r\n result.push(new Array(GRID_COLS).fill(null));\r\n }\r\n for (const el of ELEMENTS) {\r\n result[el.row - 1]![el.col - 1] = el;\r\n }\r\n return result;\r\n});\r\n\r\nfunction getBlockColor(block: string): string {\r\n const map: Record<string, string> = {\r\n s: '#ff6b6b',\r\n p: '#ffd93d',\r\n d: '#6bcb77',\r\n f: '#4d96ff',\r\n };\r\n return map[block] ?? '#adb5bd';\r\n}\r\n\r\nfunction selectElement(symbol: string): void {\r\n emit('insert', symbol);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-element-table', { 'sciexpr-element-table-compact': compact }]\">\r\n <div class=\"sciexpr-element-legend\">\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#ff6b6b\" /> s-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#ffd93d\" /> p-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#6bcb77\" /> d-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#4d96ff\" /> f-block</span>\r\n </div>\r\n\r\n <div class=\"sciexpr-element-grid\">\r\n <template v-for=\"row in grid\" :key=\"grid.indexOf(row)\">\r\n <button\r\n v-for=\"(cell, colIdx) in row\"\r\n :key=\"colIdx\"\r\n v-show=\"cell !== null\"\r\n :class=\"['sciexpr-element-cell', {\r\n 'sciexpr-element-cell-compact': compact,\r\n 'sciexpr-element-cell-disabled': disabled,\r\n }]\"\r\n :style=\"cell ? {\r\n gridRow: cell.row,\r\n gridColumn: cell.col,\r\n '--block-color': getBlockColor(cell.block),\r\n } : {}\"\r\n :title=\"cell ? `${cell.name} (${cell.atomicNumber})` : ''\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"cell && selectElement(cell.symbol)\"\r\n >\r\n <span v-if=\"cell\" class=\"sciexpr-element-number\">{{ cell.atomicNumber }}</span>\r\n <span v-if=\"cell\" class=\"sciexpr-element-symbol\">{{ cell.symbol }}</span>\r\n </button>\r\n <!-- Empty cells for layout -->\r\n <div\r\n v-for=\"colIdx in GRID_COLS\"\r\n :key=\"'empty-' + colIdx\"\r\n v-show=\"!row[colIdx - 1]\"\r\n class=\"sciexpr-element-cell sciexpr-element-empty\"\r\n :style=\"{ gridRow: grid.indexOf(row) + 1, gridColumn: colIdx }\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-element-table {\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n background: #fff;\r\n padding: 12px;\r\n overflow-x: auto;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-element-table-compact {\r\n padding: 6px;\r\n}\r\n\r\n.sciexpr-element-legend {\r\n display: flex;\r\n gap: 16px;\r\n margin-bottom: 10px;\r\n font-size: 0.7em;\r\n color: #6c757d;\r\n}\r\n\r\n.legend-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n}\r\n\r\n.legend-dot {\r\n display: inline-block;\r\n width: 10px;\r\n height: 10px;\r\n border-radius: 2px;\r\n}\r\n\r\n.sciexpr-element-grid {\r\n display: grid;\r\n grid-template-columns: repeat(18, 1fr);\r\n grid-template-rows: repeat(6, 1fr);\r\n gap: 3px;\r\n min-width: 540px;\r\n}\r\n\r\n.sciexpr-element-cell {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n aspect-ratio: 1;\r\n padding: 2px;\r\n border: 1px solid #dee2e6;\r\n border-radius: 4px;\r\n background: #f8f9fa;\r\n cursor: pointer;\r\n transition: all 0.12s ease;\r\n border-left: 3px solid var(--block-color, #adb5bd);\r\n min-width: 0;\r\n}\r\n\r\n.sciexpr-element-cell:hover:not(:disabled) {\r\n transform: scale(1.15);\r\n z-index: 10;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n background: #fff;\r\n}\r\n\r\n.sciexpr-element-cell-compact {\r\n padding: 1px;\r\n}\r\n\r\n.sciexpr-element-cell-disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-element-empty {\r\n border-color: transparent;\r\n background: transparent;\r\n cursor: default;\r\n pointer-events: none;\r\n}\r\n\r\n.sciexpr-element-number {\r\n font-size: 0.55em;\r\n color: #6c757d;\r\n line-height: 1;\r\n}\r\n\r\n.sciexpr-element-symbol {\r\n font-size: 0.85em;\r\n font-weight: 600;\r\n color: #212529;\r\n line-height: 1.2;\r\n}\r\n\r\n.sciexpr-element-cell-compact .sciexpr-element-symbol {\r\n font-size: 0.7em;\r\n}\r\n\r\n.sciexpr-element-cell-compact .sciexpr-element-number {\r\n font-size: 0.45em;\r\n}\r\n</style>\r\n","// @sciexpr/vue — useShortcuts Composable\r\n// ============================================================================\r\n\r\nimport { onMounted, onUnmounted } from 'vue';\r\n\r\n/** 快捷键定义 */\r\nexport interface ShortcutDef {\r\n key: string;\r\n ctrl?: boolean;\r\n meta?: boolean;\r\n shift?: boolean;\r\n alt?: boolean;\r\n action: () => void;\r\n description: string;\r\n}\r\n\r\n/**\r\n * 快捷键 composable\r\n *\r\n * 管理公式编辑器的键盘快捷键。\r\n *\r\n * @example\r\n * ```ts\r\n * useShortcuts([\r\n * { key: 'b', ctrl: true, action: () => insertText('\\\\textbf{}'), description: 'Bold' },\r\n * { key: '/', ctrl: true, action: () => insertText('\\\\frac{}{}'), description: 'Fraction' },\r\n * ]);\r\n * ```\r\n */\r\nexport function useShortcuts(shortcuts: ShortcutDef[]): void {\r\n function handleKeydown(e: KeyboardEvent): void {\r\n for (const shortcut of shortcuts) {\r\n const matchKey = e.key.toLowerCase() === shortcut.key.toLowerCase();\r\n const matchCtrl = !!shortcut.ctrl === (e.ctrlKey || e.metaKey);\r\n const matchShift = !!shortcut.shift === e.shiftKey;\r\n const matchAlt = !!shortcut.alt === e.altKey;\r\n\r\n if (matchKey && matchCtrl && matchShift && matchAlt) {\r\n e.preventDefault();\r\n shortcut.action();\r\n return;\r\n }\r\n }\r\n }\r\n\r\n onMounted(() => {\r\n window.addEventListener('keydown', handleKeydown);\r\n });\r\n\r\n onUnmounted(() => {\r\n window.removeEventListener('keydown', handleKeydown);\r\n });\r\n}\r\n\r\n/** 内置快捷键 */\r\nexport const BUILTIN_SHORTCUTS: ShortcutDef[] = [\r\n { key: 'b', ctrl: true, action: () => {}, description: 'Bold (\\\\mathbf{})' },\r\n { key: '/', ctrl: true, action: () => {}, description: 'Fraction (\\\\frac{}{})' },\r\n { key: 's', ctrl: true, shift: true, action: () => {}, description: 'Square root (\\\\sqrt{})' },\r\n { key: '1', ctrl: true, action: () => {}, description: 'Subscript (_)' },\r\n { key: '2', ctrl: true, action: () => {}, description: 'Superscript (^)' },\r\n];\r\n"],"names":["useFormulaRender","options","html","ref","mathml","unicode","error","parser","ParserRegistry","katexRenderer","KatexRenderer","unicodeRenderer","UnicodeRenderer","mathmlRenderer","MathMLRenderer","render","source","ast","htmlResult","_a","err","watch","newSource","useFormula","shallowRef","parsed","result","src","props","__props","slots","useSlots","slotContent","_c","_b","effectiveSource","_createElementBlock","_normalizeClass","_unref","_toDisplayString","_hoisted_2","useFormulaEditor","value","cursor","handleInput","newValue","newCursor","insertText","text","before","after","wrapSelection","val","parse","isEmpty","computed","latexSource","useAutocomplete","suggestions","visible","selectedIndex","query","pipeline","AIPipeline","config","trigger","input","cursorPos","token","extractToken","context","ExpressionKind","select","item","moveSelection","direction","close","backslashIdx","match","AI_PIPELINE_KEY","useAIProvider","inject","provideAI","aiConfig","p","provide","setCompletionProvider","provider","setKnowledgeBase","emit","__emit","commandCategories","insertCommand","latex","_Fragment","_renderList","cat","_hoisted_1","_openBlock","cmd","$event","_renderSlot","_ctx","_createTextVNode","sourceRef","displayRef","v","_cache","_createElementVNode","_hoisted_3","_hoisted_4","_hoisted_5","selectItem","getCategoryColor","category","_createBlock","_Teleport","_normalizeStyle","index","$emit","textareaRef","editorRef","dropdownPosition","localValue","editor","autocomplete","e","target","updateDropdownPosition","handleKeydown","selected","insertCompletion","handleToolbarInsert","handleAutocompleteSelect","ta","start","end","nextTick","replaceStart","wordMatch","rect","lineHeight","charWidth","lines","lastLineLen","Toolbar","_createVNode","AutocompleteDropdown","LivePreview","symbolGroups","activeTab","searchQuery","filteredGroups","q","g","s","insertSymbol","group","sym","_hoisted_7","_hoisted_8","_hoisted_10","_hoisted_11","GRID_COLS","GRID_ROWS","ELEMENTS","grid","r","el","getBlockColor","block","selectElement","symbol","row","cell","colIdx","_vShow","useShortcuts","shortcuts","shortcut","matchKey","matchCtrl","matchShift","matchAlt","onMounted","onUnmounted","BUILTIN_SHORTCUTS"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/composables/useFormulaRender.ts","../src/components/Formula.vue","../src/composables/useFormulaEditor.ts","../src/composables/useAutocomplete.ts","../src/composables/useAIProvider.ts","../src/components/Toolbar.vue","../src/components/LivePreview.vue","../src/components/AutocompleteDropdown.vue","../src/components/FormulaEditor.vue","../src/components/SymbolPanel.vue","../src/components/ElementTable.vue","../src/composables/useShortcuts.ts"],"sourcesContent":["// @sciexpr/vue — useFormulaRender Composable\r\n// ============================================================================\r\n\r\nimport { ref, watch, onMounted, shallowRef, type Ref } from 'vue';\r\nimport type { ExpressionRoot } from '@sciexpr/core';\r\nimport {\r\n KatexRenderer,\r\n UnicodeRenderer,\r\n MathMLRenderer,\r\n LatexReverseRenderer,\r\n type RenderOptions,\r\n type RenderError,\r\n} from '@sciexpr/renderer';\r\nimport { ParserRegistry } from '@sciexpr/parser';\r\n\r\n/**\r\n * 公式渲染 composable\r\n *\r\n * 将 LaTeX 源码渲染为 HTML / MathML / Unicode。\r\n *\r\n * @example\r\n * ```ts\r\n * const { html, error, render } = useFormulaRender({\r\n * source: ref('\\\\frac{1}{2}'),\r\n * displayMode: true,\r\n * });\r\n * ```\r\n */\r\nexport function useFormulaRender(options: {\r\n source: Ref<string>;\r\n displayMode?: boolean;\r\n katexRenderer?: KatexRenderer;\r\n renderOptions?: RenderOptions;\r\n}) {\r\n const html = ref('');\r\n const mathml = ref('');\r\n const unicode = ref('');\r\n const error = ref<RenderError | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n const katexRenderer = options.katexRenderer ?? new KatexRenderer();\r\n const unicodeRenderer = new UnicodeRenderer();\r\n const mathmlRenderer = new MathMLRenderer();\r\n\r\n function render(source: string): void {\r\n try {\r\n const ast = parser.parse(source, { hint: 'auto' });\r\n if (!ast || ast.children.length === 0) {\r\n html.value = '';\r\n error.value = null;\r\n return;\r\n }\r\n\r\n // Render HTML via KaTeX\r\n const htmlResult = katexRenderer.render(ast, {\r\n displayMode: options.displayMode,\r\n ...options.renderOptions,\r\n });\r\n html.value = htmlResult.value;\r\n if (htmlResult.warnings?.length) {\r\n // Non-blocking warnings — could expose via warn ref\r\n }\r\n\r\n // Render MathML\r\n mathml.value = mathmlRenderer.render(ast).value;\r\n\r\n // Render Unicode\r\n unicode.value = unicodeRenderer.render(ast).value;\r\n\r\n error.value = null;\r\n } catch (err) {\r\n error.value = {\r\n message: err instanceof Error ? err.message : String(err),\r\n };\r\n html.value = '';\r\n }\r\n }\r\n\r\n // Watch for source changes\r\n watch(options.source, (newSource) => {\r\n render(newSource);\r\n }, { immediate: true });\r\n\r\n // Re-render once KaTeX finishes async loading\r\n katexRenderer.ready.then(() => {\r\n render((options.source as Ref<string>).value);\r\n });\r\n\r\n return {\r\n html,\r\n mathml,\r\n unicode,\r\n error,\r\n render,\r\n };\r\n}\r\n\r\n/**\r\n * Formula 渲染专用\r\n * 简化版的 useFormulaRender,只返回 HTML\r\n */\r\nexport function useFormula(options: {\r\n source: Ref<string>;\r\n displayMode?: Ref<boolean>;\r\n}) {\r\n const html = ref('');\r\n const error = ref<RenderError | null>(null);\r\n const ast = shallowRef<ExpressionRoot | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n const katexRenderer = new KatexRenderer();\r\n\r\n function render(source: string): void {\r\n try {\r\n const parsed = parser.parse(source, { hint: 'auto' });\r\n ast.value = parsed;\r\n\r\n if (!parsed || parsed.children.length === 0) {\r\n html.value = '';\r\n error.value = null;\r\n return;\r\n }\r\n\r\n const result = katexRenderer.render(parsed, {\r\n displayMode: options.displayMode?.value ?? false,\r\n });\r\n html.value = result.value;\r\n error.value = null;\r\n } catch (err) {\r\n error.value = {\r\n message: err instanceof Error ? err.message : String(err),\r\n };\r\n html.value = source;\r\n }\r\n }\r\n\r\n watch([options.source, options.displayMode ?? ref(false)], ([src]) => {\r\n render(src!);\r\n }, { immediate: true });\r\n\r\n // Re-render once KaTeX finishes async loading\r\n katexRenderer.ready.then(() => {\r\n render((options.source as Ref<string>).value);\r\n });\r\n\r\n return { html, error, ast, render };\r\n}\r\n","<script setup lang=\"ts\">\r\nimport { ref, watch, useSlots, type Ref } from 'vue';\r\nimport { useFormula } from '../composables/useFormulaRender';\r\n\r\n/**\r\n * Formula — 纯公式渲染组件\r\n *\r\n * 支持三种输入方式:\r\n * 1. source prop: <Formula source=\"\\frac{1}{2}\" />\r\n * 2. default slot: <Formula>\\frac{1}{2}</Formula>\r\n * 3. ast prop (未来): <Formula :ast=\"astRoot\" />\r\n *\r\n * @example\r\n * ```vue\r\n * <Formula source=\"\\frac{x^2 + y^2}{\\sqrt{z}}\" display-mode />\r\n * <Formula>E = mc^2</Formula>\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n source?: string;\r\n displayMode?: boolean;\r\n throwOnError?: boolean;\r\n className?: string;\r\n fallbackText?: string;\r\n}>(), {\r\n source: '',\r\n displayMode: false,\r\n throwOnError: false,\r\n className: '',\r\n fallbackText: '',\r\n});\r\n\r\nconst slots = useSlots();\r\nconst slotContent = slots.default?.()?.[0]?.children as string | undefined;\r\n\r\n// Use slot content if source prop is empty\r\nconst effectiveSource = ref(props.source || slotContent || '') as Ref<string>;\r\n\r\n// Keep effectiveSource in sync when parent updates the source prop\r\nwatch(() => props.source, (newSource) => {\r\n effectiveSource.value = newSource || slotContent || '';\r\n});\r\n\r\nconst displayModeRef = ref(props.displayMode);\r\nwatch(() => props.displayMode, (val) => {\r\n displayModeRef.value = val;\r\n});\r\n\r\nconst { html, error } = useFormula({\r\n source: effectiveSource,\r\n displayMode: displayModeRef,\r\n});\r\n</script>\r\n\r\n<template>\r\n <span\r\n :class=\"['sciexpr-formula', props.className, {\r\n 'sciexpr-display': props.displayMode,\r\n 'sciexpr-error': error,\r\n }]\"\r\n :data-source=\"effectiveSource\"\r\n >\r\n <span v-if=\"error\" class=\"sciexpr-formula-error\" :title=\"error.message\">\r\n {{ fallbackText || effectiveSource }}\r\n </span>\r\n <span v-else v-html=\"html\" class=\"sciexpr-formula-content\" />\r\n </span>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-formula {\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n\r\n.sciexpr-formula.sciexpr-display {\r\n display: block;\r\n text-align: center;\r\n margin: 1em 0;\r\n}\r\n\r\n.sciexpr-formula-error {\r\n color: #d93025;\r\n font-family: 'Courier New', monospace;\r\n font-size: 0.9em;\r\n padding: 2px 6px;\r\n background: #fce8e6;\r\n border-radius: 4px;\r\n border: 1px solid #f5c6cb;\r\n}\r\n\r\n.sciexpr-formula-content :deep(.katex) {\r\n font-size: 1.1em;\r\n}\r\n\r\n.sciexpr-formula.sciexpr-display :deep(.katex) {\r\n font-size: 1.21em;\r\n}\r\n</style>\r\n","// @sciexpr/vue — useFormulaEditor Composable\r\n// ============================================================================\r\n\r\nimport { ref, watch, computed, type Ref, type ComputedRef } from 'vue';\r\nimport type { ExpressionRoot } from '@sciexpr/core';\r\nimport { ParserRegistry } from '@sciexpr/parser';\r\nimport type { RenderError, RenderOptions } from '@sciexpr/renderer';\r\nimport type { AutocompleteConfig, ToolbarConfig } from '../types';\r\n\r\n/**\r\n * 公式编辑器核心 composable\r\n *\r\n * 管理编辑器状态:值、光标位置、补全、解析、验证。\r\n *\r\n * @example\r\n * ```ts\r\n * const {\r\n * value, html, cursor, ast, error,\r\n * insertText, handleInput, getCompletions,\r\n * } = useFormulaEditor({ initialValue: '' });\r\n * ```\r\n */\r\nexport function useFormulaEditor(options: {\r\n initialValue?: string;\r\n displayMode?: boolean;\r\n autocomplete?: AutocompleteConfig;\r\n renderOptions?: RenderOptions;\r\n}) {\r\n const value = ref(options.initialValue ?? '');\r\n const cursor = ref(0);\r\n const html = ref('');\r\n const error = ref<RenderError | null>(null);\r\n const ast = ref<ExpressionRoot | null>(null);\r\n\r\n const parser = new ParserRegistry();\r\n\r\n // ==========================================================================\r\n // Input Handling\r\n // ==========================================================================\r\n\r\n function handleInput(newValue: string, newCursor?: number): void {\r\n value.value = newValue;\r\n if (newCursor !== undefined) {\r\n cursor.value = newCursor;\r\n }\r\n }\r\n\r\n /** 在光标位置插入文本 */\r\n function insertText(text: string): void {\r\n const before = value.value.slice(0, cursor.value);\r\n const after = value.value.slice(cursor.value);\r\n value.value = before + text + after;\r\n cursor.value += text.length;\r\n }\r\n\r\n /** 用 LaTeX 模板包裹选中文本 */\r\n function wrapSelection(before: string, after: string): void {\r\n const val = value.value;\r\n // For simplicity, wrap the whole current value\r\n value.value = before + val + after;\r\n cursor.value = value.value.length;\r\n }\r\n\r\n // ==========================================================================\r\n // Parsing & Validation\r\n // ==========================================================================\r\n\r\n function parse(): ExpressionRoot | null {\r\n try {\r\n const result = parser.parse(value.value, { hint: 'auto' });\r\n ast.value = result;\r\n return result;\r\n } catch {\r\n ast.value = null;\r\n return null;\r\n }\r\n }\r\n\r\n // ==========================================================================\r\n // Computed\r\n // ==========================================================================\r\n\r\n const isEmpty = computed(() => value.value.trim().length === 0);\r\n const latexSource = computed(() => value.value);\r\n\r\n return {\r\n // State\r\n value,\r\n cursor,\r\n html,\r\n ast,\r\n error,\r\n // Computed\r\n isEmpty,\r\n latexSource,\r\n // Actions\r\n handleInput,\r\n insertText,\r\n wrapSelection,\r\n parse,\r\n };\r\n}\r\n","// @sciexpr/vue — useAutocomplete Composable\r\n// ============================================================================\r\n\r\nimport { ref, type Ref } from 'vue';\r\nimport type { CompletionItem, CompletionContext } from '@sciexpr/ai';\r\nimport { AIPipeline } from '@sciexpr/ai';\r\nimport { ExpressionKind } from '@sciexpr/core';\r\nimport type { AutocompleteConfig } from '../types';\r\n\r\n/**\r\n * 自动补全 composable\r\n *\r\n * 管理公式编辑器的自动补全状态和交互。\r\n *\r\n * @example\r\n * ```ts\r\n * const { suggestions, visible, query, trigger } = useAutocomplete({\r\n * config: { enabled: true, minTriggerLength: 2 },\r\n * pipeline: aiPipeline,\r\n * });\r\n * ```\r\n */\r\nexport function useAutocomplete(options: {\r\n config?: AutocompleteConfig;\r\n pipeline?: AIPipeline | null;\r\n}) {\r\n const suggestions = ref<CompletionItem[]>([]);\r\n const visible = ref(false);\r\n const selectedIndex = ref(0);\r\n const query = ref('');\r\n\r\n const pipeline = options.pipeline ?? new AIPipeline();\r\n const config = options.config ?? { enabled: true, minTriggerLength: 2, maxItems: 10 };\r\n\r\n /** 触发补全 */\r\n async function trigger(input: string, cursorPos: number): Promise<void> {\r\n if (!config.enabled) {\r\n visible.value = false;\r\n return;\r\n }\r\n\r\n const token = extractToken(input, cursorPos);\r\n if (!token || token.length < (config.minTriggerLength ?? 2)) {\r\n visible.value = false;\r\n return;\r\n }\r\n\r\n query.value = token;\r\n\r\n const context: CompletionContext = {\r\n currentInput: input,\r\n cursorPosition: cursorPos,\r\n expressionType: ExpressionKind.Math,\r\n };\r\n\r\n const result = await pipeline.getCompletions(context);\r\n suggestions.value = result.items.slice(0, config.maxItems ?? 10);\r\n visible.value = suggestions.value.length > 0;\r\n selectedIndex.value = 0;\r\n }\r\n\r\n /** 选择补全项 */\r\n function select(item: CompletionItem): string {\r\n visible.value = false;\r\n return item.text;\r\n }\r\n\r\n /** 键盘导航 */\r\n function moveSelection(direction: 'up' | 'down'): void {\r\n if (direction === 'up') {\r\n selectedIndex.value = Math.max(0, selectedIndex.value - 1);\r\n } else {\r\n selectedIndex.value = Math.min(suggestions.value.length - 1, selectedIndex.value + 1);\r\n }\r\n }\r\n\r\n /** 关闭补全 */\r\n function close(): void {\r\n visible.value = false;\r\n suggestions.value = [];\r\n }\r\n\r\n return {\r\n suggestions,\r\n visible,\r\n selectedIndex,\r\n query,\r\n trigger,\r\n select,\r\n moveSelection,\r\n close,\r\n };\r\n}\r\n\r\n/** 提取光标前的 token */\r\nfunction extractToken(input: string, cursor: number): string {\r\n const before = input.slice(0, cursor);\r\n // Extract \\command token\r\n const backslashIdx = before.lastIndexOf('\\\\');\r\n if (backslashIdx !== -1) {\r\n const afterSlash = before.slice(backslashIdx);\r\n const match = afterSlash.match(/^\\\\[a-zA-Z]*$/);\r\n if (match) return match[0];\r\n }\r\n // Extract plain text token\r\n const match = before.match(/([a-zA-Z_]+)$/);\r\n return match ? match[1]! : '';\r\n}\r\n","// @sciexpr/vue — useAIProvider Composable\r\n// ============================================================================\r\n\r\nimport { inject, provide, type InjectionKey } from 'vue';\r\nimport type { IAICompletionProvider, IKnowledgeBaseProvider, IAINormalizerProvider, IAIFormatterProvider } from '@sciexpr/ai';\r\nimport { AIPipeline, BuiltinCompletionProvider, BuiltinKnowledgeBase, BuiltinNormalizer, BuiltinFormatter } from '@sciexpr/ai';\r\nimport type { AIPipelineConfig } from '@sciexpr/ai';\r\n\r\n/** AI Provider 注入 token */\r\nexport const AI_PIPELINE_KEY: InjectionKey<AIPipeline> = Symbol('sciexpr-ai-pipeline');\r\n\r\n/**\r\n * AI Provider 注入 composable\r\n *\r\n * 在 Vue 组件树的顶层提供 AI Provider 配置,\r\n * 所有子组件中的 FormulaEditor 自动获取 AI 能力。\r\n *\r\n * @example\r\n * ```ts\r\n * // App.vue setup\r\n * const { provideAI } = useAIProvider();\r\n * provideAI({\r\n * completionProvider: new MyOpenAIProvider(),\r\n * knowledgeBaseProvider: new MyKBProvider(),\r\n * });\r\n * ```\r\n */\r\nexport function useAIProvider(config?: AIPipelineConfig) {\r\n const pipeline = config ? new AIPipeline(config) : inject(AI_PIPELINE_KEY, null);\r\n\r\n /** 在当前组件树提供 AI Pipeline */\r\n function provideAI(aiConfig: AIPipelineConfig): void {\r\n const p = new AIPipeline(aiConfig);\r\n provide(AI_PIPELINE_KEY, p);\r\n }\r\n\r\n /** 设置补全提供者 */\r\n function setCompletionProvider(provider: IAICompletionProvider): void {\r\n if (pipeline) {\r\n // Create new pipeline with the provider\r\n provide(AI_PIPELINE_KEY, new AIPipeline({ completionProvider: provider }));\r\n }\r\n }\r\n\r\n /** 设置知识库提供者 */\r\n function setKnowledgeBase(provider: IKnowledgeBaseProvider): void {\r\n if (pipeline) {\r\n provide(AI_PIPELINE_KEY, new AIPipeline({ knowledgeBaseProvider: provider }));\r\n }\r\n }\r\n\r\n return {\r\n pipeline,\r\n provideAI,\r\n setCompletionProvider,\r\n setKnowledgeBase,\r\n };\r\n}\r\n","<script setup lang=\"ts\">\r\nimport type { Component } from 'vue';\r\n\r\n/**\r\n * Toolbar — 公式工具栏组件\r\n *\r\n * 提供常用 LaTeX 命令的快捷按钮。\r\n * 支持内置分类和自定义命令。\r\n *\r\n * @example\r\n * ```vue\r\n * <Toolbar @insert=\"(latex) => editor.insertText(latex)\" />\r\n * <Toolbar :categories=\"['fraction', 'symbol']\" @insert=\"onInsert\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n categories?: ('fraction' | 'script' | 'radical' | 'symbol' | 'matrix' | 'chemistry' | 'greek')[];\r\n disabled?: boolean;\r\n compact?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n/** 内置工具栏命令 */\r\ninterface ToolbarCategoryItem {\r\n id: string;\r\n label: string;\r\n icon?: string;\r\n commands: ToolbarCommandItem[];\r\n}\r\n\r\ninterface ToolbarCommandItem {\r\n latex: string;\r\n label: string;\r\n description: string;\r\n}\r\n\r\nconst commandCategories: ToolbarCategoryItem[] = [\r\n {\r\n id: 'fraction', label: 'Fraction & Script', icon: '📐',\r\n commands: [\r\n { latex: '\\\\frac{}{}', label: '⅟', description: 'Fraction' },\r\n { latex: '^{}', label: 'x²', description: 'Superscript' },\r\n { latex: '_{}', label: 'x₂', description: 'Subscript' },\r\n { latex: '^{}_{}', label: 'x²₁', description: 'Both scripts' },\r\n ],\r\n },\r\n {\r\n id: 'radical', label: 'Radicals', icon: '√',\r\n commands: [\r\n { latex: '\\\\sqrt{}', label: '√x', description: 'Square root' },\r\n { latex: '\\\\sqrt[3]{}', label: '∛x', description: 'Cube root' },\r\n { latex: '\\\\sqrt[n]{}', label: 'ⁿ√x', description: 'Nth root' },\r\n ],\r\n },\r\n {\r\n id: 'symbol', label: 'Operators', icon: '∑',\r\n commands: [\r\n { latex: '\\\\sum_{}^{}', label: '∑', description: 'Summation' },\r\n { latex: '\\\\prod_{}^{}', label: '∏', description: 'Product' },\r\n { latex: '\\\\int_{}^{}', label: '∫', description: 'Integral' },\r\n { latex: '\\\\lim_{x \\\\to }{}', label: 'lim', description: 'Limit' },\r\n { latex: '\\\\infty', label: '∞', description: 'Infinity' },\r\n { latex: '\\\\partial', label: '∂', description: 'Partial derivative' },\r\n ],\r\n },\r\n {\r\n id: 'greek', label: 'Greek', icon: 'α',\r\n commands: [\r\n { latex: '\\\\alpha', label: 'α', description: 'Alpha' },\r\n { latex: '\\\\beta', label: 'β', description: 'Beta' },\r\n { latex: '\\\\gamma', label: 'γ', description: 'Gamma' },\r\n { latex: '\\\\delta', label: 'δ', description: 'Delta' },\r\n { latex: '\\\\theta', label: 'θ', description: 'Theta' },\r\n { latex: '\\\\lambda', label: 'λ', description: 'Lambda' },\r\n { latex: '\\\\mu', label: 'μ', description: 'Mu' },\r\n { latex: '\\\\pi', label: 'π', description: 'Pi' },\r\n { latex: '\\\\sigma', label: 'σ', description: 'Sigma' },\r\n { latex: '\\\\phi', label: 'φ', description: 'Phi' },\r\n { latex: '\\\\omega', label: 'ω', description: 'Omega' },\r\n ],\r\n },\r\n {\r\n id: 'matrix', label: 'Matrix', icon: '▦',\r\n commands: [\r\n { latex: '\\\\begin{pmatrix} & \\\\\\\\ & \\\\end{pmatrix}', label: '( )', description: 'pmatrix' },\r\n { latex: '\\\\begin{bmatrix} & \\\\\\\\ & \\\\end{bmatrix}', label: '[ ]', description: 'bmatrix' },\r\n { latex: '\\\\begin{vmatrix} & \\\\\\\\ & \\\\end{vmatrix}', label: '| |', description: 'vmatrix' },\r\n ],\r\n },\r\n {\r\n id: 'chemistry', label: 'Chemistry', icon: '⚗',\r\n commands: [\r\n { latex: '\\\\ce{H2O}', label: 'H₂O', description: 'Water' },\r\n { latex: '\\\\ce{->}', label: '→', description: 'Reaction arrow' },\r\n { latex: '\\\\ce{<=>}', label: '⇌', description: 'Equilibrium' },\r\n { latex: '^{n+}', label: 'ⁿ⁺', description: 'Charge' },\r\n ],\r\n },\r\n];\r\n\r\nfunction insertCommand(latex: string): void {\r\n emit('insert', latex);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-toolbar', { 'sciexpr-toolbar-compact': compact }]\" role=\"toolbar\" aria-label=\"Formula toolbar\">\r\n <template v-for=\"cat in commandCategories\" :key=\"cat.id\">\r\n <div\r\n v-if=\"!categories || categories.includes(cat.id as any)\"\r\n :class=\"['sciexpr-toolbar-group', { 'sciexpr-toolbar-group-compact': compact }]\"\r\n >\r\n <span v-if=\"!compact\" class=\"sciexpr-toolbar-group-label\">\r\n {{ cat.icon }} {{ cat.label }}\r\n </span>\r\n <button\r\n v-for=\"cmd in cat.commands\"\r\n :key=\"cmd.latex\"\r\n :class=\"['sciexpr-toolbar-btn', { 'sciexpr-toolbar-btn-compact': compact }]\"\r\n :title=\"cmd.description\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertCommand(cmd.latex)\"\r\n >\r\n <slot :name=\"`btn-${cmd.label}`\" :command=\"cmd\">\r\n {{ cmd.label }}\r\n </slot>\r\n </button>\r\n </div>\r\n </template>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-toolbar {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 4px;\r\n padding: 8px;\r\n background: #f8f9fa;\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px 8px 0 0;\r\n border-bottom: none;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-toolbar-compact {\r\n padding: 4px;\r\n gap: 2px;\r\n}\r\n\r\n.sciexpr-toolbar-group {\r\n display: flex;\r\n flex-wrap: wrap;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 0 6px;\r\n border-right: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-toolbar-group:last-child {\r\n border-right: none;\r\n}\r\n\r\n.sciexpr-toolbar-group-compact {\r\n padding: 0 2px;\r\n}\r\n\r\n.sciexpr-toolbar-group-label {\r\n font-size: 0.75em;\r\n color: #6c757d;\r\n margin-right: 4px;\r\n white-space: nowrap;\r\n}\r\n\r\n.sciexpr-toolbar-btn {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n min-width: 28px;\r\n height: 28px;\r\n padding: 2px 6px;\r\n border: 1px solid #ced4da;\r\n border-radius: 4px;\r\n background: #fff;\r\n color: #212529;\r\n font-size: 0.85em;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n cursor: pointer;\r\n transition: all 0.15s ease;\r\n}\r\n\r\n.sciexpr-toolbar-btn:hover:not(:disabled) {\r\n background: #e9ecef;\r\n border-color: #adb5bd;\r\n transform: translateY(-1px);\r\n}\r\n\r\n.sciexpr-toolbar-btn:active:not(:disabled) {\r\n background: #dee2e6;\r\n transform: translateY(0);\r\n}\r\n\r\n.sciexpr-toolbar-btn:disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-toolbar-btn-compact {\r\n min-width: 24px;\r\n height: 24px;\r\n font-size: 0.75em;\r\n padding: 1px 4px;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, type Ref } from 'vue';\r\nimport { useFormula } from '../composables/useFormulaRender';\r\n\r\n/**\r\n * LivePreview — 公式实时预览组件\r\n *\r\n * 接收 LaTeX 源码,实时渲染为 HTML 预览。\r\n *\r\n * @example\r\n * ```vue\r\n * <LivePreview :source=\"latexCode\" display-mode />\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n source: string;\r\n displayMode?: boolean;\r\n showSource?: boolean;\r\n}>(), {\r\n displayMode: false,\r\n showSource: false,\r\n});\r\n\r\nconst sourceRef = ref(props.source) as Ref<string>;\r\nconst displayRef = ref(props.displayMode) as Ref<boolean>;\r\n\r\nimport { watch } from 'vue';\r\nwatch(() => props.source, (v) => { sourceRef.value = v; });\r\nwatch(() => props.displayMode, (v) => { displayRef.value = v; });\r\n\r\nconst { html, error } = useFormula({\r\n source: sourceRef,\r\n displayMode: displayRef,\r\n});\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-preview', { 'sciexpr-preview-display': displayMode }]\">\r\n <div v-if=\"error\" class=\"sciexpr-preview-error\">\r\n <span class=\"sciexpr-preview-error-icon\">⚠</span>\r\n <span>{{ error.message }}</span>\r\n </div>\r\n <div v-else-if=\"html\" class=\"sciexpr-preview-render\">\r\n <span v-html=\"html\" />\r\n </div>\r\n <div v-else class=\"sciexpr-preview-empty\">\r\n <span class=\"sciexpr-preview-empty-text\">Preview</span>\r\n </div>\r\n\r\n <div v-if=\"showSource && source\" class=\"sciexpr-preview-source\">\r\n <code>{{ source }}</code>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-preview {\r\n border: 1px solid #dee2e6;\r\n border-radius: 0 0 8px 8px;\r\n min-height: 60px;\r\n padding: 16px;\r\n background: #fff;\r\n display: flex;\r\n align-items: center;\r\n justify-content: center;\r\n}\r\n\r\n.sciexpr-preview-display {\r\n min-height: 80px;\r\n}\r\n\r\n.sciexpr-preview-error {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n color: #d93025;\r\n font-size: 0.85em;\r\n font-family: 'Courier New', monospace;\r\n}\r\n\r\n.sciexpr-preview-error-icon {\r\n font-size: 1.2em;\r\n}\r\n\r\n.sciexpr-preview-render {\r\n overflow-x: auto;\r\n max-width: 100%;\r\n}\r\n\r\n.sciexpr-preview-empty {\r\n color: #adb5bd;\r\n font-size: 0.9em;\r\n font-style: italic;\r\n}\r\n\r\n.sciexpr-preview-source {\r\n margin-top: 8px;\r\n padding: 6px 10px;\r\n background: #f8f9fa;\r\n border-radius: 4px;\r\n font-size: 0.8em;\r\n font-family: 'Courier New', monospace;\r\n color: #6c757d;\r\n border-top: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-preview :deep(.katex) {\r\n font-size: 1.1em;\r\n}\r\n\r\n.sciexpr-preview-display :deep(.katex) {\r\n font-size: 1.21em;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { inject, type Ref } from 'vue';\r\nimport type { CompletionItem } from '@sciexpr/ai';\r\nimport { AI_PIPELINE_KEY } from '../composables/useAIProvider';\r\n\r\n/**\r\n * AutocompleteDropdown — 自动补全下拉组件\r\n *\r\n * 显示公式编辑器的补全候选项列表,支持键盘导航。\r\n *\r\n * @example\r\n * ```vue\r\n * <AutocompleteDropdown\r\n * :items=\"suggestions\"\r\n * :visible=\"showAutocomplete\"\r\n * :selected-index=\"selectedIdx\"\r\n * @select=\"onSelect\"\r\n * />\r\n * ```\r\n */\r\ndefineProps<{\r\n items: CompletionItem[];\r\n visible: boolean;\r\n selectedIndex: number;\r\n position?: { top: number; left: number };\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n select: [item: CompletionItem];\r\n close: [];\r\n}>();\r\n\r\nconst pipeline = inject(AI_PIPELINE_KEY, null);\r\n\r\nfunction selectItem(item: CompletionItem): void {\r\n emit('select', item);\r\n}\r\n\r\nfunction getCategoryColor(category: string): string {\r\n const map: Record<string, string> = {\r\n symbol: '#0d6efd',\r\n command: '#6f42c1',\r\n template: '#198754',\r\n correction: '#fd7e14',\r\n formula: '#d63384',\r\n };\r\n return map[category] ?? '#6c757d';\r\n}\r\n</script>\r\n\r\n<template>\r\n <Teleport to=\"body\">\r\n <div\r\n v-if=\"visible && items.length > 0\"\r\n class=\"sciexpr-autocomplete\"\r\n :style=\"position ? { top: position.top + 'px', left: position.left + 'px' } : {}\"\r\n role=\"listbox\"\r\n >\r\n <div\r\n v-for=\"(item, index) in items\"\r\n :key=\"`${item.text}-${index}`\"\r\n :class=\"['sciexpr-autocomplete-item', { selected: index === selectedIndex }]\"\r\n role=\"option\"\r\n :aria-selected=\"index === selectedIndex\"\r\n @click=\"selectItem(item)\"\r\n @mouseenter=\"$emit('select', item)\"\r\n >\r\n <span\r\n class=\"sciexpr-autocomplete-category\"\r\n :style=\"{ background: getCategoryColor(item.category) }\"\r\n >\r\n {{ item.category }}\r\n </span>\r\n <span class=\"sciexpr-autocomplete-label\">{{ item.label }}</span>\r\n <span v-if=\"item.description\" class=\"sciexpr-autocomplete-desc\">\r\n {{ item.description }}\r\n </span>\r\n <span v-if=\"pipeline\" class=\"sciexpr-autocomplete-source\">\r\n {{ item.previewHtml ? 'AI' : '' }}\r\n </span>\r\n </div>\r\n </div>\r\n </Teleport>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-autocomplete {\r\n position: fixed;\r\n z-index: 10000;\r\n min-width: 220px;\r\n max-width: 360px;\r\n max-height: 240px;\r\n overflow-y: auto;\r\n background: #fff;\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);\r\n padding: 4px;\r\n}\r\n\r\n.sciexpr-autocomplete-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 8px;\r\n padding: 6px 10px;\r\n border-radius: 6px;\r\n cursor: pointer;\r\n font-size: 0.85em;\r\n transition: background 0.1s ease;\r\n}\r\n\r\n.sciexpr-autocomplete-item:hover,\r\n.sciexpr-autocomplete-item.selected {\r\n background: #e7f1ff;\r\n}\r\n\r\n.sciexpr-autocomplete-category {\r\n display: inline-flex;\r\n align-items: center;\r\n justify-content: center;\r\n padding: 1px 6px;\r\n border-radius: 4px;\r\n color: #fff;\r\n font-size: 0.7em;\r\n font-weight: 500;\r\n text-transform: uppercase;\r\n white-space: nowrap;\r\n}\r\n\r\n.sciexpr-autocomplete-label {\r\n font-weight: 500;\r\n color: #212529;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n font-family: 'Courier New', monospace;\r\n font-size: 0.95em;\r\n}\r\n\r\n.sciexpr-autocomplete-desc {\r\n color: #6c757d;\r\n font-size: 0.8em;\r\n margin-left: auto;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 80px;\r\n}\r\n\r\n.sciexpr-autocomplete-source {\r\n font-size: 0.65em;\r\n color: #adb5bd;\r\n font-style: italic;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, watch, computed, nextTick, type ComponentPublicInstance } from 'vue';\r\nimport { useFormulaEditor } from '../composables/useFormulaEditor';\r\nimport { useAutocomplete } from '../composables/useAutocomplete';\r\nimport { useAIProvider } from '../composables/useAIProvider';\r\nimport Toolbar from './Toolbar.vue';\r\nimport LivePreview from './LivePreview.vue';\r\nimport AutocompleteDropdown from './AutocompleteDropdown.vue';\r\nimport type { ToolbarConfig, AutocompleteConfig } from '../types';\r\n\r\n/**\r\n * FormulaEditor — 公式编辑器核心组件\r\n *\r\n * 一个功能完整的 LaTeX / 化学式编辑器,包含:\r\n * - 工具栏快捷插入\r\n * - 实时预览\r\n * - 自动补全 (AI + 本地)\r\n * - 键盘快捷键\r\n *\r\n * @example\r\n * ```vue\r\n * <FormulaEditor v-model=\"formula\" display-mode />\r\n * <FormulaEditor :value=\"latex\" @change=\"onFormulaChange\" />\r\n * ```\r\n */\r\nconst props = withDefaults(defineProps<{\r\n value?: string;\r\n displayMode?: boolean;\r\n readonly?: boolean;\r\n placeholder?: string;\r\n toolbar?: ToolbarConfig;\r\n autocomplete?: AutocompleteConfig;\r\n showPreview?: boolean;\r\n showToolbar?: boolean;\r\n rows?: number;\r\n}>(), {\r\n value: '',\r\n displayMode: false,\r\n readonly: false,\r\n placeholder: 'Type LaTeX or chemical formula...',\r\n showPreview: true,\r\n showToolbar: true,\r\n rows: 3,\r\n});\r\n\r\nconst emit = defineEmits<{\r\n 'update:value': [value: string];\r\n 'change': [value: string];\r\n 'error': [error: Error];\r\n}>();\r\n\r\n// ==========================================================================\r\n// State\r\n// ==========================================================================\r\n\r\nconst textareaRef = ref<HTMLTextAreaElement | null>(null);\r\nconst editorRef = ref<HTMLDivElement | null>(null);\r\nconst dropdownPosition = ref({ top: 0, left: 0 });\r\n\r\n// Auto-select the inner value (model or prop)\r\nconst localValue = ref(props.value);\r\nwatch(() => props.value, (v) => { localValue.value = v; });\r\n\r\n// Editor core\r\nconst editor = useFormulaEditor({ initialValue: localValue.value });\r\n\r\n// AI Pipeline (injected from parent)\r\nconst { pipeline } = useAIProvider();\r\n\r\n// Autocomplete\r\nconst autocomplete = useAutocomplete({\r\n config: props.autocomplete,\r\n pipeline: pipeline,\r\n});\r\n\r\n// ==========================================================================\r\n// Handlers\r\n// ==========================================================================\r\n\r\nfunction handleInput(e: Event): void {\r\n const target = e.target as HTMLTextAreaElement;\r\n const newValue = target.value;\r\n const cursorPos = target.selectionStart;\r\n\r\n localValue.value = newValue;\r\n editor.value.value = newValue;\r\n editor.cursor.value = cursorPos;\r\n\r\n emit('update:value', newValue);\r\n emit('change', newValue);\r\n\r\n // Trigger autocomplete\r\n autocomplete.trigger(newValue, cursorPos);\r\n\r\n // Update dropdown position\r\n updateDropdownPosition();\r\n}\r\n\r\nfunction handleKeydown(e: KeyboardEvent): void {\r\n if (autocomplete.visible.value) {\r\n if (e.key === 'ArrowDown') {\r\n e.preventDefault();\r\n autocomplete.moveSelection('down');\r\n return;\r\n }\r\n if (e.key === 'ArrowUp') {\r\n e.preventDefault();\r\n autocomplete.moveSelection('up');\r\n return;\r\n }\r\n if (e.key === 'Enter' || e.key === 'Tab') {\r\n e.preventDefault();\r\n const selected = autocomplete.suggestions.value[autocomplete.selectedIndex.value];\r\n if (selected) {\r\n insertCompletion(selected.text);\r\n }\r\n return;\r\n }\r\n if (e.key === 'Escape') {\r\n autocomplete.close();\r\n return;\r\n }\r\n }\r\n\r\n // Built-in shortcuts\r\n if (e.ctrlKey || e.metaKey) {\r\n if (e.key === 'b') {\r\n e.preventDefault();\r\n wrapSelection('\\\\mathbf{', '}');\r\n }\r\n if (e.key === '/') {\r\n e.preventDefault();\r\n insertText('\\\\frac{}{}');\r\n }\r\n }\r\n}\r\n\r\nfunction handleToolbarInsert(latex: string): void {\r\n insertText(latex);\r\n}\r\n\r\nfunction handleAutocompleteSelect(item: any): void {\r\n insertCompletion(item.text);\r\n}\r\n\r\nfunction insertText(text: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const start = ta.selectionStart;\r\n const end = ta.selectionEnd;\r\n const before = localValue.value.slice(0, start);\r\n const after = localValue.value.slice(end);\r\n\r\n localValue.value = before + text + after;\r\n emit('update:value', localValue.value);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = start + text.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n autocomplete.close();\r\n });\r\n}\r\n\r\nfunction insertCompletion(text: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const cursor = ta.selectionStart;\r\n const before = localValue.value.slice(0, cursor);\r\n\r\n // Find the token start to replace\r\n const backslashIdx = before.lastIndexOf('\\\\');\r\n let replaceStart: number;\r\n if (backslashIdx !== -1 && cursor - backslashIdx < 30) {\r\n replaceStart = backslashIdx;\r\n } else {\r\n const wordMatch = before.match(/([a-zA-Z_]+)$/);\r\n replaceStart = wordMatch ? cursor - wordMatch[0].length : cursor;\r\n }\r\n\r\n const after = localValue.value.slice(cursor);\r\n localValue.value = localValue.value.slice(0, replaceStart) + text + after;\r\n emit('update:value', localValue.value);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = replaceStart + text.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n autocomplete.close();\r\n });\r\n}\r\n\r\nfunction wrapSelection(before: string, after: string): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const start = ta.selectionStart;\r\n const end = ta.selectionEnd;\r\n const selected = localValue.value.slice(start, end) || '';\r\n\r\n const newValue = localValue.value.slice(0, start) + before + selected + after + localValue.value.slice(end);\r\n localValue.value = newValue;\r\n emit('update:value', newValue);\r\n\r\n nextTick(() => {\r\n ta.focus();\r\n const newCursor = start + before.length + selected.length;\r\n ta.setSelectionRange(newCursor, newCursor);\r\n });\r\n}\r\n\r\nfunction updateDropdownPosition(): void {\r\n const ta = textareaRef.value;\r\n if (!ta) return;\r\n\r\n const rect = ta.getBoundingClientRect();\r\n const cursorPos = ta.selectionStart;\r\n\r\n // Rough estimation of cursor position\r\n const lineHeight = 20;\r\n const charWidth = 8;\r\n const textBeforeCursor = localValue.value.slice(0, cursorPos);\r\n const lines = textBeforeCursor.split('\\n');\r\n const lastLineLen = lines[lines.length - 1]!.length;\r\n\r\n dropdownPosition.value = {\r\n top: rect.top + lines.length * lineHeight + 24 + window.scrollY,\r\n left: rect.left + lastLineLen * charWidth + window.scrollX,\r\n };\r\n}\r\n\r\n// ==========================================================================\r\n// Computed\r\n// ==========================================================================\r\n\r\nconst hasContent = computed(() => localValue.value.trim().length > 0);\r\n</script>\r\n\r\n<template>\r\n <div ref=\"editorRef\" :class=\"['sciexpr-editor', { 'sciexpr-editor-display': displayMode }]\">\r\n <!-- Toolbar -->\r\n <Toolbar\r\n v-if=\"showToolbar && !readonly\"\r\n :categories=\"toolbar?.categories\"\r\n @insert=\"handleToolbarInsert\"\r\n />\r\n\r\n <!-- Input Area -->\r\n <div class=\"sciexpr-editor-input-wrap\">\r\n <textarea\r\n ref=\"textareaRef\"\r\n v-model=\"localValue\"\r\n :class=\"['sciexpr-editor-textarea', {\r\n 'sciexpr-editor-textarea-display': displayMode,\r\n 'sciexpr-editor-textarea-readonly': readonly,\r\n }]\"\r\n :placeholder=\"placeholder\"\r\n :readonly=\"readonly\"\r\n :rows=\"rows\"\r\n :aria-label=\"'Formula input'\"\r\n spellcheck=\"false\"\r\n autocomplete=\"off\"\r\n autocorrect=\"off\"\r\n autocapitalize=\"off\"\r\n @input=\"handleInput\"\r\n @keydown=\"handleKeydown\"\r\n @focus=\"updateDropdownPosition\"\r\n />\r\n </div>\r\n\r\n <!-- Autocomplete Dropdown -->\r\n <AutocompleteDropdown\r\n :items=\"autocomplete.suggestions.value\"\r\n :visible=\"autocomplete.visible.value\"\r\n :selected-index=\"autocomplete.selectedIndex.value\"\r\n :position=\"dropdownPosition\"\r\n @select=\"handleAutocompleteSelect\"\r\n @close=\"autocomplete.close()\"\r\n />\r\n\r\n <!-- Live Preview -->\r\n <LivePreview\r\n v-if=\"showPreview\"\r\n :source=\"localValue\"\r\n :display-mode=\"displayMode\"\r\n :show-source=\"false\"\r\n />\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-editor {\r\n display: flex;\r\n flex-direction: column;\r\n border-radius: 8px;\r\n font-family: 'Segoe UI', system-ui, sans-serif;\r\n}\r\n\r\n.sciexpr-editor-input-wrap {\r\n position: relative;\r\n}\r\n\r\n.sciexpr-editor-textarea {\r\n width: 100%;\r\n padding: 12px;\r\n border: 1px solid #dee2e6;\r\n border-top: none;\r\n font-family: 'Courier New', 'Consolas', monospace;\r\n font-size: 0.95em;\r\n line-height: 1.6;\r\n resize: vertical;\r\n outline: none;\r\n box-sizing: border-box;\r\n transition: border-color 0.15s ease;\r\n min-height: 60px;\r\n}\r\n\r\n.sciexpr-editor-textarea:focus {\r\n border-color: #86b7fe;\r\n box-shadow: inset 0 0 0 2px rgba(13, 110, 253, 0.1);\r\n}\r\n\r\n.sciexpr-editor-textarea-display {\r\n font-size: 1.05em;\r\n text-align: center;\r\n}\r\n\r\n.sciexpr-editor-textarea-readonly {\r\n background: #f8f9fa;\r\n cursor: default;\r\n}\r\n\r\n.sciexpr-editor-display .sciexpr-editor-textarea {\r\n border-radius: 0;\r\n}\r\n\r\n.sciexpr-editor :deep(.sciexpr-toolbar) {\r\n border-radius: 8px 8px 0 0;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue';\r\n\r\n/**\r\n * SymbolPanel — 符号选择面板\r\n *\r\n * 提供分类浏览的数学/化学符号库,点击即可插入。\r\n *\r\n * @example\r\n * ```vue\r\n * <SymbolPanel @insert=\"(latex) => editor.insertText(latex)\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n disabled?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n/** 符号分类 */\r\ninterface SymbolGroup {\r\n id: string;\r\n label: string;\r\n symbols: { latex: string; unicode: string; name: string }[];\r\n}\r\n\r\nconst symbolGroups: SymbolGroup[] = [\r\n {\r\n id: 'greek-lower', label: 'Greek Lowercase',\r\n symbols: [\r\n { latex: '\\\\alpha', unicode: 'α', name: 'alpha' },\r\n { latex: '\\\\beta', unicode: 'β', name: 'beta' },\r\n { latex: '\\\\gamma', unicode: 'γ', name: 'gamma' },\r\n { latex: '\\\\delta', unicode: 'δ', name: 'delta' },\r\n { latex: '\\\\epsilon', unicode: 'ε', name: 'epsilon' },\r\n { latex: '\\\\zeta', unicode: 'ζ', name: 'zeta' },\r\n { latex: '\\\\eta', unicode: 'η', name: 'eta' },\r\n { latex: '\\\\theta', unicode: 'θ', name: 'theta' },\r\n { latex: '\\\\iota', unicode: 'ι', name: 'iota' },\r\n { latex: '\\\\kappa', unicode: 'κ', name: 'kappa' },\r\n { latex: '\\\\lambda', unicode: 'λ', name: 'lambda' },\r\n { latex: '\\\\mu', unicode: 'μ', name: 'mu' },\r\n { latex: '\\\\nu', unicode: 'ν', name: 'nu' },\r\n { latex: '\\\\xi', unicode: 'ξ', name: 'xi' },\r\n { latex: '\\\\pi', unicode: 'π', name: 'pi' },\r\n { latex: '\\\\rho', unicode: 'ρ', name: 'rho' },\r\n { latex: '\\\\sigma', unicode: 'σ', name: 'sigma' },\r\n { latex: '\\\\tau', unicode: 'τ', name: 'tau' },\r\n { latex: '\\\\phi', unicode: 'φ', name: 'phi' },\r\n { latex: '\\\\chi', unicode: 'χ', name: 'chi' },\r\n { latex: '\\\\psi', unicode: 'ψ', name: 'psi' },\r\n { latex: '\\\\omega', unicode: 'ω', name: 'omega' },\r\n ],\r\n },\r\n {\r\n id: 'greek-upper', label: 'Greek Uppercase',\r\n symbols: [\r\n { latex: '\\\\Gamma', unicode: 'Γ', name: 'Gamma' },\r\n { latex: '\\\\Delta', unicode: 'Δ', name: 'Delta' },\r\n { latex: '\\\\Theta', unicode: 'Θ', name: 'Theta' },\r\n { latex: '\\\\Lambda', unicode: 'Λ', name: 'Lambda' },\r\n { latex: '\\\\Xi', unicode: 'Ξ', name: 'Xi' },\r\n { latex: '\\\\Pi', unicode: 'Π', name: 'Pi' },\r\n { latex: '\\\\Sigma', unicode: 'Σ', name: 'Sigma' },\r\n { latex: '\\\\Upsilon', unicode: 'Υ', name: 'Upsilon' },\r\n { latex: '\\\\Phi', unicode: 'Φ', name: 'Phi' },\r\n { latex: '\\\\Psi', unicode: 'Ψ', name: 'Psi' },\r\n { latex: '\\\\Omega', unicode: 'Ω', name: 'Omega' },\r\n ],\r\n },\r\n {\r\n id: 'operators', label: 'Operators & Relations',\r\n symbols: [\r\n { latex: '\\\\times', unicode: '×', name: 'times' },\r\n { latex: '\\\\div', unicode: '÷', name: 'divide' },\r\n { latex: '\\\\cdot', unicode: '·', name: 'dot' },\r\n { latex: '\\\\pm', unicode: '±', name: 'plus-minus' },\r\n { latex: '\\\\mp', unicode: '∓', name: 'minus-plus' },\r\n { latex: '\\\\leq', unicode: '≤', name: 'leq' },\r\n { latex: '\\\\geq', unicode: '≥', name: 'geq' },\r\n { latex: '\\\\neq', unicode: '≠', name: 'neq' },\r\n { latex: '\\\\approx', unicode: '≈', name: 'approx' },\r\n { latex: '\\\\equiv', unicode: '≡', name: 'equiv' },\r\n { latex: '\\\\sim', unicode: '∼', name: 'sim' },\r\n { latex: '\\\\propto', unicode: '∝', name: 'propto' },\r\n { latex: '\\\\ll', unicode: '≪', name: 'll' },\r\n { latex: '\\\\gg', unicode: '≫', name: 'gg' },\r\n ],\r\n },\r\n {\r\n id: 'arrows', label: 'Arrows',\r\n symbols: [\r\n { latex: '\\\\to', unicode: '→', name: 'to' },\r\n { latex: '\\\\rightarrow', unicode: '→', name: 'rightarrow' },\r\n { latex: '\\\\leftarrow', unicode: '←', name: 'leftarrow' },\r\n { latex: '\\\\Rightarrow', unicode: '⇒', name: 'Rightarrow' },\r\n { latex: '\\\\Leftarrow', unicode: '⇐', name: 'Leftarrow' },\r\n { latex: '\\\\Leftrightarrow', unicode: '⇔', name: 'Leftrightarrow' },\r\n { latex: '\\\\mapsto', unicode: '↦', name: 'mapsto' },\r\n { latex: '\\\\uparrow', unicode: '↑', name: 'uparrow' },\r\n { latex: '\\\\downarrow', unicode: '↓', name: 'downarrow' },\r\n ],\r\n },\r\n {\r\n id: 'misc', label: 'Misc',\r\n symbols: [\r\n { latex: '\\\\infty', unicode: '∞', name: 'infinity' },\r\n { latex: '\\\\partial', unicode: '∂', name: 'partial' },\r\n { latex: '\\\\nabla', unicode: '∇', name: 'nabla' },\r\n { latex: '\\\\forall', unicode: '∀', name: 'forall' },\r\n { latex: '\\\\exists', unicode: '∃', name: 'exists' },\r\n { latex: '\\\\emptyset', unicode: '∅', name: 'emptyset' },\r\n { latex: '\\\\neg', unicode: '¬', name: 'neg' },\r\n { latex: '\\\\angle', unicode: '∠', name: 'angle' },\r\n { latex: '\\\\triangle', unicode: '△', name: 'triangle' },\r\n { latex: '\\\\square', unicode: '□', name: 'square' },\r\n { latex: '\\\\circ', unicode: '∘', name: 'circle' },\r\n { latex: '\\\\star', unicode: '★', name: 'star' },\r\n ],\r\n },\r\n {\r\n id: 'chemistry', label: 'Chemistry',\r\n symbols: [\r\n { latex: '\\\\ce{H2O}', unicode: 'H₂O', name: 'Water' },\r\n { latex: '\\\\ce{CO2}', unicode: 'CO₂', name: 'Carbon dioxide' },\r\n { latex: '\\\\ce{->}', unicode: '→', name: 'Arrow right' },\r\n { latex: '\\\\ce{<-}', unicode: '←', name: 'Arrow left' },\r\n { latex: '\\\\ce{<=>}', unicode: '⇌', name: 'Equilibrium' },\r\n { latex: '\\\\ce{<->}', unicode: '⇄', name: 'Resonance' },\r\n { latex: '\\\\ce{->[H2O]}', unicode: '→[H₂O]', name: 'With condition' },\r\n ],\r\n },\r\n];\r\n\r\nconst activeTab = ref(symbolGroups[0]!.id);\r\nconst searchQuery = ref('');\r\n\r\nconst filteredGroups = computed(() => {\r\n if (!searchQuery.value) return symbolGroups;\r\n const q = searchQuery.value.toLowerCase();\r\n return symbolGroups\r\n .map(g => ({\r\n ...g,\r\n symbols: g.symbols.filter(\r\n s => s.name.toLowerCase().includes(q) || s.latex.toLowerCase().includes(q)\r\n ),\r\n }))\r\n .filter(g => g.symbols.length > 0);\r\n});\r\n\r\nfunction insertSymbol(latex: string): void {\r\n emit('insert', latex);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div class=\"sciexpr-symbol-panel\">\r\n <div class=\"sciexpr-symbol-search\">\r\n <input\r\n v-model=\"searchQuery\"\r\n type=\"text\"\r\n class=\"sciexpr-symbol-search-input\"\r\n placeholder=\"Search symbols...\"\r\n />\r\n </div>\r\n\r\n <div class=\"sciexpr-symbol-tabs\">\r\n <button\r\n v-for=\"group in symbolGroups\"\r\n :key=\"group.id\"\r\n :class=\"['sciexpr-symbol-tab', { active: activeTab === group.id }]\"\r\n @click=\"activeTab = group.id\"\r\n type=\"button\"\r\n >\r\n {{ group.label }}\r\n </button>\r\n </div>\r\n\r\n <div class=\"sciexpr-symbol-grid\">\r\n <template v-if=\"searchQuery\">\r\n <template v-for=\"group in filteredGroups\" :key=\"group.id\">\r\n <button\r\n v-for=\"sym in group.symbols\"\r\n :key=\"sym.latex\"\r\n :class=\"['sciexpr-symbol-btn', { 'sciexpr-symbol-btn-disabled': disabled }]\"\r\n :title=\"`${sym.name} — ${sym.latex}`\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertSymbol(sym.latex)\"\r\n >\r\n <span class=\"sciexpr-symbol-unicode\">{{ sym.unicode }}</span>\r\n <span class=\"sciexpr-symbol-name\">{{ sym.name }}</span>\r\n </button>\r\n </template>\r\n </template>\r\n <template v-else>\r\n <template v-for=\"group in symbolGroups\" :key=\"group.id\">\r\n <template v-if=\"activeTab === group.id\">\r\n <button\r\n v-for=\"sym in group.symbols\"\r\n :key=\"sym.latex\"\r\n :class=\"['sciexpr-symbol-btn', { 'sciexpr-symbol-btn-disabled': disabled }]\"\r\n :title=\"`${sym.name} — ${sym.latex}`\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"insertSymbol(sym.latex)\"\r\n >\r\n <span class=\"sciexpr-symbol-unicode\">{{ sym.unicode }}</span>\r\n <span class=\"sciexpr-symbol-name\">{{ sym.name }}</span>\r\n </button>\r\n </template>\r\n </template>\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-symbol-panel {\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n background: #fff;\r\n overflow: hidden;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-symbol-search {\r\n padding: 8px;\r\n border-bottom: 1px solid #dee2e6;\r\n}\r\n\r\n.sciexpr-symbol-search-input {\r\n width: 100%;\r\n padding: 6px 10px;\r\n border: 1px solid #ced4da;\r\n border-radius: 6px;\r\n font-size: 0.85em;\r\n outline: none;\r\n box-sizing: border-box;\r\n}\r\n\r\n.sciexpr-symbol-search-input:focus {\r\n border-color: #86b7fe;\r\n box-shadow: 0 0 0 3px rgba(13, 110, 253, 0.15);\r\n}\r\n\r\n.sciexpr-symbol-tabs {\r\n display: flex;\r\n flex-wrap: wrap;\r\n gap: 0;\r\n border-bottom: 1px solid #dee2e6;\r\n background: #f8f9fa;\r\n}\r\n\r\n.sciexpr-symbol-tab {\r\n padding: 6px 10px;\r\n border: none;\r\n background: none;\r\n font-size: 0.78em;\r\n color: #6c757d;\r\n cursor: pointer;\r\n border-bottom: 2px solid transparent;\r\n transition: all 0.15s ease;\r\n}\r\n\r\n.sciexpr-symbol-tab:hover {\r\n color: #212529;\r\n background: #e9ecef;\r\n}\r\n\r\n.sciexpr-symbol-tab.active {\r\n color: #0d6efd;\r\n border-bottom-color: #0d6efd;\r\n font-weight: 500;\r\n}\r\n\r\n.sciexpr-symbol-grid {\r\n display: grid;\r\n grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));\r\n gap: 4px;\r\n padding: 8px;\r\n max-height: 280px;\r\n overflow-y: auto;\r\n}\r\n\r\n.sciexpr-symbol-btn {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n gap: 2px;\r\n padding: 6px 4px;\r\n border: 1px solid transparent;\r\n border-radius: 6px;\r\n background: #f8f9fa;\r\n cursor: pointer;\r\n transition: all 0.12s ease;\r\n}\r\n\r\n.sciexpr-symbol-btn:hover:not(:disabled) {\r\n background: #e7f1ff;\r\n border-color: #b6d4fe;\r\n}\r\n\r\n.sciexpr-symbol-btn:active:not(:disabled) {\r\n background: #cfe2ff;\r\n}\r\n\r\n.sciexpr-symbol-btn-disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-symbol-unicode {\r\n font-size: 1.3em;\r\n line-height: 1.2;\r\n}\r\n\r\n.sciexpr-symbol-name {\r\n font-size: 0.65em;\r\n color: #6c757d;\r\n white-space: nowrap;\r\n overflow: hidden;\r\n text-overflow: ellipsis;\r\n max-width: 100%;\r\n}\r\n</style>\r\n","<script setup lang=\"ts\">\r\nimport { ref, computed } from 'vue';\r\n\r\n/**\r\n * ElementTable — 交互式化学元素周期表\r\n *\r\n * 点击元素即可插入其 LaTeX 表示。\r\n *\r\n * @example\r\n * ```vue\r\n * <ElementTable @insert=\"(latex) => editor.insertText(latex)\" />\r\n * ```\r\n */\r\ndefineProps<{\r\n disabled?: boolean;\r\n compact?: boolean;\r\n}>();\r\n\r\nconst emit = defineEmits<{\r\n insert: [latex: string];\r\n}>();\r\n\r\n// ==========================================================================\r\n// Element grid layout (simplified periodic table)\r\n// ==========================================================================\r\n\r\ninterface ElementCell {\r\n symbol: string;\r\n name: string;\r\n atomicNumber: number;\r\n row: number;\r\n col: number;\r\n block: 's' | 'p' | 'd' | 'f';\r\n}\r\n\r\nconst ELEMENTS: ElementCell[] = [\r\n // Row 1\r\n { symbol: 'H', name: 'Hydrogen', atomicNumber: 1, row: 1, col: 1, block: 's' },\r\n { symbol: 'He', name: 'Helium', atomicNumber: 2, row: 1, col: 18, block: 's' },\r\n // Row 2\r\n { symbol: 'Li', name: 'Lithium', atomicNumber: 3, row: 2, col: 1, block: 's' },\r\n { symbol: 'Be', name: 'Beryllium', atomicNumber: 4, row: 2, col: 2, block: 's' },\r\n { symbol: 'B', name: 'Boron', atomicNumber: 5, row: 2, col: 13, block: 'p' },\r\n { symbol: 'C', name: 'Carbon', atomicNumber: 6, row: 2, col: 14, block: 'p' },\r\n { symbol: 'N', name: 'Nitrogen', atomicNumber: 7, row: 2, col: 15, block: 'p' },\r\n { symbol: 'O', name: 'Oxygen', atomicNumber: 8, row: 2, col: 16, block: 'p' },\r\n { symbol: 'F', name: 'Fluorine', atomicNumber: 9, row: 2, col: 17, block: 'p' },\r\n { symbol: 'Ne', name: 'Neon', atomicNumber: 10, row: 2, col: 18, block: 'p' },\r\n // Row 3\r\n { symbol: 'Na', name: 'Sodium', atomicNumber: 11, row: 3, col: 1, block: 's' },\r\n { symbol: 'Mg', name: 'Magnesium', atomicNumber: 12, row: 3, col: 2, block: 's' },\r\n { symbol: 'Al', name: 'Aluminium', atomicNumber: 13, row: 3, col: 13, block: 'p' },\r\n { symbol: 'Si', name: 'Silicon', atomicNumber: 14, row: 3, col: 14, block: 'p' },\r\n { symbol: 'P', name: 'Phosphorus', atomicNumber: 15, row: 3, col: 15, block: 'p' },\r\n { symbol: 'S', name: 'Sulfur', atomicNumber: 16, row: 3, col: 16, block: 'p' },\r\n { symbol: 'Cl', name: 'Chlorine', atomicNumber: 17, row: 3, col: 17, block: 'p' },\r\n { symbol: 'Ar', name: 'Argon', atomicNumber: 18, row: 3, col: 18, block: 'p' },\r\n // Row 4\r\n { symbol: 'K', name: 'Potassium', atomicNumber: 19, row: 4, col: 1, block: 's' },\r\n { symbol: 'Ca', name: 'Calcium', atomicNumber: 20, row: 4, col: 2, block: 's' },\r\n // Transition metals (simplified)\r\n { symbol: 'Cr', name: 'Chromium', atomicNumber: 24, row: 4, col: 6, block: 'd' },\r\n { symbol: 'Mn', name: 'Manganese', atomicNumber: 25, row: 4, col: 7, block: 'd' },\r\n { symbol: 'Fe', name: 'Iron', atomicNumber: 26, row: 4, col: 8, block: 'd' },\r\n { symbol: 'Co', name: 'Cobalt', atomicNumber: 27, row: 4, col: 9, block: 'd' },\r\n { symbol: 'Ni', name: 'Nickel', atomicNumber: 28, row: 4, col: 10, block: 'd' },\r\n { symbol: 'Cu', name: 'Copper', atomicNumber: 29, row: 4, col: 11, block: 'd' },\r\n { symbol: 'Zn', name: 'Zinc', atomicNumber: 30, row: 4, col: 12, block: 'd' },\r\n // P-block continued\r\n { symbol: 'Br', name: 'Bromine', atomicNumber: 35, row: 4, col: 17, block: 'p' },\r\n // Row 5\r\n { symbol: 'Ag', name: 'Silver', atomicNumber: 47, row: 5, col: 11, block: 'd' },\r\n { symbol: 'Au', name: 'Gold', atomicNumber: 79, row: 5, col: 11, block: 'd' },\r\n { symbol: 'Hg', name: 'Mercury', atomicNumber: 80, row: 5, col: 12, block: 'd' },\r\n { symbol: 'I', name: 'Iodine', atomicNumber: 53, row: 5, col: 17, block: 'p' },\r\n // Row 6\r\n { symbol: 'Pt', name: 'Platinum', atomicNumber: 78, row: 6, col: 10, block: 'd' },\r\n { symbol: 'Pb', name: 'Lead', atomicNumber: 82, row: 6, col: 14, block: 'p' },\r\n];\r\n\r\nconst GRID_COLS = 18;\r\nconst GRID_ROWS = 6;\r\n\r\nconst grid = computed<(ElementCell | null)[][]>(() => {\r\n const result: (ElementCell | null)[][] = [];\r\n for (let r = 0; r < GRID_ROWS; r++) {\r\n result.push(new Array(GRID_COLS).fill(null));\r\n }\r\n for (const el of ELEMENTS) {\r\n result[el.row - 1]![el.col - 1] = el;\r\n }\r\n return result;\r\n});\r\n\r\nfunction getBlockColor(block: string): string {\r\n const map: Record<string, string> = {\r\n s: '#ff6b6b',\r\n p: '#ffd93d',\r\n d: '#6bcb77',\r\n f: '#4d96ff',\r\n };\r\n return map[block] ?? '#adb5bd';\r\n}\r\n\r\nfunction selectElement(symbol: string): void {\r\n emit('insert', symbol);\r\n}\r\n</script>\r\n\r\n<template>\r\n <div :class=\"['sciexpr-element-table', { 'sciexpr-element-table-compact': compact }]\">\r\n <div class=\"sciexpr-element-legend\">\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#ff6b6b\" /> s-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#ffd93d\" /> p-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#6bcb77\" /> d-block</span>\r\n <span class=\"legend-item\"><span class=\"legend-dot\" style=\"background:#4d96ff\" /> f-block</span>\r\n </div>\r\n\r\n <div class=\"sciexpr-element-grid\">\r\n <template v-for=\"row in grid\" :key=\"grid.indexOf(row)\">\r\n <button\r\n v-for=\"(cell, colIdx) in row\"\r\n :key=\"colIdx\"\r\n v-show=\"cell !== null\"\r\n :class=\"['sciexpr-element-cell', {\r\n 'sciexpr-element-cell-compact': compact,\r\n 'sciexpr-element-cell-disabled': disabled,\r\n }]\"\r\n :style=\"cell ? {\r\n gridRow: cell.row,\r\n gridColumn: cell.col,\r\n '--block-color': getBlockColor(cell.block),\r\n } : {}\"\r\n :title=\"cell ? `${cell.name} (${cell.atomicNumber})` : ''\"\r\n :disabled=\"disabled\"\r\n type=\"button\"\r\n @click=\"cell && selectElement(cell.symbol)\"\r\n >\r\n <span v-if=\"cell\" class=\"sciexpr-element-number\">{{ cell.atomicNumber }}</span>\r\n <span v-if=\"cell\" class=\"sciexpr-element-symbol\">{{ cell.symbol }}</span>\r\n </button>\r\n <!-- Empty cells for layout -->\r\n <div\r\n v-for=\"colIdx in GRID_COLS\"\r\n :key=\"'empty-' + colIdx\"\r\n v-show=\"!row[colIdx - 1]\"\r\n class=\"sciexpr-element-cell sciexpr-element-empty\"\r\n :style=\"{ gridRow: grid.indexOf(row) + 1, gridColumn: colIdx }\"\r\n />\r\n </template>\r\n </div>\r\n </div>\r\n</template>\r\n\r\n<style scoped>\r\n.sciexpr-element-table {\r\n border: 1px solid #dee2e6;\r\n border-radius: 8px;\r\n background: #fff;\r\n padding: 12px;\r\n overflow-x: auto;\r\n user-select: none;\r\n}\r\n\r\n.sciexpr-element-table-compact {\r\n padding: 6px;\r\n}\r\n\r\n.sciexpr-element-legend {\r\n display: flex;\r\n gap: 16px;\r\n margin-bottom: 10px;\r\n font-size: 0.7em;\r\n color: #6c757d;\r\n}\r\n\r\n.legend-item {\r\n display: flex;\r\n align-items: center;\r\n gap: 4px;\r\n}\r\n\r\n.legend-dot {\r\n display: inline-block;\r\n width: 10px;\r\n height: 10px;\r\n border-radius: 2px;\r\n}\r\n\r\n.sciexpr-element-grid {\r\n display: grid;\r\n grid-template-columns: repeat(18, 1fr);\r\n grid-template-rows: repeat(6, 1fr);\r\n gap: 3px;\r\n min-width: 540px;\r\n}\r\n\r\n.sciexpr-element-cell {\r\n display: flex;\r\n flex-direction: column;\r\n align-items: center;\r\n justify-content: center;\r\n aspect-ratio: 1;\r\n padding: 2px;\r\n border: 1px solid #dee2e6;\r\n border-radius: 4px;\r\n background: #f8f9fa;\r\n cursor: pointer;\r\n transition: all 0.12s ease;\r\n border-left: 3px solid var(--block-color, #adb5bd);\r\n min-width: 0;\r\n}\r\n\r\n.sciexpr-element-cell:hover:not(:disabled) {\r\n transform: scale(1.15);\r\n z-index: 10;\r\n box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);\r\n background: #fff;\r\n}\r\n\r\n.sciexpr-element-cell-compact {\r\n padding: 1px;\r\n}\r\n\r\n.sciexpr-element-cell-disabled {\r\n opacity: 0.4;\r\n cursor: not-allowed;\r\n}\r\n\r\n.sciexpr-element-empty {\r\n border-color: transparent;\r\n background: transparent;\r\n cursor: default;\r\n pointer-events: none;\r\n}\r\n\r\n.sciexpr-element-number {\r\n font-size: 0.55em;\r\n color: #6c757d;\r\n line-height: 1;\r\n}\r\n\r\n.sciexpr-element-symbol {\r\n font-size: 0.85em;\r\n font-weight: 600;\r\n color: #212529;\r\n line-height: 1.2;\r\n}\r\n\r\n.sciexpr-element-cell-compact .sciexpr-element-symbol {\r\n font-size: 0.7em;\r\n}\r\n\r\n.sciexpr-element-cell-compact .sciexpr-element-number {\r\n font-size: 0.45em;\r\n}\r\n</style>\r\n","// @sciexpr/vue — useShortcuts Composable\r\n// ============================================================================\r\n\r\nimport { onMounted, onUnmounted } from 'vue';\r\n\r\n/** 快捷键定义 */\r\nexport interface ShortcutDef {\r\n key: string;\r\n ctrl?: boolean;\r\n meta?: boolean;\r\n shift?: boolean;\r\n alt?: boolean;\r\n action: () => void;\r\n description: string;\r\n}\r\n\r\n/**\r\n * 快捷键 composable\r\n *\r\n * 管理公式编辑器的键盘快捷键。\r\n *\r\n * @example\r\n * ```ts\r\n * useShortcuts([\r\n * { key: 'b', ctrl: true, action: () => insertText('\\\\textbf{}'), description: 'Bold' },\r\n * { key: '/', ctrl: true, action: () => insertText('\\\\frac{}{}'), description: 'Fraction' },\r\n * ]);\r\n * ```\r\n */\r\nexport function useShortcuts(shortcuts: ShortcutDef[]): void {\r\n function handleKeydown(e: KeyboardEvent): void {\r\n for (const shortcut of shortcuts) {\r\n const matchKey = e.key.toLowerCase() === shortcut.key.toLowerCase();\r\n const matchCtrl = !!shortcut.ctrl === (e.ctrlKey || e.metaKey);\r\n const matchShift = !!shortcut.shift === e.shiftKey;\r\n const matchAlt = !!shortcut.alt === e.altKey;\r\n\r\n if (matchKey && matchCtrl && matchShift && matchAlt) {\r\n e.preventDefault();\r\n shortcut.action();\r\n return;\r\n }\r\n }\r\n }\r\n\r\n onMounted(() => {\r\n window.addEventListener('keydown', handleKeydown);\r\n });\r\n\r\n onUnmounted(() => {\r\n window.removeEventListener('keydown', handleKeydown);\r\n });\r\n}\r\n\r\n/** 内置快捷键 */\r\nexport const BUILTIN_SHORTCUTS: ShortcutDef[] = [\r\n { key: 'b', ctrl: true, action: () => {}, description: 'Bold (\\\\mathbf{})' },\r\n { key: '/', ctrl: true, action: () => {}, description: 'Fraction (\\\\frac{}{})' },\r\n { key: 's', ctrl: true, shift: true, action: () => {}, description: 'Square root (\\\\sqrt{})' },\r\n { key: '1', ctrl: true, action: () => {}, description: 'Subscript (_)' },\r\n { key: '2', ctrl: true, action: () => {}, description: 'Superscript (^)' },\r\n];\r\n"],"names":["useFormulaRender","options","html","ref","mathml","unicode","error","parser","ParserRegistry","katexRenderer","KatexRenderer","unicodeRenderer","UnicodeRenderer","mathmlRenderer","MathMLRenderer","render","source","ast","htmlResult","_a","err","watch","newSource","useFormula","shallowRef","parsed","result","src","props","__props","slots","useSlots","slotContent","_c","_b","effectiveSource","displayModeRef","val","_createElementBlock","_normalizeClass","_unref","_toDisplayString","_hoisted_2","useFormulaEditor","value","cursor","handleInput","newValue","newCursor","insertText","text","before","after","wrapSelection","parse","isEmpty","computed","latexSource","useAutocomplete","suggestions","visible","selectedIndex","query","pipeline","AIPipeline","config","trigger","input","cursorPos","token","extractToken","context","ExpressionKind","select","item","moveSelection","direction","close","backslashIdx","match","AI_PIPELINE_KEY","useAIProvider","inject","provideAI","aiConfig","p","provide","setCompletionProvider","provider","setKnowledgeBase","emit","__emit","commandCategories","insertCommand","latex","_Fragment","_renderList","cat","_hoisted_1","_openBlock","cmd","$event","_renderSlot","_ctx","_createTextVNode","sourceRef","displayRef","v","_cache","_createElementVNode","_hoisted_3","_hoisted_4","_hoisted_5","selectItem","getCategoryColor","category","_createBlock","_Teleport","_normalizeStyle","index","$emit","textareaRef","editorRef","dropdownPosition","localValue","editor","autocomplete","e","target","updateDropdownPosition","handleKeydown","selected","insertCompletion","handleToolbarInsert","handleAutocompleteSelect","ta","start","end","nextTick","replaceStart","wordMatch","rect","lineHeight","charWidth","lines","lastLineLen","Toolbar","_createVNode","AutocompleteDropdown","LivePreview","symbolGroups","activeTab","searchQuery","filteredGroups","q","g","s","insertSymbol","group","sym","_hoisted_7","_hoisted_8","_hoisted_10","_hoisted_11","GRID_COLS","GRID_ROWS","ELEMENTS","grid","r","el","getBlockColor","block","selectElement","symbol","row","cell","colIdx","_vShow","useShortcuts","shortcuts","shortcut","matchKey","matchCtrl","matchShift","matchAlt","onMounted","onUnmounted","BUILTIN_SHORTCUTS"],"mappings":"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"}
package/dist/style.css CHANGED
@@ -1 +1 @@
1
- .sciexpr-formula[data-v-b2381271]{display:inline;vertical-align:middle}.sciexpr-formula.sciexpr-display[data-v-b2381271]{display:block;text-align:center;margin:1em 0}.sciexpr-formula-error[data-v-b2381271]{color:#d93025;font-family:Courier New,monospace;font-size:.9em;padding:2px 6px;background:#fce8e6;border-radius:4px;border:1px solid #f5c6cb}.sciexpr-formula-content[data-v-b2381271] .katex{font-size:1.1em}.sciexpr-formula.sciexpr-display[data-v-b2381271] .katex{font-size:1.21em}.sciexpr-toolbar[data-v-329eccb9]{display:flex;flex-wrap:wrap;gap:4px;padding:8px;background:#f8f9fa;border:1px solid #dee2e6;border-radius:8px 8px 0 0;border-bottom:none;-webkit-user-select:none;user-select:none}.sciexpr-toolbar-compact[data-v-329eccb9]{padding:4px;gap:2px}.sciexpr-toolbar-group[data-v-329eccb9]{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:0 6px;border-right:1px solid #dee2e6}.sciexpr-toolbar-group[data-v-329eccb9]:last-child{border-right:none}.sciexpr-toolbar-group-compact[data-v-329eccb9]{padding:0 2px}.sciexpr-toolbar-group-label[data-v-329eccb9]{font-size:.75em;color:#6c757d;margin-right:4px;white-space:nowrap}.sciexpr-toolbar-btn[data-v-329eccb9]{display:inline-flex;align-items:center;justify-content:center;min-width:28px;height:28px;padding:2px 6px;border:1px solid #ced4da;border-radius:4px;background:#fff;color:#212529;font-size:.85em;font-family:Segoe UI,system-ui,sans-serif;cursor:pointer;transition:all .15s ease}.sciexpr-toolbar-btn[data-v-329eccb9]:hover:not(:disabled){background:#e9ecef;border-color:#adb5bd;transform:translateY(-1px)}.sciexpr-toolbar-btn[data-v-329eccb9]:active:not(:disabled){background:#dee2e6;transform:translateY(0)}.sciexpr-toolbar-btn[data-v-329eccb9]:disabled{opacity:.4;cursor:not-allowed}.sciexpr-toolbar-btn-compact[data-v-329eccb9]{min-width:24px;height:24px;font-size:.75em;padding:1px 4px}.sciexpr-preview[data-v-b3730bc4]{border:1px solid #dee2e6;border-radius:0 0 8px 8px;min-height:60px;padding:16px;background:#fff;display:flex;align-items:center;justify-content:center}.sciexpr-preview-display[data-v-b3730bc4]{min-height:80px}.sciexpr-preview-error[data-v-b3730bc4]{display:flex;align-items:center;gap:8px;color:#d93025;font-size:.85em;font-family:Courier New,monospace}.sciexpr-preview-error-icon[data-v-b3730bc4]{font-size:1.2em}.sciexpr-preview-render[data-v-b3730bc4]{overflow-x:auto;max-width:100%}.sciexpr-preview-empty[data-v-b3730bc4]{color:#adb5bd;font-size:.9em;font-style:italic}.sciexpr-preview-source[data-v-b3730bc4]{margin-top:8px;padding:6px 10px;background:#f8f9fa;border-radius:4px;font-size:.8em;font-family:Courier New,monospace;color:#6c757d;border-top:1px solid #dee2e6}.sciexpr-preview[data-v-b3730bc4] .katex{font-size:1.1em}.sciexpr-preview-display[data-v-b3730bc4] .katex{font-size:1.21em}.sciexpr-autocomplete[data-v-d18e03d1]{position:fixed;z-index:10000;min-width:220px;max-width:360px;max-height:240px;overflow-y:auto;background:#fff;border:1px solid #dee2e6;border-radius:8px;box-shadow:0 8px 24px #0000001f;padding:4px}.sciexpr-autocomplete-item[data-v-d18e03d1]{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer;font-size:.85em;transition:background .1s ease}.sciexpr-autocomplete-item[data-v-d18e03d1]:hover,.sciexpr-autocomplete-item.selected[data-v-d18e03d1]{background:#e7f1ff}.sciexpr-autocomplete-category[data-v-d18e03d1]{display:inline-flex;align-items:center;justify-content:center;padding:1px 6px;border-radius:4px;color:#fff;font-size:.7em;font-weight:500;text-transform:uppercase;white-space:nowrap}.sciexpr-autocomplete-label[data-v-d18e03d1]{font-weight:500;color:#212529;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Courier New,monospace;font-size:.95em}.sciexpr-autocomplete-desc[data-v-d18e03d1]{color:#6c757d;font-size:.8em;margin-left:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:80px}.sciexpr-autocomplete-source[data-v-d18e03d1]{font-size:.65em;color:#adb5bd;font-style:italic}.sciexpr-editor[data-v-d6181c80]{display:flex;flex-direction:column;border-radius:8px;font-family:Segoe UI,system-ui,sans-serif}.sciexpr-editor-input-wrap[data-v-d6181c80]{position:relative}.sciexpr-editor-textarea[data-v-d6181c80]{width:100%;padding:12px;border:1px solid #dee2e6;border-top:none;font-family:Courier New,Consolas,monospace;font-size:.95em;line-height:1.6;resize:vertical;outline:none;box-sizing:border-box;transition:border-color .15s ease;min-height:60px}.sciexpr-editor-textarea[data-v-d6181c80]:focus{border-color:#86b7fe;box-shadow:inset 0 0 0 2px #0d6efd1a}.sciexpr-editor-textarea-display[data-v-d6181c80]{font-size:1.05em;text-align:center}.sciexpr-editor-textarea-readonly[data-v-d6181c80]{background:#f8f9fa;cursor:default}.sciexpr-editor-display .sciexpr-editor-textarea[data-v-d6181c80]{border-radius:0}.sciexpr-editor[data-v-d6181c80] .sciexpr-toolbar{border-radius:8px 8px 0 0}.sciexpr-symbol-panel[data-v-8a9ec119]{border:1px solid #dee2e6;border-radius:8px;background:#fff;overflow:hidden;-webkit-user-select:none;user-select:none}.sciexpr-symbol-search[data-v-8a9ec119]{padding:8px;border-bottom:1px solid #dee2e6}.sciexpr-symbol-search-input[data-v-8a9ec119]{width:100%;padding:6px 10px;border:1px solid #ced4da;border-radius:6px;font-size:.85em;outline:none;box-sizing:border-box}.sciexpr-symbol-search-input[data-v-8a9ec119]:focus{border-color:#86b7fe;box-shadow:0 0 0 3px #0d6efd26}.sciexpr-symbol-tabs[data-v-8a9ec119]{display:flex;flex-wrap:wrap;gap:0;border-bottom:1px solid #dee2e6;background:#f8f9fa}.sciexpr-symbol-tab[data-v-8a9ec119]{padding:6px 10px;border:none;background:none;font-size:.78em;color:#6c757d;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s ease}.sciexpr-symbol-tab[data-v-8a9ec119]:hover{color:#212529;background:#e9ecef}.sciexpr-symbol-tab.active[data-v-8a9ec119]{color:#0d6efd;border-bottom-color:#0d6efd;font-weight:500}.sciexpr-symbol-grid[data-v-8a9ec119]{display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:4px;padding:8px;max-height:280px;overflow-y:auto}.sciexpr-symbol-btn[data-v-8a9ec119]{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 4px;border:1px solid transparent;border-radius:6px;background:#f8f9fa;cursor:pointer;transition:all .12s ease}.sciexpr-symbol-btn[data-v-8a9ec119]:hover:not(:disabled){background:#e7f1ff;border-color:#b6d4fe}.sciexpr-symbol-btn[data-v-8a9ec119]:active:not(:disabled){background:#cfe2ff}.sciexpr-symbol-btn-disabled[data-v-8a9ec119]{opacity:.4;cursor:not-allowed}.sciexpr-symbol-unicode[data-v-8a9ec119]{font-size:1.3em;line-height:1.2}.sciexpr-symbol-name[data-v-8a9ec119]{font-size:.65em;color:#6c757d;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.sciexpr-element-table[data-v-a5437c7c]{border:1px solid #dee2e6;border-radius:8px;background:#fff;padding:12px;overflow-x:auto;-webkit-user-select:none;user-select:none}.sciexpr-element-table-compact[data-v-a5437c7c]{padding:6px}.sciexpr-element-legend[data-v-a5437c7c]{display:flex;gap:16px;margin-bottom:10px;font-size:.7em;color:#6c757d}.legend-item[data-v-a5437c7c]{display:flex;align-items:center;gap:4px}.legend-dot[data-v-a5437c7c]{display:inline-block;width:10px;height:10px;border-radius:2px}.sciexpr-element-grid[data-v-a5437c7c]{display:grid;grid-template-columns:repeat(18,1fr);grid-template-rows:repeat(6,1fr);gap:3px;min-width:540px}.sciexpr-element-cell[data-v-a5437c7c]{display:flex;flex-direction:column;align-items:center;justify-content:center;aspect-ratio:1;padding:2px;border:1px solid #dee2e6;border-radius:4px;background:#f8f9fa;cursor:pointer;transition:all .12s ease;border-left:3px solid var(--block-color, #adb5bd);min-width:0}.sciexpr-element-cell[data-v-a5437c7c]:hover:not(:disabled){transform:scale(1.15);z-index:10;box-shadow:0 4px 12px #00000026;background:#fff}.sciexpr-element-cell-compact[data-v-a5437c7c]{padding:1px}.sciexpr-element-cell-disabled[data-v-a5437c7c]{opacity:.4;cursor:not-allowed}.sciexpr-element-empty[data-v-a5437c7c]{border-color:transparent;background:transparent;cursor:default;pointer-events:none}.sciexpr-element-number[data-v-a5437c7c]{font-size:.55em;color:#6c757d;line-height:1}.sciexpr-element-symbol[data-v-a5437c7c]{font-size:.85em;font-weight:600;color:#212529;line-height:1.2}.sciexpr-element-cell-compact .sciexpr-element-symbol[data-v-a5437c7c]{font-size:.7em}.sciexpr-element-cell-compact .sciexpr-element-number[data-v-a5437c7c]{font-size:.45em}
1
+ .sciexpr-formula[data-v-557e5ff9]{display:inline;vertical-align:middle}.sciexpr-formula.sciexpr-display[data-v-557e5ff9]{display:block;text-align:center;margin:1em 0}.sciexpr-formula-error[data-v-557e5ff9]{color:#d93025;font-family:Courier New,monospace;font-size:.9em;padding:2px 6px;background:#fce8e6;border-radius:4px;border:1px solid #f5c6cb}.sciexpr-formula-content[data-v-557e5ff9] .katex{font-size:1.1em}.sciexpr-formula.sciexpr-display[data-v-557e5ff9] .katex{font-size:1.21em}.sciexpr-toolbar[data-v-329eccb9]{display:flex;flex-wrap:wrap;gap:4px;padding:8px;background:#f8f9fa;border:1px solid #dee2e6;border-radius:8px 8px 0 0;border-bottom:none;-webkit-user-select:none;user-select:none}.sciexpr-toolbar-compact[data-v-329eccb9]{padding:4px;gap:2px}.sciexpr-toolbar-group[data-v-329eccb9]{display:flex;flex-wrap:wrap;align-items:center;gap:2px;padding:0 6px;border-right:1px solid #dee2e6}.sciexpr-toolbar-group[data-v-329eccb9]:last-child{border-right:none}.sciexpr-toolbar-group-compact[data-v-329eccb9]{padding:0 2px}.sciexpr-toolbar-group-label[data-v-329eccb9]{font-size:.75em;color:#6c757d;margin-right:4px;white-space:nowrap}.sciexpr-toolbar-btn[data-v-329eccb9]{display:inline-flex;align-items:center;justify-content:center;min-width:28px;height:28px;padding:2px 6px;border:1px solid #ced4da;border-radius:4px;background:#fff;color:#212529;font-size:.85em;font-family:Segoe UI,system-ui,sans-serif;cursor:pointer;transition:all .15s ease}.sciexpr-toolbar-btn[data-v-329eccb9]:hover:not(:disabled){background:#e9ecef;border-color:#adb5bd;transform:translateY(-1px)}.sciexpr-toolbar-btn[data-v-329eccb9]:active:not(:disabled){background:#dee2e6;transform:translateY(0)}.sciexpr-toolbar-btn[data-v-329eccb9]:disabled{opacity:.4;cursor:not-allowed}.sciexpr-toolbar-btn-compact[data-v-329eccb9]{min-width:24px;height:24px;font-size:.75em;padding:1px 4px}.sciexpr-preview[data-v-b3730bc4]{border:1px solid #dee2e6;border-radius:0 0 8px 8px;min-height:60px;padding:16px;background:#fff;display:flex;align-items:center;justify-content:center}.sciexpr-preview-display[data-v-b3730bc4]{min-height:80px}.sciexpr-preview-error[data-v-b3730bc4]{display:flex;align-items:center;gap:8px;color:#d93025;font-size:.85em;font-family:Courier New,monospace}.sciexpr-preview-error-icon[data-v-b3730bc4]{font-size:1.2em}.sciexpr-preview-render[data-v-b3730bc4]{overflow-x:auto;max-width:100%}.sciexpr-preview-empty[data-v-b3730bc4]{color:#adb5bd;font-size:.9em;font-style:italic}.sciexpr-preview-source[data-v-b3730bc4]{margin-top:8px;padding:6px 10px;background:#f8f9fa;border-radius:4px;font-size:.8em;font-family:Courier New,monospace;color:#6c757d;border-top:1px solid #dee2e6}.sciexpr-preview[data-v-b3730bc4] .katex{font-size:1.1em}.sciexpr-preview-display[data-v-b3730bc4] .katex{font-size:1.21em}.sciexpr-autocomplete[data-v-d18e03d1]{position:fixed;z-index:10000;min-width:220px;max-width:360px;max-height:240px;overflow-y:auto;background:#fff;border:1px solid #dee2e6;border-radius:8px;box-shadow:0 8px 24px #0000001f;padding:4px}.sciexpr-autocomplete-item[data-v-d18e03d1]{display:flex;align-items:center;gap:8px;padding:6px 10px;border-radius:6px;cursor:pointer;font-size:.85em;transition:background .1s ease}.sciexpr-autocomplete-item[data-v-d18e03d1]:hover,.sciexpr-autocomplete-item.selected[data-v-d18e03d1]{background:#e7f1ff}.sciexpr-autocomplete-category[data-v-d18e03d1]{display:inline-flex;align-items:center;justify-content:center;padding:1px 6px;border-radius:4px;color:#fff;font-size:.7em;font-weight:500;text-transform:uppercase;white-space:nowrap}.sciexpr-autocomplete-label[data-v-d18e03d1]{font-weight:500;color:#212529;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-family:Courier New,monospace;font-size:.95em}.sciexpr-autocomplete-desc[data-v-d18e03d1]{color:#6c757d;font-size:.8em;margin-left:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:80px}.sciexpr-autocomplete-source[data-v-d18e03d1]{font-size:.65em;color:#adb5bd;font-style:italic}.sciexpr-editor[data-v-d6181c80]{display:flex;flex-direction:column;border-radius:8px;font-family:Segoe UI,system-ui,sans-serif}.sciexpr-editor-input-wrap[data-v-d6181c80]{position:relative}.sciexpr-editor-textarea[data-v-d6181c80]{width:100%;padding:12px;border:1px solid #dee2e6;border-top:none;font-family:Courier New,Consolas,monospace;font-size:.95em;line-height:1.6;resize:vertical;outline:none;box-sizing:border-box;transition:border-color .15s ease;min-height:60px}.sciexpr-editor-textarea[data-v-d6181c80]:focus{border-color:#86b7fe;box-shadow:inset 0 0 0 2px #0d6efd1a}.sciexpr-editor-textarea-display[data-v-d6181c80]{font-size:1.05em;text-align:center}.sciexpr-editor-textarea-readonly[data-v-d6181c80]{background:#f8f9fa;cursor:default}.sciexpr-editor-display .sciexpr-editor-textarea[data-v-d6181c80]{border-radius:0}.sciexpr-editor[data-v-d6181c80] .sciexpr-toolbar{border-radius:8px 8px 0 0}.sciexpr-symbol-panel[data-v-8a9ec119]{border:1px solid #dee2e6;border-radius:8px;background:#fff;overflow:hidden;-webkit-user-select:none;user-select:none}.sciexpr-symbol-search[data-v-8a9ec119]{padding:8px;border-bottom:1px solid #dee2e6}.sciexpr-symbol-search-input[data-v-8a9ec119]{width:100%;padding:6px 10px;border:1px solid #ced4da;border-radius:6px;font-size:.85em;outline:none;box-sizing:border-box}.sciexpr-symbol-search-input[data-v-8a9ec119]:focus{border-color:#86b7fe;box-shadow:0 0 0 3px #0d6efd26}.sciexpr-symbol-tabs[data-v-8a9ec119]{display:flex;flex-wrap:wrap;gap:0;border-bottom:1px solid #dee2e6;background:#f8f9fa}.sciexpr-symbol-tab[data-v-8a9ec119]{padding:6px 10px;border:none;background:none;font-size:.78em;color:#6c757d;cursor:pointer;border-bottom:2px solid transparent;transition:all .15s ease}.sciexpr-symbol-tab[data-v-8a9ec119]:hover{color:#212529;background:#e9ecef}.sciexpr-symbol-tab.active[data-v-8a9ec119]{color:#0d6efd;border-bottom-color:#0d6efd;font-weight:500}.sciexpr-symbol-grid[data-v-8a9ec119]{display:grid;grid-template-columns:repeat(auto-fill,minmax(72px,1fr));gap:4px;padding:8px;max-height:280px;overflow-y:auto}.sciexpr-symbol-btn[data-v-8a9ec119]{display:flex;flex-direction:column;align-items:center;gap:2px;padding:6px 4px;border:1px solid transparent;border-radius:6px;background:#f8f9fa;cursor:pointer;transition:all .12s ease}.sciexpr-symbol-btn[data-v-8a9ec119]:hover:not(:disabled){background:#e7f1ff;border-color:#b6d4fe}.sciexpr-symbol-btn[data-v-8a9ec119]:active:not(:disabled){background:#cfe2ff}.sciexpr-symbol-btn-disabled[data-v-8a9ec119]{opacity:.4;cursor:not-allowed}.sciexpr-symbol-unicode[data-v-8a9ec119]{font-size:1.3em;line-height:1.2}.sciexpr-symbol-name[data-v-8a9ec119]{font-size:.65em;color:#6c757d;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%}.sciexpr-element-table[data-v-a5437c7c]{border:1px solid #dee2e6;border-radius:8px;background:#fff;padding:12px;overflow-x:auto;-webkit-user-select:none;user-select:none}.sciexpr-element-table-compact[data-v-a5437c7c]{padding:6px}.sciexpr-element-legend[data-v-a5437c7c]{display:flex;gap:16px;margin-bottom:10px;font-size:.7em;color:#6c757d}.legend-item[data-v-a5437c7c]{display:flex;align-items:center;gap:4px}.legend-dot[data-v-a5437c7c]{display:inline-block;width:10px;height:10px;border-radius:2px}.sciexpr-element-grid[data-v-a5437c7c]{display:grid;grid-template-columns:repeat(18,1fr);grid-template-rows:repeat(6,1fr);gap:3px;min-width:540px}.sciexpr-element-cell[data-v-a5437c7c]{display:flex;flex-direction:column;align-items:center;justify-content:center;aspect-ratio:1;padding:2px;border:1px solid #dee2e6;border-radius:4px;background:#f8f9fa;cursor:pointer;transition:all .12s ease;border-left:3px solid var(--block-color, #adb5bd);min-width:0}.sciexpr-element-cell[data-v-a5437c7c]:hover:not(:disabled){transform:scale(1.15);z-index:10;box-shadow:0 4px 12px #00000026;background:#fff}.sciexpr-element-cell-compact[data-v-a5437c7c]{padding:1px}.sciexpr-element-cell-disabled[data-v-a5437c7c]{opacity:.4;cursor:not-allowed}.sciexpr-element-empty[data-v-a5437c7c]{border-color:transparent;background:transparent;cursor:default;pointer-events:none}.sciexpr-element-number[data-v-a5437c7c]{font-size:.55em;color:#6c757d;line-height:1}.sciexpr-element-symbol[data-v-a5437c7c]{font-size:.85em;font-weight:600;color:#212529;line-height:1.2}.sciexpr-element-cell-compact .sciexpr-element-symbol[data-v-a5437c7c]{font-size:.7em}.sciexpr-element-cell-compact .sciexpr-element-number[data-v-a5437c7c]{font-size:.45em}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sciexpr/vue",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Scientific Expression Engine - Vue 3 components (FormulaEditor, Toolbar, SymbolPanel)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -44,9 +44,9 @@
44
44
  },
45
45
  "dependencies": {
46
46
  "@sciexpr/core": "0.1.0",
47
- "@sciexpr/parser": "0.1.0",
48
- "@sciexpr/ai": "0.1.0",
49
- "@sciexpr/renderer": "0.1.0"
47
+ "@sciexpr/parser": "0.1.1",
48
+ "@sciexpr/renderer": "0.1.1",
49
+ "@sciexpr/ai": "0.1.0"
50
50
  },
51
51
  "peerDependencies": {
52
52
  "vue": "^3.4.0"
@@ -63,6 +63,7 @@
63
63
  "scripts": {
64
64
  "build": "vite build",
65
65
  "dev": "vite build --watch",
66
+ "playground": "vite --config vite.dev.config.ts",
66
67
  "lint": "vue-tsc --noEmit",
67
68
  "clean": "rimraf dist",
68
69
  "test": "vitest run"