@sciexpr/vue 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.mjs +931 -0
- package/dist/index.mjs.map +1 -0
- package/dist/style.css +1 -0
- package/package.json +70 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("vue"),_=require("@sciexpr/renderer"),$=require("@sciexpr/parser"),S=require("@sciexpr/ai"),q=require("@sciexpr/core");function z(t){const a=e.ref(""),n=e.ref(""),c=e.ref(""),i=e.ref(null),m=new $.ParserRegistry,s=t.katexRenderer??new _.KatexRenderer,o=new _.UnicodeRenderer,r=new _.MathMLRenderer;function u(l){var p;try{const x=m.parse(l,{hint:"auto"});if(!x||x.children.length===0){a.value="",i.value=null;return}const y=s.render(x,{displayMode:t.displayMode,...t.renderOptions});a.value=y.value,(p=y.warnings)!=null&&p.length,n.value=r.render(x).value,c.value=o.render(x).value,i.value=null}catch(x){i.value={message:x instanceof Error?x.message:String(x)},a.value=""}}return e.watch(t.source,l=>{u(l)},{immediate:!0}),{html:a,mathml:n,unicode:c,error:i,render:u}}function I(t){const a=e.ref(""),n=e.ref(null),c=e.shallowRef(null),i=new $.ParserRegistry,m=new _.KatexRenderer;function s(o){var r;try{const u=i.parse(o,{hint:"auto"});if(c.value=u,!u||u.children.length===0){a.value="",n.value=null;return}const l=m.render(u,{displayMode:((r=t.displayMode)==null?void 0:r.value)??!1});a.value=l.value,n.value=null}catch(u){n.value={message:u instanceof Error?u.message:String(u)},a.value=o}}return e.watch([t.source,t.displayMode??e.ref(!1)],([o])=>{s(o)},{immediate:!0}),{html:a,error:n,ast:c,render:s}}const H=["data-source"],K=["title"],U=["innerHTML"],G=e.defineComponent({__name:"Formula",props:{source:{default:""},displayMode:{type:Boolean,default:!1},throwOnError:{type:Boolean,default:!1},className:{default:""},fallbackText:{default:""}},setup(t){var o,r,u;const a=t,n=e.useSlots(),c=(u=(r=(o=n.default)==null?void 0:o.call(n))==null?void 0:r[0])==null?void 0:u.children,i=e.ref(a.source||c||""),{html:m,error:s}=I({source:i,displayMode:e.ref(a.displayMode)});return(l,p)=>(e.openBlock(),e.createElementBlock("span",{class:e.normalizeClass(["sciexpr-formula",a.className,{"sciexpr-display":a.displayMode,"sciexpr-error":e.unref(s)}]),"data-source":i.value},[e.unref(s)?(e.openBlock(),e.createElementBlock("span",{key:0,class:"sciexpr-formula-error",title:e.unref(s).message},e.toDisplayString(t.fallbackText||i.value),9,K)):(e.openBlock(),e.createElementBlock("span",{key:1,innerHTML:e.unref(m),class:"sciexpr-formula-content"},null,8,U))],10,H))}}),C=(t,a)=>{const n=t.__vccOpts||t;for(const[c,i]of a)n[c]=i;return n},W=C(G,[["__scopeId","data-v-b2381271"]]);function T(t){const a=e.ref(t.initialValue??""),n=e.ref(0),c=e.ref(""),i=e.ref(null),m=e.ref(null),s=new $.ParserRegistry;function o(y,g){a.value=y,g!==void 0&&(n.value=g)}function r(y){const g=a.value.slice(0,n.value),E=a.value.slice(n.value);a.value=g+y+E,n.value+=y.length}function u(y,g){const E=a.value;a.value=y+E+g,n.value=a.value.length}function l(){try{const y=s.parse(a.value,{hint:"auto"});return m.value=y,y}catch{return m.value=null,null}}const p=e.computed(()=>a.value.trim().length===0),x=e.computed(()=>a.value);return{value:a,cursor:n,html:c,ast:m,error:i,isEmpty:p,latexSource:x,handleInput:o,insertText:r,wrapSelection:u,parse:l}}function V(t){const a=e.ref([]),n=e.ref(!1),c=e.ref(0),i=e.ref(""),m=t.pipeline??new S.AIPipeline,s=t.config??{enabled:!0,minTriggerLength:2,maxItems:10};async function o(p,x){if(!s.enabled){n.value=!1;return}const y=Z(p,x);if(!y||y.length<(s.minTriggerLength??2)){n.value=!1;return}i.value=y;const g={currentInput:p,cursorPosition:x,expressionType:q.ExpressionKind.Math},E=await m.getCompletions(g);a.value=E.items.slice(0,s.maxItems??10),n.value=a.value.length>0,c.value=0}function r(p){return n.value=!1,p.text}function u(p){p==="up"?c.value=Math.max(0,c.value-1):c.value=Math.min(a.value.length-1,c.value+1)}function l(){n.value=!1,a.value=[]}return{suggestions:a,visible:n,selectedIndex:c,query:i,trigger:o,select:r,moveSelection:u,close:l}}function Z(t,a){const n=t.slice(0,a),c=n.lastIndexOf("\\");if(c!==-1){const s=n.slice(c).match(/^\\[a-zA-Z]*$/);if(s)return s[0]}const i=n.match(/([a-zA-Z_]+)$/);return i?i[1]:""}const N=Symbol("sciexpr-ai-pipeline");function R(t){const a=t?new S.AIPipeline(t):e.inject(N,null);function n(m){const s=new S.AIPipeline(m);e.provide(N,s)}function c(m){a&&e.provide(N,new S.AIPipeline({completionProvider:m}))}function i(m){a&&e.provide(N,new S.AIPipeline({knowledgeBaseProvider:m}))}return{pipeline:a,provideAI:n,setCompletionProvider:c,setKnowledgeBase:i}}const X={key:0,class:"sciexpr-toolbar-group-label"},j=["title","disabled","onClick"],Y=e.defineComponent({__name:"Toolbar",props:{categories:{},disabled:{type:Boolean},compact:{type:Boolean}},emits:["insert"],setup(t,{emit:a}){const n=a,c=[{id:"fraction",label:"Fraction & Script",icon:"📐",commands:[{latex:"\\frac{}{}",label:"⅟",description:"Fraction"},{latex:"^{}",label:"x²",description:"Superscript"},{latex:"_{}",label:"x₂",description:"Subscript"},{latex:"^{}_{}",label:"x²₁",description:"Both scripts"}]},{id:"radical",label:"Radicals",icon:"√",commands:[{latex:"\\sqrt{}",label:"√x",description:"Square root"},{latex:"\\sqrt[3]{}",label:"∛x",description:"Cube root"},{latex:"\\sqrt[n]{}",label:"ⁿ√x",description:"Nth root"}]},{id:"symbol",label:"Operators",icon:"∑",commands:[{latex:"\\sum_{}^{}",label:"∑",description:"Summation"},{latex:"\\prod_{}^{}",label:"∏",description:"Product"},{latex:"\\int_{}^{}",label:"∫",description:"Integral"},{latex:"\\lim_{x \\to }{}",label:"lim",description:"Limit"},{latex:"\\infty",label:"∞",description:"Infinity"},{latex:"\\partial",label:"∂",description:"Partial derivative"}]},{id:"greek",label:"Greek",icon:"α",commands:[{latex:"\\alpha",label:"α",description:"Alpha"},{latex:"\\beta",label:"β",description:"Beta"},{latex:"\\gamma",label:"γ",description:"Gamma"},{latex:"\\delta",label:"δ",description:"Delta"},{latex:"\\theta",label:"θ",description:"Theta"},{latex:"\\lambda",label:"λ",description:"Lambda"},{latex:"\\mu",label:"μ",description:"Mu"},{latex:"\\pi",label:"π",description:"Pi"},{latex:"\\sigma",label:"σ",description:"Sigma"},{latex:"\\phi",label:"φ",description:"Phi"},{latex:"\\omega",label:"ω",description:"Omega"}]},{id:"matrix",label:"Matrix",icon:"▦",commands:[{latex:"\\begin{pmatrix} & \\\\ & \\end{pmatrix}",label:"( )",description:"pmatrix"},{latex:"\\begin{bmatrix} & \\\\ & \\end{bmatrix}",label:"[ ]",description:"bmatrix"},{latex:"\\begin{vmatrix} & \\\\ & \\end{vmatrix}",label:"| |",description:"vmatrix"}]},{id:"chemistry",label:"Chemistry",icon:"⚗",commands:[{latex:"\\ce{H2O}",label:"H₂O",description:"Water"},{latex:"\\ce{->}",label:"→",description:"Reaction arrow"},{latex:"\\ce{<=>}",label:"⇌",description:"Equilibrium"},{latex:"^{n+}",label:"ⁿ⁺",description:"Charge"}]}];function i(m){n("insert",m)}return(m,s)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["sciexpr-toolbar",{"sciexpr-toolbar-compact":t.compact}]),role:"toolbar","aria-label":"Formula toolbar"},[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(c,o=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:o.id},[!t.categories||t.categories.includes(o.id)?(e.openBlock(),e.createElementBlock("div",{key:0,class:e.normalizeClass(["sciexpr-toolbar-group",{"sciexpr-toolbar-group-compact":t.compact}])},[t.compact?e.createCommentVNode("",!0):(e.openBlock(),e.createElementBlock("span",X,e.toDisplayString(o.icon)+" "+e.toDisplayString(o.label),1)),(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(o.commands,r=>(e.openBlock(),e.createElementBlock("button",{key:r.latex,class:e.normalizeClass(["sciexpr-toolbar-btn",{"sciexpr-toolbar-btn-compact":t.compact}]),title:r.description,disabled:t.disabled,type:"button",onClick:u=>i(r.latex)},[e.renderSlot(m.$slots,`btn-${r.label}`,{command:r},()=>[e.createTextVNode(e.toDisplayString(r.label),1)],!0)],10,j))),128))],2)):e.createCommentVNode("",!0)],64))),64))],2))}}),D=C(Y,[["__scopeId","data-v-329eccb9"]]),Q={key:0,class:"sciexpr-preview-error"},J={key:1,class:"sciexpr-preview-render"},ee=["innerHTML"],te={key:2,class:"sciexpr-preview-empty"},oe={key:3,class:"sciexpr-preview-source"},le=e.defineComponent({__name:"LivePreview",props:{source:{},displayMode:{type:Boolean,default:!1},showSource:{type:Boolean,default:!1}},setup(t){const a=t,n=e.ref(a.source),c=e.ref(a.displayMode);e.watch(()=>a.source,s=>{n.value=s}),e.watch(()=>a.displayMode,s=>{c.value=s});const{html:i,error:m}=I({source:n,displayMode:c});return(s,o)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["sciexpr-preview",{"sciexpr-preview-display":t.displayMode}])},[e.unref(m)?(e.openBlock(),e.createElementBlock("div",Q,[o[0]||(o[0]=e.createElementVNode("span",{class:"sciexpr-preview-error-icon"},"⚠",-1)),e.createElementVNode("span",null,e.toDisplayString(e.unref(m).message),1)])):e.unref(i)?(e.openBlock(),e.createElementBlock("div",J,[e.createElementVNode("span",{innerHTML:e.unref(i)},null,8,ee)])):(e.openBlock(),e.createElementBlock("div",te,[...o[1]||(o[1]=[e.createElementVNode("span",{class:"sciexpr-preview-empty-text"},"Preview",-1)])])),t.showSource&&t.source?(e.openBlock(),e.createElementBlock("div",oe,[e.createElementVNode("code",null,e.toDisplayString(t.source),1)])):e.createCommentVNode("",!0)],2))}}),F=C(le,[["__scopeId","data-v-b3730bc4"]]),ae=["aria-selected","onClick","onMouseenter"],ne={class:"sciexpr-autocomplete-label"},ce={key:0,class:"sciexpr-autocomplete-desc"},re={key:1,class:"sciexpr-autocomplete-source"},ie=e.defineComponent({__name:"AutocompleteDropdown",props:{items:{},visible:{type:Boolean},selectedIndex:{},position:{}},emits:["select","close"],setup(t,{emit:a}){const n=a,c=e.inject(N,null);function i(s){n("select",s)}function m(s){return{symbol:"#0d6efd",command:"#6f42c1",template:"#198754",correction:"#fd7e14",formula:"#d63384"}[s]??"#6c757d"}return(s,o)=>(e.openBlock(),e.createBlock(e.Teleport,{to:"body"},[t.visible&&t.items.length>0?(e.openBlock(),e.createElementBlock("div",{key:0,class:"sciexpr-autocomplete",style:e.normalizeStyle(t.position?{top:t.position.top+"px",left:t.position.left+"px"}:{}),role:"listbox"},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(t.items,(r,u)=>(e.openBlock(),e.createElementBlock("div",{key:`${r.text}-${u}`,class:e.normalizeClass(["sciexpr-autocomplete-item",{selected:u===t.selectedIndex}]),role:"option","aria-selected":u===t.selectedIndex,onClick:l=>i(r),onMouseenter:l=>s.$emit("select",r)},[e.createElementVNode("span",{class:"sciexpr-autocomplete-category",style:e.normalizeStyle({background:m(r.category)})},e.toDisplayString(r.category),5),e.createElementVNode("span",ne,e.toDisplayString(r.label),1),r.description?(e.openBlock(),e.createElementBlock("span",ce,e.toDisplayString(r.description),1)):e.createCommentVNode("",!0),e.unref(c)?(e.openBlock(),e.createElementBlock("span",re,e.toDisplayString(r.previewHtml?"AI":""),1)):e.createCommentVNode("",!0)],42,ae))),128))],4)):e.createCommentVNode("",!0)]))}}),A=C(ie,[["__scopeId","data-v-d18e03d1"]]),se={class:"sciexpr-editor-input-wrap"},me=["placeholder","readonly","rows"],ue=e.defineComponent({__name:"FormulaEditor",props:{value:{default:""},displayMode:{type:Boolean,default:!1},readonly:{type:Boolean,default:!1},placeholder:{default:"Type LaTeX or chemical formula..."},toolbar:{},autocomplete:{},showPreview:{type:Boolean,default:!0},showToolbar:{type:Boolean,default:!0},rows:{default:3}},emits:["update:value","change","error"],setup(t,{emit:a}){const n=t,c=a,i=e.ref(null),m=e.ref(null),s=e.ref({top:0,left:0}),o=e.ref(n.value);e.watch(()=>n.value,d=>{o.value=d});const r=T({initialValue:o.value}),{pipeline:u}=R(),l=V({config:n.autocomplete,pipeline:u});function p(d){const b=d.target,f=b.value,v=b.selectionStart;o.value=f,r.value.value=f,r.cursor.value=v,c("update:value",f),c("change",f),l.trigger(f,v),P()}function x(d){if(l.visible.value){if(d.key==="ArrowDown"){d.preventDefault(),l.moveSelection("down");return}if(d.key==="ArrowUp"){d.preventDefault(),l.moveSelection("up");return}if(d.key==="Enter"||d.key==="Tab"){d.preventDefault();const b=l.suggestions.value[l.selectedIndex.value];b&&L(b.text);return}if(d.key==="Escape"){l.close();return}}(d.ctrlKey||d.metaKey)&&(d.key==="b"&&(d.preventDefault(),O("\\mathbf{","}")),d.key==="/"&&(d.preventDefault(),E("\\frac{}{}")))}function y(d){E(d)}function g(d){L(d.text)}function E(d){const b=i.value;if(!b)return;const f=b.selectionStart,v=b.selectionEnd,h=o.value.slice(0,f),w=o.value.slice(v);o.value=h+d+w,c("update:value",o.value),e.nextTick(()=>{b.focus();const k=f+d.length;b.setSelectionRange(k,k),l.close()})}function L(d){const b=i.value;if(!b)return;const f=b.selectionStart,v=o.value.slice(0,f),h=v.lastIndexOf("\\");let w;if(h!==-1&&f-h<30)w=h;else{const B=v.match(/([a-zA-Z_]+)$/);w=B?f-B[0].length:f}const k=o.value.slice(f);o.value=o.value.slice(0,w)+d+k,c("update:value",o.value),e.nextTick(()=>{b.focus();const B=w+d.length;b.setSelectionRange(B,B),l.close()})}function O(d,b){const f=i.value;if(!f)return;const v=f.selectionStart,h=f.selectionEnd,w=o.value.slice(v,h)||"",k=o.value.slice(0,v)+d+w+b+o.value.slice(h);o.value=k,c("update:value",k),e.nextTick(()=>{f.focus();const B=v+d.length+w.length;f.setSelectionRange(B,B)})}function P(){const d=i.value;if(!d)return;const b=d.getBoundingClientRect(),f=d.selectionStart,v=20,h=8,k=o.value.slice(0,f).split(`
|
|
2
|
+
`),B=k[k.length-1].length;s.value={top:b.top+k.length*v+24+window.scrollY,left:b.left+B*h+window.scrollX}}return e.computed(()=>o.value.trim().length>0),(d,b)=>{var f;return e.openBlock(),e.createElementBlock("div",{ref_key:"editorRef",ref:m,class:e.normalizeClass(["sciexpr-editor",{"sciexpr-editor-display":t.displayMode}])},[t.showToolbar&&!t.readonly?(e.openBlock(),e.createBlock(D,{key:0,categories:(f=t.toolbar)==null?void 0:f.categories,onInsert:y},null,8,["categories"])):e.createCommentVNode("",!0),e.createElementVNode("div",se,[e.withDirectives(e.createElementVNode("textarea",{ref_key:"textareaRef",ref:i,"onUpdate:modelValue":b[0]||(b[0]=v=>o.value=v),class:e.normalizeClass(["sciexpr-editor-textarea",{"sciexpr-editor-textarea-display":t.displayMode,"sciexpr-editor-textarea-readonly":t.readonly}]),placeholder:t.placeholder,readonly:t.readonly,rows:t.rows,"aria-label":"Formula input",spellcheck:"false",autocomplete:"off",autocorrect:"off",autocapitalize:"off",onInput:p,onKeydown:x,onFocus:P},null,42,me),[[e.vModelText,o.value]])]),e.createVNode(A,{items:e.unref(l).suggestions.value,visible:e.unref(l).visible.value,"selected-index":e.unref(l).selectedIndex.value,position:s.value,onSelect:g,onClose:b[1]||(b[1]=v=>e.unref(l).close())},null,8,["items","visible","selected-index","position"]),t.showPreview?(e.openBlock(),e.createBlock(F,{key:1,source:o.value,"display-mode":t.displayMode,"show-source":!1},null,8,["source","display-mode"])):e.createCommentVNode("",!0)],2)}}}),de=C(ue,[["__scopeId","data-v-d6181c80"]]),pe={class:"sciexpr-symbol-panel"},be={class:"sciexpr-symbol-search"},fe={class:"sciexpr-symbol-tabs"},xe=["onClick"],ye={class:"sciexpr-symbol-grid"},ve=["title","disabled","onClick"],ke={class:"sciexpr-symbol-unicode"},ge={class:"sciexpr-symbol-name"},he=["title","disabled","onClick"],we={class:"sciexpr-symbol-unicode"},Be={class:"sciexpr-symbol-name"},Ee=e.defineComponent({__name:"SymbolPanel",props:{disabled:{type:Boolean}},emits:["insert"],setup(t,{emit:a}){const n=a,c=[{id:"greek-lower",label:"Greek Lowercase",symbols:[{latex:"\\alpha",unicode:"α",name:"alpha"},{latex:"\\beta",unicode:"β",name:"beta"},{latex:"\\gamma",unicode:"γ",name:"gamma"},{latex:"\\delta",unicode:"δ",name:"delta"},{latex:"\\epsilon",unicode:"ε",name:"epsilon"},{latex:"\\zeta",unicode:"ζ",name:"zeta"},{latex:"\\eta",unicode:"η",name:"eta"},{latex:"\\theta",unicode:"θ",name:"theta"},{latex:"\\iota",unicode:"ι",name:"iota"},{latex:"\\kappa",unicode:"κ",name:"kappa"},{latex:"\\lambda",unicode:"λ",name:"lambda"},{latex:"\\mu",unicode:"μ",name:"mu"},{latex:"\\nu",unicode:"ν",name:"nu"},{latex:"\\xi",unicode:"ξ",name:"xi"},{latex:"\\pi",unicode:"π",name:"pi"},{latex:"\\rho",unicode:"ρ",name:"rho"},{latex:"\\sigma",unicode:"σ",name:"sigma"},{latex:"\\tau",unicode:"τ",name:"tau"},{latex:"\\phi",unicode:"φ",name:"phi"},{latex:"\\chi",unicode:"χ",name:"chi"},{latex:"\\psi",unicode:"ψ",name:"psi"},{latex:"\\omega",unicode:"ω",name:"omega"}]},{id:"greek-upper",label:"Greek Uppercase",symbols:[{latex:"\\Gamma",unicode:"Γ",name:"Gamma"},{latex:"\\Delta",unicode:"Δ",name:"Delta"},{latex:"\\Theta",unicode:"Θ",name:"Theta"},{latex:"\\Lambda",unicode:"Λ",name:"Lambda"},{latex:"\\Xi",unicode:"Ξ",name:"Xi"},{latex:"\\Pi",unicode:"Π",name:"Pi"},{latex:"\\Sigma",unicode:"Σ",name:"Sigma"},{latex:"\\Upsilon",unicode:"Υ",name:"Upsilon"},{latex:"\\Phi",unicode:"Φ",name:"Phi"},{latex:"\\Psi",unicode:"Ψ",name:"Psi"},{latex:"\\Omega",unicode:"Ω",name:"Omega"}]},{id:"operators",label:"Operators & Relations",symbols:[{latex:"\\times",unicode:"×",name:"times"},{latex:"\\div",unicode:"÷",name:"divide"},{latex:"\\cdot",unicode:"·",name:"dot"},{latex:"\\pm",unicode:"±",name:"plus-minus"},{latex:"\\mp",unicode:"∓",name:"minus-plus"},{latex:"\\leq",unicode:"≤",name:"leq"},{latex:"\\geq",unicode:"≥",name:"geq"},{latex:"\\neq",unicode:"≠",name:"neq"},{latex:"\\approx",unicode:"≈",name:"approx"},{latex:"\\equiv",unicode:"≡",name:"equiv"},{latex:"\\sim",unicode:"∼",name:"sim"},{latex:"\\propto",unicode:"∝",name:"propto"},{latex:"\\ll",unicode:"≪",name:"ll"},{latex:"\\gg",unicode:"≫",name:"gg"}]},{id:"arrows",label:"Arrows",symbols:[{latex:"\\to",unicode:"→",name:"to"},{latex:"\\rightarrow",unicode:"→",name:"rightarrow"},{latex:"\\leftarrow",unicode:"←",name:"leftarrow"},{latex:"\\Rightarrow",unicode:"⇒",name:"Rightarrow"},{latex:"\\Leftarrow",unicode:"⇐",name:"Leftarrow"},{latex:"\\Leftrightarrow",unicode:"⇔",name:"Leftrightarrow"},{latex:"\\mapsto",unicode:"↦",name:"mapsto"},{latex:"\\uparrow",unicode:"↑",name:"uparrow"},{latex:"\\downarrow",unicode:"↓",name:"downarrow"}]},{id:"misc",label:"Misc",symbols:[{latex:"\\infty",unicode:"∞",name:"infinity"},{latex:"\\partial",unicode:"∂",name:"partial"},{latex:"\\nabla",unicode:"∇",name:"nabla"},{latex:"\\forall",unicode:"∀",name:"forall"},{latex:"\\exists",unicode:"∃",name:"exists"},{latex:"\\emptyset",unicode:"∅",name:"emptyset"},{latex:"\\neg",unicode:"¬",name:"neg"},{latex:"\\angle",unicode:"∠",name:"angle"},{latex:"\\triangle",unicode:"△",name:"triangle"},{latex:"\\square",unicode:"□",name:"square"},{latex:"\\circ",unicode:"∘",name:"circle"},{latex:"\\star",unicode:"★",name:"star"}]},{id:"chemistry",label:"Chemistry",symbols:[{latex:"\\ce{H2O}",unicode:"H₂O",name:"Water"},{latex:"\\ce{CO2}",unicode:"CO₂",name:"Carbon dioxide"},{latex:"\\ce{->}",unicode:"→",name:"Arrow right"},{latex:"\\ce{<-}",unicode:"←",name:"Arrow left"},{latex:"\\ce{<=>}",unicode:"⇌",name:"Equilibrium"},{latex:"\\ce{<->}",unicode:"⇄",name:"Resonance"},{latex:"\\ce{->[H2O]}",unicode:"→[H₂O]",name:"With condition"}]}],i=e.ref(c[0].id),m=e.ref(""),s=e.computed(()=>{if(!m.value)return c;const r=m.value.toLowerCase();return c.map(u=>({...u,symbols:u.symbols.filter(l=>l.name.toLowerCase().includes(r)||l.latex.toLowerCase().includes(r))})).filter(u=>u.symbols.length>0)});function o(r){n("insert",r)}return(r,u)=>(e.openBlock(),e.createElementBlock("div",pe,[e.createElementVNode("div",be,[e.withDirectives(e.createElementVNode("input",{"onUpdate:modelValue":u[0]||(u[0]=l=>m.value=l),type:"text",class:"sciexpr-symbol-search-input",placeholder:"Search symbols..."},null,512),[[e.vModelText,m.value]])]),e.createElementVNode("div",fe,[(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(c,l=>e.createElementVNode("button",{key:l.id,class:e.normalizeClass(["sciexpr-symbol-tab",{active:i.value===l.id}]),onClick:p=>i.value=l.id,type:"button"},e.toDisplayString(l.label),11,xe)),64))]),e.createElementVNode("div",ye,[m.value?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:0},e.renderList(s.value,l=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:l.id},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(l.symbols,p=>(e.openBlock(),e.createElementBlock("button",{key:p.latex,class:e.normalizeClass(["sciexpr-symbol-btn",{"sciexpr-symbol-btn-disabled":t.disabled}]),title:`${p.name} — ${p.latex}`,disabled:t.disabled,type:"button",onClick:x=>o(p.latex)},[e.createElementVNode("span",ke,e.toDisplayString(p.unicode),1),e.createElementVNode("span",ge,e.toDisplayString(p.name),1)],10,ve))),128))],64))),128)):(e.openBlock(),e.createElementBlock(e.Fragment,{key:1},e.renderList(c,l=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:l.id},[i.value===l.id?(e.openBlock(!0),e.createElementBlock(e.Fragment,{key:0},e.renderList(l.symbols,p=>(e.openBlock(),e.createElementBlock("button",{key:p.latex,class:e.normalizeClass(["sciexpr-symbol-btn",{"sciexpr-symbol-btn-disabled":t.disabled}]),title:`${p.name} — ${p.latex}`,disabled:t.disabled,type:"button",onClick:x=>o(p.latex)},[e.createElementVNode("span",we,e.toDisplayString(p.unicode),1),e.createElementVNode("span",Be,e.toDisplayString(p.name),1)],10,he))),128)):e.createCommentVNode("",!0)],64))),64))])]))}}),Ce=C(Ee,[["__scopeId","data-v-8a9ec119"]]),Ne={class:"sciexpr-element-grid"},Se=["title","disabled","onClick"],_e={key:0,class:"sciexpr-element-number"},$e={key:1,class:"sciexpr-element-symbol"},M=18,Ie=6,Le=e.defineComponent({__name:"ElementTable",props:{disabled:{type:Boolean},compact:{type:Boolean}},emits:["insert"],setup(t,{emit:a}){const n=a,c=[{symbol:"H",name:"Hydrogen",atomicNumber:1,row:1,col:1,block:"s"},{symbol:"He",name:"Helium",atomicNumber:2,row:1,col:18,block:"s"},{symbol:"Li",name:"Lithium",atomicNumber:3,row:2,col:1,block:"s"},{symbol:"Be",name:"Beryllium",atomicNumber:4,row:2,col:2,block:"s"},{symbol:"B",name:"Boron",atomicNumber:5,row:2,col:13,block:"p"},{symbol:"C",name:"Carbon",atomicNumber:6,row:2,col:14,block:"p"},{symbol:"N",name:"Nitrogen",atomicNumber:7,row:2,col:15,block:"p"},{symbol:"O",name:"Oxygen",atomicNumber:8,row:2,col:16,block:"p"},{symbol:"F",name:"Fluorine",atomicNumber:9,row:2,col:17,block:"p"},{symbol:"Ne",name:"Neon",atomicNumber:10,row:2,col:18,block:"p"},{symbol:"Na",name:"Sodium",atomicNumber:11,row:3,col:1,block:"s"},{symbol:"Mg",name:"Magnesium",atomicNumber:12,row:3,col:2,block:"s"},{symbol:"Al",name:"Aluminium",atomicNumber:13,row:3,col:13,block:"p"},{symbol:"Si",name:"Silicon",atomicNumber:14,row:3,col:14,block:"p"},{symbol:"P",name:"Phosphorus",atomicNumber:15,row:3,col:15,block:"p"},{symbol:"S",name:"Sulfur",atomicNumber:16,row:3,col:16,block:"p"},{symbol:"Cl",name:"Chlorine",atomicNumber:17,row:3,col:17,block:"p"},{symbol:"Ar",name:"Argon",atomicNumber:18,row:3,col:18,block:"p"},{symbol:"K",name:"Potassium",atomicNumber:19,row:4,col:1,block:"s"},{symbol:"Ca",name:"Calcium",atomicNumber:20,row:4,col:2,block:"s"},{symbol:"Cr",name:"Chromium",atomicNumber:24,row:4,col:6,block:"d"},{symbol:"Mn",name:"Manganese",atomicNumber:25,row:4,col:7,block:"d"},{symbol:"Fe",name:"Iron",atomicNumber:26,row:4,col:8,block:"d"},{symbol:"Co",name:"Cobalt",atomicNumber:27,row:4,col:9,block:"d"},{symbol:"Ni",name:"Nickel",atomicNumber:28,row:4,col:10,block:"d"},{symbol:"Cu",name:"Copper",atomicNumber:29,row:4,col:11,block:"d"},{symbol:"Zn",name:"Zinc",atomicNumber:30,row:4,col:12,block:"d"},{symbol:"Br",name:"Bromine",atomicNumber:35,row:4,col:17,block:"p"},{symbol:"Ag",name:"Silver",atomicNumber:47,row:5,col:11,block:"d"},{symbol:"Au",name:"Gold",atomicNumber:79,row:5,col:11,block:"d"},{symbol:"Hg",name:"Mercury",atomicNumber:80,row:5,col:12,block:"d"},{symbol:"I",name:"Iodine",atomicNumber:53,row:5,col:17,block:"p"},{symbol:"Pt",name:"Platinum",atomicNumber:78,row:6,col:10,block:"d"},{symbol:"Pb",name:"Lead",atomicNumber:82,row:6,col:14,block:"p"}],i=e.computed(()=>{const o=[];for(let r=0;r<Ie;r++)o.push(new Array(M).fill(null));for(const r of c)o[r.row-1][r.col-1]=r;return o});function m(o){return{s:"#ff6b6b",p:"#ffd93d",d:"#6bcb77",f:"#4d96ff"}[o]??"#adb5bd"}function s(o){n("insert",o)}return(o,r)=>(e.openBlock(),e.createElementBlock("div",{class:e.normalizeClass(["sciexpr-element-table",{"sciexpr-element-table-compact":t.compact}])},[r[0]||(r[0]=e.createStaticVNode('<div class="sciexpr-element-legend" data-v-a5437c7c><span class="legend-item" data-v-a5437c7c><span class="legend-dot" style="background:#ff6b6b;" data-v-a5437c7c></span> s-block</span><span class="legend-item" data-v-a5437c7c><span class="legend-dot" style="background:#ffd93d;" data-v-a5437c7c></span> p-block</span><span class="legend-item" data-v-a5437c7c><span class="legend-dot" style="background:#6bcb77;" data-v-a5437c7c></span> d-block</span><span class="legend-item" data-v-a5437c7c><span class="legend-dot" style="background:#4d96ff;" data-v-a5437c7c></span> f-block</span></div>',1)),e.createElementVNode("div",Ne,[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(i.value,u=>(e.openBlock(),e.createElementBlock(e.Fragment,{key:i.value.indexOf(u)},[(e.openBlock(!0),e.createElementBlock(e.Fragment,null,e.renderList(u,(l,p)=>e.withDirectives((e.openBlock(),e.createElementBlock("button",{key:p,class:e.normalizeClass(["sciexpr-element-cell",{"sciexpr-element-cell-compact":t.compact,"sciexpr-element-cell-disabled":t.disabled}]),style:e.normalizeStyle(l?{gridRow:l.row,gridColumn:l.col,"--block-color":m(l.block)}:{}),title:l?`${l.name} (${l.atomicNumber})`:"",disabled:t.disabled,type:"button",onClick:x=>l&&s(l.symbol)},[l?(e.openBlock(),e.createElementBlock("span",_e,e.toDisplayString(l.atomicNumber),1)):e.createCommentVNode("",!0),l?(e.openBlock(),e.createElementBlock("span",$e,e.toDisplayString(l.symbol),1)):e.createCommentVNode("",!0)],14,Se)),[[e.vShow,l!==null]])),128)),(e.openBlock(),e.createElementBlock(e.Fragment,null,e.renderList(M,l=>e.withDirectives(e.createElementVNode("div",{key:"empty-"+l,class:"sciexpr-element-cell sciexpr-element-empty",style:e.normalizeStyle({gridRow:i.value.indexOf(u)+1,gridColumn:l})},null,4),[[e.vShow,!u[l-1]]])),64))],64))),128))])],2))}}),Pe=C(Le,[["__scopeId","data-v-a5437c7c"]]);function Me(t){function a(n){for(const c of t){const i=n.key.toLowerCase()===c.key.toLowerCase(),m=!!c.ctrl===(n.ctrlKey||n.metaKey),s=!!c.shift===n.shiftKey,o=!!c.alt===n.altKey;if(i&&m&&s&&o){n.preventDefault(),c.action();return}}}e.onMounted(()=>{window.addEventListener("keydown",a)}),e.onUnmounted(()=>{window.removeEventListener("keydown",a)})}const Te=[{key:"b",ctrl:!0,action:()=>{},description:"Bold (\\mathbf{})"},{key:"/",ctrl:!0,action:()=>{},description:"Fraction (\\frac{}{})"},{key:"s",ctrl:!0,shift:!0,action:()=>{},description:"Square root (\\sqrt{})"},{key:"1",ctrl:!0,action:()=>{},description:"Subscript (_)"},{key:"2",ctrl:!0,action:()=>{},description:"Superscript (^)"}];exports.AI_PIPELINE_KEY=N;exports.AutocompleteDropdown=A;exports.BUILTIN_SHORTCUTS=Te;exports.ElementTable=Pe;exports.Formula=W;exports.FormulaEditor=de;exports.FormulaToolbar=D;exports.LivePreview=F;exports.SymbolPanel=Ce;exports.useAIProvider=R;exports.useAutocomplete=V;exports.useFormula=I;exports.useFormulaEditor=T;exports.useFormulaRender=z;exports.useShortcuts=Me;
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","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","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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"}
|