@eigenpal/docx-js-editor 0.0.20 → 0.0.21
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/{ClipboardManager-EZ0C6Onq.d.cts → ClipboardManager-B1jZrC6h.d.cts} +1 -1
- package/dist/{ClipboardManager-D6dkOFg6.d.ts → ClipboardManager-jqJVxB6g.d.ts} +1 -1
- package/dist/{DocumentAgent-BcCDg7i2.d.ts → DocumentAgent-CnJ9AEl_.d.cts} +31 -3
- package/dist/{DocumentAgent-B0EC8lPC.d.cts → DocumentAgent-CrbsDniO.d.ts} +31 -3
- package/dist/{FindReplaceDialog-AWQXKEUQ.js → FindReplaceDialog-AQFR4OCT.js} +1 -2
- package/dist/FindReplaceDialog-J3DI3U5I.cjs +1 -0
- package/dist/{FootnotePropertiesDialog-73VT2ZVZ.cjs → FootnotePropertiesDialog-DO5DCAW6.cjs} +1 -2
- package/dist/{FootnotePropertiesDialog-ZM3EF3EF.js → FootnotePropertiesDialog-YYIZU5U6.js} +1 -2
- package/dist/{HyperlinkDialog-BA25XUT5.js → HyperlinkDialog-HGZ2S37Z.js} +1 -2
- package/dist/HyperlinkDialog-PEPS3C2G.cjs +1 -0
- package/dist/{ImagePositionDialog-AIAMKPFK.js → ImagePositionDialog-DQ4JWS4F.js} +1 -2
- package/dist/{ImagePositionDialog-KMK7ROV2.cjs → ImagePositionDialog-UYXYHSP4.cjs} +1 -2
- package/dist/{ImagePropertiesDialog-ERFCUVCW.js → ImagePropertiesDialog-GJMGLM6G.js} +1 -2
- package/dist/{ImagePropertiesDialog-USMMRK6X.cjs → ImagePropertiesDialog-V6SVKINO.cjs} +1 -2
- package/dist/{TablePropertiesDialog-72CIUAZT.cjs → TablePropertiesDialog-A36OXG3A.cjs} +1 -2
- package/dist/{TablePropertiesDialog-EMUEVYB3.js → TablePropertiesDialog-STZOGHJB.js} +1 -2
- package/dist/{agentApi-BFVyKagE.d.cts → agentApi-DfsWRyrP.d.cts} +1 -1
- package/dist/{agentApi-BFVyKagE.d.ts → agentApi-DfsWRyrP.d.ts} +1 -1
- package/dist/{chunk-FDANI5P4.cjs → chunk-2VHQ7YOQ.cjs} +1 -2
- package/dist/chunk-2Y6FLZ5Q.js +3 -0
- package/dist/chunk-32HMU2UV.js +111 -0
- package/dist/chunk-4CUGBNL2.cjs +1 -0
- package/dist/chunk-5GFXHUMP.js +1 -0
- package/dist/chunk-6NDMKJIE.js +9 -0
- package/dist/chunk-6NYA53QC.cjs +258 -0
- package/dist/chunk-7KJ3YVDQ.js +10 -0
- package/dist/{chunk-JOYPFQW2.js → chunk-AARNCPWR.js} +1 -2
- package/dist/{chunk-4QT5LPBA.cjs → chunk-B7TICMXD.cjs} +16 -17
- package/dist/{chunk-2QOEHCBX.js → chunk-BUEMG4NW.js} +1 -2
- package/dist/{chunk-CV5WFE7K.js → chunk-CLDB6TL7.js} +2 -3
- package/dist/{chunk-M2T6XKT5.js → chunk-CTYOM6BE.js} +1 -2
- package/dist/chunk-EH3NY2DQ.cjs +26 -0
- package/dist/{chunk-FGVGZLBL.js → chunk-FVUGBRDD.js} +1 -2
- package/dist/chunk-FXJAIFPR.js +59 -0
- package/dist/chunk-GICVJSFJ.cjs +9 -0
- package/dist/{chunk-Y6VCTLCJ.js → chunk-H5NTJZO4.js} +1 -2
- package/dist/chunk-HT2Z33YM.cjs +111 -0
- package/dist/chunk-JRRTZZ72.cjs +1 -0
- package/dist/{chunk-T2HQYRA7.cjs → chunk-NVAQQYBJ.cjs} +1 -2
- package/dist/chunk-P3AEZKQO.cjs +3 -0
- package/dist/{chunk-GWBTKVFD.cjs → chunk-P7ZF45KZ.cjs} +1 -2
- package/dist/{chunk-QEBO3EQP.cjs → chunk-PCJ5ACUV.cjs} +1 -2
- package/dist/{chunk-Q6HUGWO6.js → chunk-PJVI53AH.js} +1 -2
- package/dist/chunk-Q7YYC75E.js +258 -0
- package/dist/{chunk-7JSPKVOW.js → chunk-QVPR2W5S.js} +1 -2
- package/dist/{chunk-XZNOV52K.cjs → chunk-TAF6KYDM.cjs} +4 -5
- package/dist/chunk-USRMBYI6.js +3 -0
- package/dist/chunk-UTWPV2I4.js +26 -0
- package/dist/{chunk-DJAEBZ33.cjs → chunk-VTAS7VZ6.cjs} +1 -2
- package/dist/chunk-XQNCLN4T.cjs +3 -0
- package/dist/{chunk-S26DZVRQ.cjs → chunk-XS2AQFMF.cjs} +1 -2
- package/dist/chunk-Y6QBJGMO.cjs +59 -0
- package/dist/{chunk-WD2HTKRR.cjs → chunk-YS7FDEZ4.cjs} +1 -2
- package/dist/chunk-ZTVQA46Q.js +1 -0
- package/dist/{clipboard-beGtyabO.d.ts → clipboard-BE8E-szx.d.ts} +1 -1
- package/dist/{clipboard-CqE-UZ2d.d.cts → clipboard-DkfAv07F.d.cts} +1 -1
- package/dist/{colorResolver-B5YbO_a4.d.ts → colorResolver-CYttioMe.d.ts} +46 -3
- package/dist/{colorResolver-Cu46bSKr.d.cts → colorResolver-Dr8kQZAQ.d.cts} +46 -3
- package/dist/core-plugins-reexport.cjs +1 -2
- package/dist/core-plugins-reexport.d.cts +4 -4
- package/dist/core-plugins-reexport.d.ts +4 -4
- package/dist/core-plugins-reexport.js +1 -2
- package/dist/core-reexport.cjs +1 -2
- package/dist/core-reexport.d.cts +10 -10
- package/dist/core-reexport.d.ts +10 -10
- package/dist/core-reexport.js +1 -2
- package/dist/executor-JGWZ7S6Z.cjs +1 -0
- package/dist/executor-L2MVKMXO.js +1 -0
- package/dist/{fontLoader-CFKpg0Ri.d.ts → fontLoader-BsqQnB4v.d.ts} +1 -1
- package/dist/{fontLoader-HZYfILUm.d.cts → fontLoader-DECXIoMr.d.cts} +1 -1
- package/dist/headless-reexport.cjs +4 -5
- package/dist/headless-reexport.d.cts +7 -7
- package/dist/headless-reexport.d.ts +7 -7
- package/dist/headless-reexport.js +4 -5
- package/dist/index.cjs +6 -7
- package/dist/index.css +0 -1
- package/dist/index.d.cts +12 -12
- package/dist/index.d.ts +12 -12
- package/dist/index.js +6 -7
- package/dist/lib-GD2QD2JK.js +1 -0
- package/dist/lib-HOLGQI5K.cjs +1 -0
- package/dist/mcp-reexport.cjs +9 -10
- package/dist/mcp-reexport.d.cts +2 -2
- package/dist/mcp-reexport.d.ts +2 -2
- package/dist/mcp-reexport.js +4 -5
- package/dist/{processTemplate-G37IM66O.js → processTemplate-3HN7Q3KT.js} +1 -2
- package/dist/processTemplate-BXZKWRQD.cjs +1 -0
- package/dist/{react-BjOCdeTs.d.ts → react-C6bgHDFl.d.ts} +8 -6
- package/dist/{react-UzAn4o7l.d.cts → react-CAlVCYa4.d.cts} +8 -6
- package/dist/react.cjs +1 -2
- package/dist/react.css +0 -1
- package/dist/react.d.cts +5 -5
- package/dist/react.d.ts +5 -5
- package/dist/react.js +1 -2
- package/dist/{registry-DjacfR6Q.d.cts → registry-BU-FbHh-.d.cts} +1 -1
- package/dist/{registry-CV6nYWqP.d.ts → registry-gRbkCooh.d.ts} +1 -1
- package/dist/selectionRects-7QU337P5.cjs +1 -0
- package/dist/selectionRects-V5RC2BYX.js +1 -0
- package/dist/styles.css +1 -1
- package/dist/{types-DwZ3xysp.d.ts → types-7wjInVMW.d.ts} +1 -1
- package/dist/{types-Bnp8rvJn.d.cts → types-DEEpBL9H.d.cts} +1 -1
- package/dist/ui.cjs +1 -2
- package/dist/ui.d.cts +32 -85
- package/dist/ui.d.ts +32 -85
- package/dist/ui.js +1 -2
- package/dist/{variableDetector-CMhJtM96.d.cts → variableDetector-B4oQJa2e.d.cts} +33 -2
- package/dist/{variableDetector-BaDeXz7D.d.ts → variableDetector-BXJaTkiB.d.ts} +33 -2
- package/package.json +1 -1
- package/dist/FindReplaceDialog-AWQXKEUQ.js.map +0 -1
- package/dist/FindReplaceDialog-I4SZDSVP.cjs +0 -2
- package/dist/FindReplaceDialog-I4SZDSVP.cjs.map +0 -1
- package/dist/FootnotePropertiesDialog-73VT2ZVZ.cjs.map +0 -1
- package/dist/FootnotePropertiesDialog-ZM3EF3EF.js.map +0 -1
- package/dist/HyperlinkDialog-BA25XUT5.js.map +0 -1
- package/dist/HyperlinkDialog-V63LPOT2.cjs +0 -2
- package/dist/HyperlinkDialog-V63LPOT2.cjs.map +0 -1
- package/dist/ImagePositionDialog-AIAMKPFK.js.map +0 -1
- package/dist/ImagePositionDialog-KMK7ROV2.cjs.map +0 -1
- package/dist/ImagePropertiesDialog-ERFCUVCW.js.map +0 -1
- package/dist/ImagePropertiesDialog-USMMRK6X.cjs.map +0 -1
- package/dist/TablePropertiesDialog-72CIUAZT.cjs.map +0 -1
- package/dist/TablePropertiesDialog-EMUEVYB3.js.map +0 -1
- package/dist/chunk-2CHPKB5A.cjs +0 -112
- package/dist/chunk-2CHPKB5A.cjs.map +0 -1
- package/dist/chunk-2QOEHCBX.js.map +0 -1
- package/dist/chunk-4QT5LPBA.cjs.map +0 -1
- package/dist/chunk-5DYSI4O4.cjs +0 -60
- package/dist/chunk-5DYSI4O4.cjs.map +0 -1
- package/dist/chunk-5FJXHXFV.cjs +0 -2
- package/dist/chunk-5FJXHXFV.cjs.map +0 -1
- package/dist/chunk-6FEWNF6B.js +0 -4
- package/dist/chunk-6FEWNF6B.js.map +0 -1
- package/dist/chunk-6LF5HZCV.js +0 -10
- package/dist/chunk-6LF5HZCV.js.map +0 -1
- package/dist/chunk-7JSPKVOW.js.map +0 -1
- package/dist/chunk-C33XDRDJ.cjs +0 -28
- package/dist/chunk-C33XDRDJ.cjs.map +0 -1
- package/dist/chunk-CV5WFE7K.js.map +0 -1
- package/dist/chunk-CXJRNISO.js +0 -2
- package/dist/chunk-CXJRNISO.js.map +0 -1
- package/dist/chunk-DJAEBZ33.cjs.map +0 -1
- package/dist/chunk-DP6Q75ZD.js +0 -28
- package/dist/chunk-DP6Q75ZD.js.map +0 -1
- package/dist/chunk-FDANI5P4.cjs.map +0 -1
- package/dist/chunk-FGVGZLBL.js.map +0 -1
- package/dist/chunk-GJ4GKSDU.cjs +0 -2
- package/dist/chunk-GJ4GKSDU.cjs.map +0 -1
- package/dist/chunk-GWBTKVFD.cjs.map +0 -1
- package/dist/chunk-JOYPFQW2.js.map +0 -1
- package/dist/chunk-L54YNLSE.js +0 -2
- package/dist/chunk-L54YNLSE.js.map +0 -1
- package/dist/chunk-LPGMLJMO.js +0 -259
- package/dist/chunk-LPGMLJMO.js.map +0 -1
- package/dist/chunk-M2T6XKT5.js.map +0 -1
- package/dist/chunk-OHG7ROFC.js +0 -11
- package/dist/chunk-OHG7ROFC.js.map +0 -1
- package/dist/chunk-PANKMCFX.cjs +0 -4
- package/dist/chunk-PANKMCFX.cjs.map +0 -1
- package/dist/chunk-Q6HUGWO6.js.map +0 -1
- package/dist/chunk-QDV75OJ4.js +0 -112
- package/dist/chunk-QDV75OJ4.js.map +0 -1
- package/dist/chunk-QEBO3EQP.cjs.map +0 -1
- package/dist/chunk-QVIZ775M.cjs +0 -259
- package/dist/chunk-QVIZ775M.cjs.map +0 -1
- package/dist/chunk-RMUMR42R.cjs +0 -10
- package/dist/chunk-RMUMR42R.cjs.map +0 -1
- package/dist/chunk-S26DZVRQ.cjs.map +0 -1
- package/dist/chunk-T2HQYRA7.cjs.map +0 -1
- package/dist/chunk-ULXNEG66.js +0 -60
- package/dist/chunk-ULXNEG66.js.map +0 -1
- package/dist/chunk-WD2HTKRR.cjs.map +0 -1
- package/dist/chunk-XZNOV52K.cjs.map +0 -1
- package/dist/chunk-Y6VCTLCJ.js.map +0 -1
- package/dist/core-plugins-reexport.cjs.map +0 -1
- package/dist/core-plugins-reexport.js.map +0 -1
- package/dist/core-reexport.cjs.map +0 -1
- package/dist/core-reexport.js.map +0 -1
- package/dist/executor-K5RXUTTR.js +0 -2
- package/dist/executor-K5RXUTTR.js.map +0 -1
- package/dist/executor-XIPIU3H4.cjs +0 -2
- package/dist/executor-XIPIU3H4.cjs.map +0 -1
- package/dist/headless-reexport.cjs.map +0 -1
- package/dist/headless-reexport.js.map +0 -1
- package/dist/index.cjs.map +0 -1
- package/dist/index.css.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp-reexport.cjs.map +0 -1
- package/dist/mcp-reexport.js.map +0 -1
- package/dist/processTemplate-G37IM66O.js.map +0 -1
- package/dist/processTemplate-RFBGVH7T.cjs +0 -2
- package/dist/processTemplate-RFBGVH7T.cjs.map +0 -1
- package/dist/react.cjs.map +0 -1
- package/dist/react.css.map +0 -1
- package/dist/react.js.map +0 -1
- package/dist/selectionRects-6DU7HN7E.js +0 -2
- package/dist/selectionRects-6DU7HN7E.js.map +0 -1
- package/dist/selectionRects-YZSC24ZP.cjs +0 -2
- package/dist/selectionRects-YZSC24ZP.cjs.map +0 -1
- package/dist/ui.cjs.map +0 -1
- package/dist/ui.js.map +0 -1
package/dist/chunk-5FJXHXFV.cjs
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
'use strict';var ue={calibri:{googleFont:"Carlito",category:"sans-serif",fallbackStack:["Calibri","Carlito","Arial","Helvetica","sans-serif"],singleLineRatio:1.2207},cambria:{googleFont:"Caladea",category:"serif",fallbackStack:["Cambria","Caladea","Georgia","serif"],singleLineRatio:1.2676},arial:{googleFont:"Arimo",category:"sans-serif",fallbackStack:["Arial","Arimo","Helvetica","sans-serif"],singleLineRatio:1.1499},"times new roman":{googleFont:"Tinos",category:"serif",fallbackStack:["Times New Roman","Tinos","Times","serif"],singleLineRatio:1.1499},"courier new":{googleFont:"Cousine",category:"monospace",fallbackStack:["Courier New","Cousine","Courier","monospace"],singleLineRatio:1.1328},georgia:{googleFont:"Tinos",category:"serif",fallbackStack:["Georgia","Tinos","Times New Roman","serif"],singleLineRatio:1.1362},verdana:{googleFont:"Open Sans",category:"sans-serif",fallbackStack:["Verdana","Open Sans","Arial","sans-serif"],singleLineRatio:1.2153},tahoma:{googleFont:"Open Sans",category:"sans-serif",fallbackStack:["Tahoma","Open Sans","Arial","sans-serif"],singleLineRatio:1.2075},"trebuchet ms":{googleFont:"Fira Sans",category:"sans-serif",fallbackStack:["Trebuchet MS","Fira Sans","Arial","sans-serif"],singleLineRatio:1.1431},"comic sans ms":{googleFont:"Comic Neue",category:"cursive",fallbackStack:["Comic Sans MS","Comic Neue","cursive"],singleLineRatio:1.3936},impact:{googleFont:"Anton",category:"sans-serif",fallbackStack:["Impact","Anton","Arial Black","sans-serif"],singleLineRatio:1.2197},"palatino linotype":{googleFont:"EB Garamond",category:"serif",fallbackStack:["Palatino Linotype","EB Garamond","Palatino","Georgia","serif"],singleLineRatio:1.0259},"book antiqua":{googleFont:"EB Garamond",category:"serif",fallbackStack:["Book Antiqua","EB Garamond","Palatino","Georgia","serif"],singleLineRatio:1.0259},garamond:{googleFont:"EB Garamond",category:"serif",fallbackStack:["Garamond","EB Garamond","Georgia","serif"],singleLineRatio:1.068},"century gothic":{googleFont:"Questrial",category:"sans-serif",fallbackStack:["Century Gothic","Questrial","Arial","sans-serif"],singleLineRatio:1.1611},"lucida sans":{googleFont:"Open Sans",category:"sans-serif",fallbackStack:["Lucida Sans","Open Sans","Arial","sans-serif"],singleLineRatio:1.1655},"lucida console":{googleFont:"Cousine",category:"monospace",fallbackStack:["Lucida Console","Cousine","Courier New","monospace"],singleLineRatio:1.1387},consolas:{googleFont:"Inconsolata",category:"monospace",fallbackStack:["Consolas","Inconsolata","Cousine","Courier New","monospace"],singleLineRatio:1.1626},"ms mincho":{googleFont:"Noto Serif JP",category:"serif",fallbackStack:["MS Mincho","Noto Serif JP","serif"],singleLineRatio:1.15},"ms gothic":{googleFont:"Noto Sans JP",category:"sans-serif",fallbackStack:["MS Gothic","Noto Sans JP","sans-serif"],singleLineRatio:1.15},simhei:{googleFont:"Noto Sans SC",category:"sans-serif",fallbackStack:["SimHei","Noto Sans SC","sans-serif"],singleLineRatio:1.15},simsun:{googleFont:"Noto Serif SC",category:"serif",fallbackStack:["SimSun","Noto Serif SC","serif"],singleLineRatio:1.15},"malgun gothic":{googleFont:"Noto Sans KR",category:"sans-serif",fallbackStack:["Malgun Gothic","Noto Sans KR","sans-serif"],singleLineRatio:1.15}},ge={"sans-serif":"Arial, Helvetica, sans-serif",serif:"Times New Roman, Times, serif",monospace:"Courier New, Courier, monospace",cursive:"cursive",fantasy:"fantasy","system-ui":"system-ui, sans-serif"};function fe(n){let e=n.toLowerCase();return e.includes("mono")||e.includes("courier")||e.includes("consolas")||e.includes("console")||e.includes("code")||e.includes("terminal")?"monospace":e.includes("times")||e.includes("georgia")||e.includes("garamond")||e.includes("palatino")||e.includes("baskerville")||e.includes("bodoni")||e.includes("cambria")||e.includes("mincho")||e.includes("ming")||e.includes("song")||e.includes("serif")?"serif":e.includes("script")||e.includes("cursive")||e.includes("comic")||e.includes("brush")||e.includes("hand")?"cursive":"sans-serif"}function Q(n){let e=n.trim().toLowerCase(),a=ue[e];if(a)return {googleFont:a.googleFont,cssFallback:a.fallbackStack.map(K).join(", "),originalFont:n,hasGoogleEquivalent:true,singleLineRatio:a.singleLineRatio};let t=fe(n),r=ge[t];return {googleFont:null,cssFallback:`${K(n)}, ${r}`,originalFont:n,hasGoogleEquivalent:false,singleLineRatio:1.15}}function K(n){return ["serif","sans-serif","monospace","cursive","fantasy","system-ui"].includes(n.toLowerCase())?n:/[\s,'"()]/.test(n)?`"${n.replace(/"/g,'\\"')}"`:n}function Fe(n,e){if(!e)return null;let t=n.toLowerCase().startsWith("major")?e.majorFont:e.minorFont;if(!t)return null;let r=n.toLowerCase();return r.includes("eastasia")||r.includes("ea")?t.ea??t.latin??null:r.includes("cs")||r.includes("bidi")?t.cs??t.latin??null:t.latin??null}var Z=96,ee=11,ne="Calibri",he=1.15,de=.8,pe=.2,A=null;function X(){if(!A){let n=typeof document<"u"?document.createElement("canvas"):null;if(!n)throw new Error("Canvas not available. Ensure this runs in a DOM environment.");if(A=n.getContext("2d"),!A)throw new Error("Failed to get 2D context from canvas")}return A}function we(){A=null;}var V=new Map;function te(n){let e=V.get(n);if(e===void 0){let a=Q(n);e={cssFallback:a.cssFallback,singleLineRatio:a.singleLineRatio},V.set(n,e);}return e}function be(n){return te(n).cssFallback}function U(n){let e=[];n.italic&&e.push("italic"),n.bold&&e.push("bold");let a=n.fontSize??ee,t=oe(a);e.push(`${t}px`);let r=n.fontFamily??ne;return e.push(be(r)),e.join(" ")}function xe(n){let e=n.fontSize??ee,a=n.fontFamily??ne,t=oe(e),r=t*de,o=t*pe,c=t*he;try{let s=X();s.font=U(n);let g=s.measureText("Hg");typeof g.actualBoundingBoxAscent=="number"&&typeof g.actualBoundingBoxDescent=="number"&&(r=g.actualBoundingBoxAscent,o=g.actualBoundingBoxDescent);}catch{}c=Math.max(c,r+o);let i=te(a).singleLineRatio;return {fontSize:e,ascent:r,descent:o,lineHeight:c,fontFamily:a,singleLineRatio:i}}function Me(n,e){if(!n)return 0;let a=X();a.font=U(e);let r=a.measureText(n).width;return e.letterSpacing&&n.length>1&&(r+=e.letterSpacing*(n.length-1)),r}function W(n,e){let a=xe(e);if(!n)return {width:0,charWidths:[],metrics:a};let t=X();t.font=U(e);let r=e.letterSpacing??0,o=[],c=0;for(let i=0;i<n.length;i++){let s=n[i],h=t.measureText(s).width;r&&i<n.length-1&&(h+=r),o.push(h),c+=h;}return {width:c,charWidths:o,metrics:a}}function Te(n,e){if(e.length===0||n<=0)return 0;let a=0;for(let t=0;t<e.length;t++){let r=e[t],o=a+r/2;if(n<=o)return t;a+=r;}return e.length}function oe(n){return n*Z/72}function q(n,e){let a=n.pageGap??0,t=0;for(let r=0;r<e&&r<n.pages.length;r++){let c=n.pages[r].size?.h??n.pageSize.h;t+=c+a;}return t}function ae(n,e){return n.findIndex(a=>a.id===e)}function ke(n,e){let a=0;for(let t=n.fromLine;t<n.toLine&&t<e.lines.length;t++)a+=e.lines[t].lineHeight;return a}function Ie(n,e,a,t){let r=[...n.page.fragments].sort((o,c)=>{let i=o.y-c.y;return Math.abs(i)>.5?i:o.x-c.x});for(let o of r){let c=ae(e,o.blockId);if(c===-1)continue;let i=e[c],s=a[c];if(!i||!s)continue;let g;if(o.kind==="paragraph"){if(i.kind!=="paragraph"||s.kind!=="paragraph")continue;g=ke(o,s);}else if(o.kind==="table")g=o.height;else if(o.kind==="image")g=o.height;else continue;let h=t.x>=o.x&&t.x<=o.x+o.width,l=t.y>=o.y&&t.y<=o.y+g;if(h&&l)return {fragment:o,block:i,measure:s,pageIndex:n.pageIndex,localX:t.x-o.x,localY:t.y-o.y}}return null}function Ce(n,e,a,t){for(let r of n.page.fragments){if(r.kind!=="table")continue;let o=r,c=t.x>=o.x&&t.x<=o.x+o.width,i=t.y>=o.y&&t.y<=o.y+o.height;if(!c||!i)continue;let s=ae(e,o.blockId);if(s===-1)continue;let g=e[s],h=a[s];if(!g||g.kind!=="table"||!h||h.kind!=="table")continue;let l=g,f=h,d=t.x-o.x,F=t.y-o.y,x=0,p=-1;if(f.rows.length===0||l.rows.length===0)continue;for(let u=o.fromRow;u<o.toRow&&u<f.rows.length;u++){let L=f.rows[u];if(F>=x&&F<x+L.height){p=u;break}x+=L.height;}if(p===-1&&(p=Math.min(o.toRow-1,f.rows.length-1),p<o.fromRow))continue;let m=f.rows[p],S=l.rows[p];if(!m||!S)continue;let b=0,k=-1;if(m.cells.length===0||S.cells.length===0)continue;for(let u=0;u<m.cells.length;u++){let L=m.cells[u];if(d>=b&&d<b+L.width){k=u;break}b+=L.width;}if(k===-1&&(k=m.cells.length-1,k<0))continue;let y=m.cells[k],R=S.cells[k];if(!y||!R)continue;let w=0;for(let u=o.fromRow;u<p;u++)w+=f.rows[u]?.height??0;let I=0;for(let u=0;u<k;u++)I+=m.cells[u]?.width??0;let T,M;if(R.blocks&&R.blocks.length>0){let u=R.blocks[0],L=y.blocks[0];u.kind==="paragraph"&&L?.kind==="paragraph"&&(T=u,M=L);}let C=d-I,B=F-w;return {fragment:o,block:l,measure:f,pageIndex:n.pageIndex,rowIndex:p,colIndex:k,cellBlock:T,cellMeasure:M,cellLocalX:Math.max(0,C),cellLocalY:Math.max(0,B)}}return null}function re(n){return {fontFamily:n.fontFamily??"Arial",fontSize:n.fontSize??12,bold:n.bold,italic:n.italic,letterSpacing:n.letterSpacing}}function j(n,e){return n.findIndex(a=>a.id===e)}function G(n,e){let t=(n.pmStart??0)+1,r=0,o;for(let s=0;s<n.runs.length&&s<=e.toRun;s++){let g=n.runs[s];if(g){if(s<e.fromRun)g.kind==="text"?r+=(g.text??"").length:r+=1;else if(s===e.fromRun){r+=e.fromChar,o=t+r;break}}}o===void 0&&(o=t);let c=0;for(let s=e.fromRun;s<=e.toRun&&s<n.runs.length;s++){let g=n.runs[s];if(g)if(g.kind==="text"){let h=g.text??"",l=s===e.fromRun?e.fromChar:0,f=s===e.toRun?e.toChar:h.length;c+=f-l;}else c+=1;}let i=o+c;return {pmStart:o,pmEnd:i}}function ie(n,e,a,t){let r=[];for(let o=0;o<e.lines.length;o++){let c=e.lines[o],i=G(n,c);i.pmStart===void 0||i.pmEnd===void 0||i.pmEnd>a&&i.pmStart<t&&r.push({line:c,index:o});}return r}function v(n,e,a){let t=G(n,e);return t.pmStart===void 0?0:Math.max(0,a-t.pmStart)}function _(n,e,a,t){let r=0,o=0;for(let c=e.fromRun;c<=e.toRun&&c<n.runs.length;c++){let i=n.runs[c];if(i){if(i.kind==="tab"){let s=i.width??48;if(o+1>=a)return a<=o?r:r+s;r+=s,o+=1;continue}if(i.kind==="image"){let s=i.width;if(o+1>=a)return a<=o?r:r+s;r+=s,o+=1;continue}if(i.kind==="lineBreak"){if(a<=o)return r;o+=1;continue}if(i.kind==="text"){let s=i.text??"",g=c===e.fromRun,h=c===e.toRun,l=g?e.fromChar:0,f=h?e.toChar:s.length,d=s.slice(l,f);if(o+d.length>=a){let p=a-o,m=re(i),S=W(d.slice(0,p),m);return r+S.width}let F=re(i),x=W(d,F);r+=x.width,o+=d.length;}}}return r}function N(n,e){let a=0;for(let t=0;t<e&&t<n.lines.length;t++)a+=n.lines[t].lineHeight;return a}function He(n,e,a,t,r){if(t===r)return [];let o=Math.min(t,r),c=Math.max(t,r),i=[];for(let s=0;s<n.pages.length;s++){let g=n.pages[s],h=q(n,s);for(let l of g.fragments){if(l.kind==="paragraph"){let f=j(e,l.blockId);if(f===-1)continue;let d=e[f],F=a[f];if(!d||d.kind!=="paragraph"||!F||F.kind!=="paragraph")continue;let x=d,p=F,m=l,S=ie(x,p,o,c);for(let{line:b,index:k}of S){if(k<m.fromLine||k>=m.toLine)continue;let y=G(x,b);if(y.pmStart===void 0||y.pmEnd===void 0)continue;let R=Math.max(y.pmStart,o),w=Math.min(y.pmEnd,c);if(R>=w)continue;let I=v(x,b,R),T=v(x,b,w),M=x.attrs?.indent,C=M?.left??0,B=M?.right??0,u=Math.max(0,l.width-C-B),L=_(x,b,I),z=_(x,b,T),H=x.attrs?.alignment??"left",P=0;H==="center"?P=Math.max(0,(u-b.width)/2):H==="right"&&(P=Math.max(0,u-b.width));let D=N(p,k)-N(p,m.fromLine),E=l.x+C+P+Math.min(L,z),O=Math.max(1,Math.abs(z-L)),Y=l.y+D;i.push({x:E,y:Y+h,width:O,height:b.lineHeight,pageIndex:s});}}if(l.kind==="table"){let f=j(e,l.blockId);if(f===-1)continue;let d=e[f],F=a[f];if(!d||d.kind!=="table"||!F||F.kind!=="table")continue;let x=d,p=F,m=l,S=0;for(let b=m.fromRow;b<m.toRow&&b<x.rows.length;b++){let k=x.rows[b],y=p.rows[b];if(!k||!y)continue;let R=0;for(let w=0;w<k.cells.length;w++){let I=k.cells[w],T=y.cells[w];if(!(!I||!T)){for(let M=0;M<I.blocks.length;M++){let C=I.blocks[M],B=T.blocks[M];if(!C||C.kind!=="paragraph"||!B||B.kind!=="paragraph")continue;let u=C,L=B,z=ie(u,L,o,c),H=0;for(let{line:P,index:D}of z){let E=G(u,P);if(E.pmStart===void 0||E.pmEnd===void 0)continue;let O=Math.max(E.pmStart,o),Y=Math.min(E.pmEnd,c);if(O>=Y)continue;let se=v(u,P,O),ce=v(u,P,Y),J=_(u,P,se,T.width),$=_(u,P,ce,T.width),le=N(L,D);i.push({x:m.x+R+Math.min(J,$),y:m.y+S+H+le+h,width:Math.max(1,Math.abs($-J)),height:P.lineHeight,pageIndex:s});}H+=L.totalHeight;}R+=T.width;}}S+=y.height;}}if(l.kind==="image"){let f=l.pmStart??0;(l.pmEnd??f+1)>o&&f<c&&i.push({x:l.x,y:l.y+h,width:l.width,height:l.height,pageIndex:s});}}}return i}function Ae(n,e,a,t){for(let r=0;r<n.pages.length;r++){let o=n.pages[r],c=q(n,r);for(let i of o.fragments){if(i.kind==="paragraph"){let s=j(e,i.blockId);if(s===-1)continue;let g=e[s],h=a[s];if(!g||g.kind!=="paragraph"||!h||h.kind!=="paragraph")continue;let l=g,f=h,d=i,F=l.pmStart??0,x=l.pmEnd??F;if(t<F||t>x)continue;for(let p=d.fromLine;p<d.toLine;p++){let m=f.lines[p];if(!m)continue;let S=G(l,m);if(!(S.pmStart===void 0||S.pmEnd===void 0)&&t>=S.pmStart&&t<=S.pmEnd){let b=v(l,m,t),k=l.attrs?.indent,y=k?.left??0,R=k?.right??0,w=Math.max(0,i.width-y-R),I=_(l,m,b),T=l.attrs?.alignment??"left",M=0;T==="center"?M=Math.max(0,(w-m.width)/2):T==="right"&&(M=Math.max(0,w-m.width));let C=N(f,p)-N(f,d.fromLine);return {x:i.x+y+M+I,y:i.y+C+c,height:m.lineHeight,pageIndex:r}}}}if(i.kind==="image"){let s=i.pmStart??0,g=i.pmEnd??s+1;if(t>=s&&t<=g){let h=t===s?0:i.width;return {x:i.x+h,y:i.y+c,height:i.height,pageIndex:r}}}}}return null}function ve(n){return n.length<=1?false:new Set(n.map(a=>a.pageIndex)).size>1}function _e(n){let e=new Map;for(let a of n){let t=e.get(a.pageIndex)??[];t.push(a),e.set(a.pageIndex,t);}return e}exports.a=Q;exports.b=Fe;exports.c=we;exports.d=xe;exports.e=Me;exports.f=W;exports.g=Te;exports.h=oe;exports.i=Ie;exports.j=Ce;exports.k=He;exports.l=Ae;exports.m=ve;exports.n=_e;//# sourceMappingURL=chunk-5FJXHXFV.cjs.map
|
|
2
|
-
//# sourceMappingURL=chunk-5FJXHXFV.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../core/src/utils/fontResolver.ts","../../core/src/layout-bridge/measuring/measureContainer.ts","../../core/src/layout-bridge/hitTest.ts","../../core/src/layout-bridge/selectionRects.ts"],"names":["FONT_MAPPINGS","DEFAULT_FALLBACKS","detectFontCategory","fontName","lower","resolveFontFamily","docxFontName","normalizedName","mapping","quoteFontName","category","defaultFallback","resolveThemeFont","themeRef","fontScheme","themeFont","ref","PX_PER_INCH","DEFAULT_FONT_SIZE","DEFAULT_FONT_FAMILY","DEFAULT_LINE_HEIGHT_MULTIPLIER","DEFAULT_ASCENT_RATIO","DEFAULT_DESCENT_RATIO","canvasContext","getCanvasContext","canvas","resetCanvasContext","fontResolvedCache","getResolvedData","fontFamily","cached","resolved","getResolvedFallback","buildFontString","style","parts","fontSizePt","fontSizePx","ptToPx","getFontMetrics","fontSize","ascent","descent","lineHeight","ctx","metrics","singleLineRatio","measureTextWidth","text","width","measureRun","letterSpacing","charWidths","totalWidth","char","charWidth","findCharacterAtX","x","accumulatedWidth","i","charMidpoint","pt","getPageTop","layout","pageIndex","pageGap","y","pageHeight","findBlockIndexById","blocks","blockId","block","calculateParagraphFragmentHeight","fragment","measure","height","hitTestFragment","pageHit","measures","pagePoint","sortedFragments","a","b","dy","blockIndex","fragmentHeight","withinX","withinY","hitTestTableCell","tableFragment","tableBlock","tableMeasure","localX","localY","rowY","rowIndex","r","rowMeasure","row","colX","colIndex","c","cellMeasure","cell","rowTop","colLeft","cellBlock","cellBlockMeasure","firstBlock","firstMeasure","cellLocalX","cellLocalY","runToFontStyle","run","findBlockById","computeLinePmRange","line","contentStart","charOffset","pmStart","runIndex","lineLength","start","end","pmEnd","findLinesInRange","from","to","result","range","pmPosToCharOffset","pmPos","charOffsetToX","_availableWidth","charsProcessed","tabWidth","imageWidth","isFirstRun","isLastRun","lineText","charInRun","measurement","lineHeightBefore","lineIndex","selectionToRects","selFrom","selTo","rects","page","pageTopY","paragraphBlock","paragraphMeasure","paragraphFragment","intersectingLines","index","sliceFrom","sliceTo","charOffsetFrom","charOffsetTo","indent","indentLeft","indentRight","availableWidth","startX","endX","alignment","alignmentOffset","lineOffset","rectX","rectWidth","rectY","cellX","cellIndex","blockIdx","blockY","lineY","blockPmStart","getCaretPosition","pmPosition","blockPmEnd","fragPmStart","fragPmEnd","xOffset","isMultiPageSelection","groupRectsByPage","map","rect","pageRects"],"mappings":"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","file":"chunk-5FJXHXFV.cjs","sourcesContent":["/**\n * Font Family Resolver\n *\n * Maps DOCX font names to Google Fonts equivalents with proper CSS fallback stacks.\n *\n * DOCX files often use fonts that aren't freely available (Calibri, Cambria, etc.)\n * This module provides mappings to metrically-compatible Google Fonts alternatives.\n */\n\nimport type { ThemeFontScheme, ThemeFont } from '../types';\n\n/**\n * Result of resolving a font family\n */\nexport interface ResolvedFont {\n /** Google Font name to load (null if no mapping available) */\n googleFont: string | null;\n /** CSS font-family value with proper fallback stack */\n cssFallback: string;\n /** Original font name from the DOCX */\n originalFont: string;\n /** Whether this font has a Google Fonts equivalent */\n hasGoogleEquivalent: boolean;\n /** OS/2 single-line ratio: (usWinAscent + usWinDescent + externalLeading) / unitsPerEm */\n singleLineRatio: number;\n}\n\n/**\n * Font category for fallback selection\n */\ntype FontCategory = 'sans-serif' | 'serif' | 'monospace' | 'cursive' | 'fantasy' | 'system-ui';\n\n/**\n * Font mapping entry\n */\ninterface FontMapping {\n googleFont: string;\n category: FontCategory;\n fallbackStack: string[];\n /** OS/2 single-line ratio: (usWinAscent + usWinDescent + externalLeading) / unitsPerEm */\n singleLineRatio: number;\n}\n\n/**\n * Default OS/2 single-line ratio for unmapped fonts.\n * Middle of the common range (1.07–1.27) for standard DOCX fonts.\n */\nexport const DEFAULT_SINGLE_LINE_RATIO = 1.15;\n\n/**\n * Mapping of common DOCX fonts to Google Fonts equivalents\n *\n * These are metrically compatible fonts that preserve document layout.\n * See: https://wiki.archlinux.org/title/Metric-compatible_fonts\n *\n * singleLineRatio values are derived from each font's OS/2 table:\n * (usWinAscent + usWinDescent + externalLeading) / unitsPerEm\n * These define the Windows GDI \"single line\" height that OOXML lineRule=\"auto\" uses.\n */\nconst FONT_MAPPINGS: Record<string, FontMapping> = {\n // Microsoft Office fonts -> Google equivalents (via Croscore)\n calibri: {\n googleFont: 'Carlito',\n category: 'sans-serif',\n fallbackStack: ['Calibri', 'Carlito', 'Arial', 'Helvetica', 'sans-serif'],\n singleLineRatio: 1.2207, // 2500/2048\n },\n cambria: {\n googleFont: 'Caladea',\n category: 'serif',\n fallbackStack: ['Cambria', 'Caladea', 'Georgia', 'serif'],\n singleLineRatio: 1.2676, // 2596/2048\n },\n arial: {\n googleFont: 'Arimo',\n category: 'sans-serif',\n fallbackStack: ['Arial', 'Arimo', 'Helvetica', 'sans-serif'],\n singleLineRatio: 1.1499, // 2355/2048\n },\n 'times new roman': {\n googleFont: 'Tinos',\n category: 'serif',\n fallbackStack: ['Times New Roman', 'Tinos', 'Times', 'serif'],\n singleLineRatio: 1.1499, // 2355/2048\n },\n 'courier new': {\n googleFont: 'Cousine',\n category: 'monospace',\n fallbackStack: ['Courier New', 'Cousine', 'Courier', 'monospace'],\n singleLineRatio: 1.1328, // 2320/2048\n },\n\n // Additional common fonts\n georgia: {\n googleFont: 'Tinos', // Similar but not perfect match\n category: 'serif',\n fallbackStack: ['Georgia', 'Tinos', 'Times New Roman', 'serif'],\n singleLineRatio: 1.1362, // 2327/2048\n },\n verdana: {\n googleFont: 'Open Sans', // Similar sans-serif\n category: 'sans-serif',\n fallbackStack: ['Verdana', 'Open Sans', 'Arial', 'sans-serif'],\n singleLineRatio: 1.2153, // 2489/2048\n },\n tahoma: {\n googleFont: 'Open Sans',\n category: 'sans-serif',\n fallbackStack: ['Tahoma', 'Open Sans', 'Arial', 'sans-serif'],\n singleLineRatio: 1.2075, // 2472/2048\n },\n 'trebuchet ms': {\n googleFont: 'Fira Sans',\n category: 'sans-serif',\n fallbackStack: ['Trebuchet MS', 'Fira Sans', 'Arial', 'sans-serif'],\n singleLineRatio: 1.1431, // 2341/2048\n },\n 'comic sans ms': {\n googleFont: 'Comic Neue',\n category: 'cursive',\n fallbackStack: ['Comic Sans MS', 'Comic Neue', 'cursive'],\n singleLineRatio: 1.3936, // 2854/2048\n },\n impact: {\n googleFont: 'Anton',\n category: 'sans-serif',\n fallbackStack: ['Impact', 'Anton', 'Arial Black', 'sans-serif'],\n singleLineRatio: 1.2197, // 2498/2048\n },\n 'palatino linotype': {\n googleFont: 'EB Garamond',\n category: 'serif',\n fallbackStack: ['Palatino Linotype', 'EB Garamond', 'Palatino', 'Georgia', 'serif'],\n singleLineRatio: 1.0259, // 2101/2048\n },\n 'book antiqua': {\n googleFont: 'EB Garamond',\n category: 'serif',\n fallbackStack: ['Book Antiqua', 'EB Garamond', 'Palatino', 'Georgia', 'serif'],\n singleLineRatio: 1.0259, // 2101/2048\n },\n garamond: {\n googleFont: 'EB Garamond',\n category: 'serif',\n fallbackStack: ['Garamond', 'EB Garamond', 'Georgia', 'serif'],\n singleLineRatio: 1.068, // 1068/1000\n },\n 'century gothic': {\n googleFont: 'Questrial',\n category: 'sans-serif',\n fallbackStack: ['Century Gothic', 'Questrial', 'Arial', 'sans-serif'],\n singleLineRatio: 1.1611, // 2378/2048\n },\n 'lucida sans': {\n googleFont: 'Open Sans',\n category: 'sans-serif',\n fallbackStack: ['Lucida Sans', 'Open Sans', 'Arial', 'sans-serif'],\n singleLineRatio: 1.1655, // 2387/2048\n },\n 'lucida console': {\n googleFont: 'Cousine',\n category: 'monospace',\n fallbackStack: ['Lucida Console', 'Cousine', 'Courier New', 'monospace'],\n singleLineRatio: 1.1387, // 2332/2048\n },\n consolas: {\n googleFont: 'Inconsolata',\n category: 'monospace',\n fallbackStack: ['Consolas', 'Inconsolata', 'Cousine', 'Courier New', 'monospace'],\n singleLineRatio: 1.1626, // 2381/2048\n },\n\n // CJK fonts\n 'ms mincho': {\n googleFont: 'Noto Serif JP',\n category: 'serif',\n fallbackStack: ['MS Mincho', 'Noto Serif JP', 'serif'],\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n },\n 'ms gothic': {\n googleFont: 'Noto Sans JP',\n category: 'sans-serif',\n fallbackStack: ['MS Gothic', 'Noto Sans JP', 'sans-serif'],\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n },\n simhei: {\n googleFont: 'Noto Sans SC',\n category: 'sans-serif',\n fallbackStack: ['SimHei', 'Noto Sans SC', 'sans-serif'],\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n },\n simsun: {\n googleFont: 'Noto Serif SC',\n category: 'serif',\n fallbackStack: ['SimSun', 'Noto Serif SC', 'serif'],\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n },\n 'malgun gothic': {\n googleFont: 'Noto Sans KR',\n category: 'sans-serif',\n fallbackStack: ['Malgun Gothic', 'Noto Sans KR', 'sans-serif'],\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n },\n};\n\n/**\n * Default fallback stacks by category\n */\nconst DEFAULT_FALLBACKS: Record<FontCategory, string> = {\n 'sans-serif': 'Arial, Helvetica, sans-serif',\n serif: 'Times New Roman, Times, serif',\n monospace: 'Courier New, Courier, monospace',\n cursive: 'cursive',\n fantasy: 'fantasy',\n 'system-ui': 'system-ui, sans-serif',\n};\n\n/**\n * Detect font category from font name\n */\nfunction detectFontCategory(fontName: string): FontCategory {\n const lower = fontName.toLowerCase();\n\n // Monospace indicators\n if (\n lower.includes('mono') ||\n lower.includes('courier') ||\n lower.includes('consolas') ||\n lower.includes('console') ||\n lower.includes('code') ||\n lower.includes('terminal')\n ) {\n return 'monospace';\n }\n\n // Serif indicators\n if (\n lower.includes('times') ||\n lower.includes('georgia') ||\n lower.includes('garamond') ||\n lower.includes('palatino') ||\n lower.includes('baskerville') ||\n lower.includes('bodoni') ||\n lower.includes('cambria') ||\n lower.includes('mincho') ||\n lower.includes('ming') ||\n lower.includes('song') ||\n lower.includes('serif')\n ) {\n return 'serif';\n }\n\n // Cursive/script indicators\n if (\n lower.includes('script') ||\n lower.includes('cursive') ||\n lower.includes('comic') ||\n lower.includes('brush') ||\n lower.includes('hand')\n ) {\n return 'cursive';\n }\n\n // Default to sans-serif\n return 'sans-serif';\n}\n\n/**\n * Resolve a DOCX font name to a Google Font and CSS fallback stack\n *\n * @param docxFontName - The font name from the DOCX file\n * @returns Resolved font information\n */\nexport function resolveFontFamily(docxFontName: string): ResolvedFont {\n const normalizedName = docxFontName.trim().toLowerCase();\n\n // Check if we have a direct mapping\n const mapping = FONT_MAPPINGS[normalizedName];\n\n if (mapping) {\n return {\n googleFont: mapping.googleFont,\n cssFallback: mapping.fallbackStack.map(quoteFontName).join(', '),\n originalFont: docxFontName,\n hasGoogleEquivalent: true,\n singleLineRatio: mapping.singleLineRatio,\n };\n }\n\n // No mapping - detect category and create fallback\n const category = detectFontCategory(docxFontName);\n const defaultFallback = DEFAULT_FALLBACKS[category];\n\n return {\n googleFont: null,\n cssFallback: `${quoteFontName(docxFontName)}, ${defaultFallback}`,\n originalFont: docxFontName,\n hasGoogleEquivalent: false,\n singleLineRatio: DEFAULT_SINGLE_LINE_RATIO,\n };\n}\n\n/**\n * Quote a font name if it contains spaces or special characters\n */\nfunction quoteFontName(fontName: string): string {\n // If it's a generic family, don't quote\n if (\n ['serif', 'sans-serif', 'monospace', 'cursive', 'fantasy', 'system-ui'].includes(\n fontName.toLowerCase()\n )\n ) {\n return fontName;\n }\n\n // Quote if contains spaces or special characters\n if (/[\\s,'\"()]/.test(fontName)) {\n return `\"${fontName.replace(/\"/g, '\\\\\"')}\"`;\n }\n\n return fontName;\n}\n\n/**\n * Resolve a theme font reference to actual font names\n *\n * @param themeRef - Theme font reference (e.g., 'majorAscii', 'minorHAnsi')\n * @param fontScheme - Theme font scheme from the DOCX\n * @returns Resolved font name or null if not found\n */\nexport function resolveThemeFont(themeRef: string, fontScheme?: ThemeFontScheme): string | null {\n if (!fontScheme) {\n return null;\n }\n\n // Parse the theme reference\n const isMajor = themeRef.toLowerCase().startsWith('major');\n const themeFont: ThemeFont | undefined = isMajor ? fontScheme.majorFont : fontScheme.minorFont;\n\n if (!themeFont) {\n return null;\n }\n\n // Determine which script variant to use\n const ref = themeRef.toLowerCase();\n\n if (ref.includes('eastasia') || ref.includes('ea')) {\n return themeFont.ea ?? themeFont.latin ?? null;\n }\n\n if (ref.includes('cs') || ref.includes('bidi')) {\n return themeFont.cs ?? themeFont.latin ?? null;\n }\n\n // Default to Latin/Western font\n return themeFont.latin ?? null;\n}\n\n/**\n * Get all Google Font names needed for a list of DOCX fonts\n *\n * @param docxFonts - Array of font names from the DOCX\n * @returns Array of Google Font names to load\n */\nexport function getGoogleFontsToLoad(docxFonts: string[]): string[] {\n const googleFonts = new Set<string>();\n\n for (const font of docxFonts) {\n const resolved = resolveFontFamily(font);\n if (resolved.googleFont) {\n googleFonts.add(resolved.googleFont);\n }\n }\n\n return Array.from(googleFonts);\n}\n\n/**\n * Build a CSS font-family string from an array of font names\n *\n * @param fonts - Array of font names\n * @param category - Fallback category\n * @returns CSS font-family value\n */\nexport function buildFontFamilyString(\n fonts: string[],\n category: FontCategory = 'sans-serif'\n): string {\n const quoted = fonts.map(quoteFontName);\n\n // Ensure we have the generic fallback\n const parts = [...quoted];\n if (!parts.some((p) => p.toLowerCase() === category)) {\n parts.push(category);\n }\n\n return parts.join(', ');\n}\n\n/**\n * Get the Google Font equivalent for a DOCX font (if any)\n *\n * @param docxFontName - The font name from the DOCX file\n * @returns Google Font name or null\n */\nexport function getGoogleFontEquivalent(docxFontName: string): string | null {\n const normalizedName = docxFontName.trim().toLowerCase();\n const mapping = FONT_MAPPINGS[normalizedName];\n return mapping?.googleFont ?? null;\n}\n\n/**\n * Check if a font has a known Google Fonts equivalent\n *\n * @param docxFontName - The font name from the DOCX file\n * @returns true if there's a Google Fonts equivalent\n */\nexport function hasGoogleFontEquivalent(docxFontName: string): boolean {\n const normalizedName = docxFontName.trim().toLowerCase();\n return normalizedName in FONT_MAPPINGS;\n}\n","/**\n * Measurement container for text layout\n *\n * Uses HTML5 Canvas API to measure text runs and calculate typography metrics.\n * Canvas-based measurement is more accurate and performant than DOM-based approaches.\n *\n * Typography conventions (matching Word behavior):\n * - ascent ≈ fontSize * 0.8 (baseline to top)\n * - descent ≈ fontSize * 0.2 (baseline to bottom)\n * - lineHeight from font metrics (fontBoundingBoxAscent + fontBoundingBoxDescent),\n * falling back to fontSize * 1.15 (Word 2007+ \"single\" line spacing)\n */\n\nimport { resolveFontFamily } from '../../utils/fontResolver';\n\n// Constants for OOXML unit conversions\nconst TWIPS_PER_INCH = 1440;\nconst PX_PER_INCH = 96; // Standard CSS/DOM DPI\nconst TWIPS_PER_PX = TWIPS_PER_INCH / PX_PER_INCH; // 15 twips per pixel\n\n// Default typography values\nconst DEFAULT_FONT_SIZE = 11; // 11pt (Word 2007+ default)\nconst DEFAULT_FONT_FAMILY = 'Calibri';\nconst DEFAULT_LINE_HEIGHT_MULTIPLIER = 1.15; // Word single spacing\nconst DEFAULT_ASCENT_RATIO = 0.8;\nconst DEFAULT_DESCENT_RATIO = 0.2;\n\n/**\n * Font styling properties for measurement\n */\nexport interface FontStyle {\n fontFamily?: string;\n fontSize?: number; // in points\n bold?: boolean;\n italic?: boolean;\n letterSpacing?: number; // in pixels\n}\n\n/**\n * Typography metrics for a font\n */\nexport interface FontMetrics {\n fontSize: number;\n ascent: number;\n descent: number;\n lineHeight: number;\n fontFamily: string;\n /** OS/2 single-line ratio for OOXML line spacing calculation */\n singleLineRatio: number;\n}\n\n/**\n * Result of measuring a text string\n */\nexport interface TextMeasurement {\n width: number;\n height: number;\n ascent: number;\n descent: number;\n}\n\n/**\n * Result of measuring a run of text\n */\nexport interface RunMeasurement {\n width: number;\n charWidths: number[]; // Width of each character for click positioning\n metrics: FontMetrics;\n}\n\n// Cached canvas context for text measurement\nlet canvasContext: CanvasRenderingContext2D | null = null;\n\n/**\n * Get or create a canvas 2D context for text measurement\n */\nexport function getCanvasContext(): CanvasRenderingContext2D {\n if (!canvasContext) {\n // Create offscreen canvas\n const canvas = typeof document !== 'undefined' ? document.createElement('canvas') : null;\n\n if (!canvas) {\n throw new Error('Canvas not available. Ensure this runs in a DOM environment.');\n }\n\n canvasContext = canvas.getContext('2d');\n if (!canvasContext) {\n throw new Error('Failed to get 2D context from canvas');\n }\n }\n\n return canvasContext;\n}\n\n/**\n * Reset the canvas context (useful for testing)\n */\nexport function resetCanvasContext(): void {\n canvasContext = null;\n}\n\n/** Cached resolved font data (CSS fallback + single-line ratio) */\ninterface ResolvedFontCache {\n cssFallback: string;\n singleLineRatio: number;\n}\n\n/** Cache for resolved font data */\nconst fontResolvedCache = new Map<string, ResolvedFontCache>();\n\n/**\n * Get the resolved font data for a font family, with caching.\n */\nfunction getResolvedData(fontFamily: string): ResolvedFontCache {\n let cached = fontResolvedCache.get(fontFamily);\n if (cached === undefined) {\n const resolved = resolveFontFamily(fontFamily);\n cached = { cssFallback: resolved.cssFallback, singleLineRatio: resolved.singleLineRatio };\n fontResolvedCache.set(fontFamily, cached);\n }\n return cached;\n}\n\n/**\n * Get the CSS fallback string for a font family, with caching.\n */\nfunction getResolvedFallback(fontFamily: string): string {\n return getResolvedData(fontFamily).cssFallback;\n}\n\n/**\n * Build a CSS font string from styling properties\n *\n * Font sizes are in points and need to be converted to pixels for canvas.\n * 1pt = 96/72 px ≈ 1.333px at standard web DPI.\n *\n * Uses the font resolver to get category-appropriate fallback stacks\n * (serif fonts get serif fallbacks, sans-serif get sans-serif, etc.)\n * matching the same stacks used in rendering for consistent measurements.\n *\n * @example\n * buildFontString({ fontFamily: \"Arial\", fontSize: 12, bold: true })\n * // Returns: \"bold 16px Arial, Arimo, Helvetica, sans-serif\" (12pt = 16px)\n */\nexport function buildFontString(style: FontStyle): string {\n const parts: string[] = [];\n\n if (style.italic) parts.push('italic');\n if (style.bold) parts.push('bold');\n\n // Convert points to pixels for canvas measurement\n const fontSizePt = style.fontSize ?? DEFAULT_FONT_SIZE;\n const fontSizePx = ptToPx(fontSizePt);\n parts.push(`${fontSizePx}px`);\n\n // Use the font resolver for category-appropriate fallback stacks\n const fontFamily = style.fontFamily ?? DEFAULT_FONT_FAMILY;\n parts.push(getResolvedFallback(fontFamily));\n\n return parts.join(' ');\n}\n\n/**\n * Get typography metrics for a given font size and family\n *\n * Uses Canvas TextMetrics API when available for precise metrics,\n * falls back to ratio-based approximations.\n */\nexport function getFontMetrics(style: FontStyle): FontMetrics {\n const fontSize = style.fontSize ?? DEFAULT_FONT_SIZE;\n const fontFamily = style.fontFamily ?? DEFAULT_FONT_FAMILY;\n\n // Convert font size from points to pixels\n const fontSizePx = ptToPx(fontSize);\n\n // Try to get precise metrics from canvas\n let ascent = fontSizePx * DEFAULT_ASCENT_RATIO;\n let descent = fontSizePx * DEFAULT_DESCENT_RATIO;\n let lineHeight = fontSizePx * DEFAULT_LINE_HEIGHT_MULTIPLIER;\n\n try {\n const ctx = getCanvasContext();\n ctx.font = buildFontString(style);\n\n // Measure a standard character to get metrics\n const metrics = ctx.measureText('Hg');\n\n // Use actual bounding box for ascent/descent (ink bounds for baseline positioning)\n if (\n typeof metrics.actualBoundingBoxAscent === 'number' &&\n typeof metrics.actualBoundingBoxDescent === 'number'\n ) {\n ascent = metrics.actualBoundingBoxAscent;\n descent = metrics.actualBoundingBoxDescent;\n }\n\n // Note: We intentionally do NOT use fontBoundingBoxAscent/Descent for lineHeight.\n // When Google Font substitutes are used (e.g., EB Garamond for Garamond),\n // their fontBoundingBox metrics are significantly larger than the original font's\n // OS/2 metrics that Word uses (e.g., EB Garamond 12pt: 21px vs Garamond: 18px).\n // Using fontSize * 1.15 as the base provides a better approximation of Word's\n // single-line spacing across all fonts, including substitutes.\n } catch {\n // Use fallback ratio-based values\n }\n\n // Ensure line height is never smaller than actual glyph bounds\n lineHeight = Math.max(lineHeight, ascent + descent);\n\n // Look up OS/2 single-line ratio for OOXML line spacing\n const singleLineRatio = getResolvedData(fontFamily).singleLineRatio;\n\n return {\n fontSize, // Keep in points for reference\n ascent,\n descent,\n lineHeight,\n fontFamily,\n singleLineRatio,\n };\n}\n\n/**\n * Measure the width of a text string with specific styling\n *\n * @param text - The text to measure\n * @param style - Font styling properties\n * @returns Width in pixels\n */\nexport function measureTextWidth(text: string, style: FontStyle): number {\n if (!text) return 0;\n\n const ctx = getCanvasContext();\n ctx.font = buildFontString(style);\n\n const metrics = ctx.measureText(text);\n\n // Use advance width for line breaking — this is the standard metric for text flow.\n // Painted width (actualBoundingBox) includes glyph overhang which is visual only\n // and should not affect line breaking decisions.\n let width = metrics.width;\n\n // Apply letter spacing if specified\n if (style.letterSpacing && text.length > 1) {\n width += style.letterSpacing * (text.length - 1);\n }\n\n return width;\n}\n\n/**\n * Measure text and return full metrics\n */\nexport function measureText(text: string, style: FontStyle): TextMeasurement {\n const width = measureTextWidth(text, style);\n const metrics = getFontMetrics(style);\n\n return {\n width,\n height: metrics.ascent + metrics.descent,\n ascent: metrics.ascent,\n descent: metrics.descent,\n };\n}\n\n/**\n * Measure a run of text and return per-character widths for click positioning\n *\n * @param text - The text to measure\n * @param style - Font styling properties\n * @returns Run measurement with width and per-character widths\n */\nexport function measureRun(text: string, style: FontStyle): RunMeasurement {\n const metrics = getFontMetrics(style);\n\n if (!text) {\n return {\n width: 0,\n charWidths: [],\n metrics,\n };\n }\n\n const ctx = getCanvasContext();\n ctx.font = buildFontString(style);\n\n const letterSpacing = style.letterSpacing ?? 0;\n const charWidths: number[] = [];\n let totalWidth = 0;\n\n // Measure each character individually for click positioning\n for (let i = 0; i < text.length; i++) {\n const char = text[i];\n const charMetrics = ctx.measureText(char);\n\n // Use advance width for individual characters\n let charWidth = charMetrics.width;\n\n // Add letter spacing after each character except the last\n if (letterSpacing && i < text.length - 1) {\n charWidth += letterSpacing;\n }\n\n charWidths.push(charWidth);\n totalWidth += charWidth;\n }\n\n return {\n width: totalWidth,\n charWidths,\n metrics,\n };\n}\n\n/**\n * Find the character offset at a given X position within a text run\n *\n * @param x - X position relative to run start\n * @param charWidths - Per-character widths from measureRun\n * @returns Character offset (0-based index)\n */\nexport function findCharacterAtX(x: number, charWidths: number[]): number {\n if (charWidths.length === 0) return 0;\n if (x <= 0) return 0;\n\n let accumulatedWidth = 0;\n\n for (let i = 0; i < charWidths.length; i++) {\n const charWidth = charWidths[i];\n const charMidpoint = accumulatedWidth + charWidth / 2;\n\n // If x is before the midpoint, the cursor is at this character\n if (x <= charMidpoint) {\n return i;\n }\n\n accumulatedWidth += charWidth;\n }\n\n // X is past all characters, return position after last character\n return charWidths.length;\n}\n\n/**\n * Get the X position of a character offset within a text run\n *\n * @param offset - Character offset (0-based index)\n * @param charWidths - Per-character widths from measureRun\n * @returns X position in pixels\n */\nexport function getXForCharacter(offset: number, charWidths: number[]): number {\n if (offset <= 0 || charWidths.length === 0) return 0;\n\n const clampedOffset = Math.min(offset, charWidths.length);\n let x = 0;\n\n for (let i = 0; i < clampedOffset; i++) {\n x += charWidths[i];\n }\n\n return x;\n}\n\n// Unit conversion utilities\n\n/**\n * Convert twips to pixels\n */\nexport function twipsToPx(twips: number): number {\n return twips / TWIPS_PER_PX;\n}\n\n/**\n * Convert pixels to twips\n */\nexport function pxToTwips(px: number): number {\n return Math.round(px * TWIPS_PER_PX);\n}\n\n/**\n * Convert points to pixels\n */\nexport function ptToPx(pt: number): number {\n return (pt * PX_PER_INCH) / 72;\n}\n\n/**\n * Convert pixels to points\n */\nexport function pxToPt(px: number): number {\n return (px * 72) / PX_PER_INCH;\n}\n\n/**\n * Convert OOXML half-points to pixels\n * OOXML font sizes are in half-points (24 = 12pt)\n */\nexport function halfPtToPx(halfPt: number): number {\n return ptToPx(halfPt / 2);\n}\n\n/**\n * Convert pixels to OOXML half-points\n */\nexport function pxToHalfPt(px: number): number {\n return pxToPt(px) * 2;\n}\n","/**\n * Hit Testing Utilities\n *\n * Maps click coordinates to pages, fragments, and document positions.\n * Used by the paged editor to translate user clicks into PM positions.\n */\n\nimport type {\n Layout,\n Page,\n Fragment,\n ParagraphFragment,\n TableFragment,\n FlowBlock,\n Measure,\n ParagraphBlock,\n ParagraphMeasure,\n TableBlock,\n TableMeasure,\n BlockId,\n} from '../layout-engine/types';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/**\n * A 2D point in page coordinate space.\n */\nexport type Point = {\n x: number;\n y: number;\n};\n\n/**\n * Result of hit-testing to find which page contains a point.\n */\nexport type PageHit = {\n /** Index of the page (0-based). */\n pageIndex: number;\n /** The page that was hit. */\n page: Page;\n /** Y position relative to the page top. */\n pageY: number;\n};\n\n/**\n * Result of hit-testing to find which fragment contains a point.\n */\nexport type FragmentHit = {\n /** The fragment that was hit. */\n fragment: Fragment;\n /** The corresponding flow block. */\n block: FlowBlock;\n /** The corresponding measurement. */\n measure: Measure;\n /** Page index (0-based). */\n pageIndex: number;\n /** Y position relative to the fragment top. */\n localY: number;\n /** X position relative to the fragment left. */\n localX: number;\n};\n\n/**\n * Result of hit-testing a table to find the cell.\n */\nexport type TableCellHit = {\n /** The table fragment. */\n fragment: TableFragment;\n /** The table block. */\n block: TableBlock;\n /** The table measure. */\n measure: TableMeasure;\n /** Page index (0-based). */\n pageIndex: number;\n /** Row index (0-based). */\n rowIndex: number;\n /** Column index (0-based). */\n colIndex: number;\n /** Paragraph block within the cell (first one). */\n cellBlock?: ParagraphBlock;\n /** Paragraph measure within the cell. */\n cellMeasure?: ParagraphMeasure;\n /** X position relative to cell content area. */\n cellLocalX: number;\n /** Y position relative to cell content area. */\n cellLocalY: number;\n};\n\n// =============================================================================\n// PAGE HIT TESTING\n// =============================================================================\n\n/**\n * Hit-test pages to find which page contains a given Y coordinate.\n *\n * Pages are stacked vertically with optional gaps between them.\n * If the point is in a gap, returns the nearest page.\n *\n * @param layout - The layout containing pages.\n * @param point - The point to test (only Y is used for page lookup).\n * @returns PageHit if a page was found, null otherwise.\n */\nexport function hitTestPage(layout: Layout, point: Point): PageHit | null {\n if (layout.pages.length === 0) {\n return null;\n }\n\n const pageGap = layout.pageGap ?? 0;\n let cursorY = 0;\n\n // Track nearest page for gap hits\n let nearestPageIndex: number | null = null;\n let nearestDistance = Infinity;\n\n for (let pageIndex = 0; pageIndex < layout.pages.length; pageIndex++) {\n const page = layout.pages[pageIndex];\n const pageHeight = page.size?.h ?? layout.pageSize.h;\n const pageTop = cursorY;\n const pageBottom = pageTop + pageHeight;\n\n // Check if point is within this page\n if (point.y >= pageTop && point.y < pageBottom) {\n return {\n pageIndex,\n page,\n pageY: point.y - pageTop,\n };\n }\n\n // Track nearest page by distance to page center\n const pageCenter = pageTop + pageHeight / 2;\n const distance = Math.abs(point.y - pageCenter);\n if (distance < nearestDistance) {\n nearestDistance = distance;\n nearestPageIndex = pageIndex;\n }\n\n // Move to next page (add gap after)\n cursorY = pageBottom + pageGap;\n }\n\n // If point is in a gap or outside, return nearest page\n if (nearestPageIndex !== null) {\n const page = layout.pages[nearestPageIndex];\n const pageTop = getPageTop(layout, nearestPageIndex);\n return {\n pageIndex: nearestPageIndex,\n page,\n pageY: Math.max(0, Math.min(point.y - pageTop, page.size?.h ?? layout.pageSize.h)),\n };\n }\n\n return null;\n}\n\n/**\n * Calculate the Y offset of a page from the top of the document.\n */\nexport function getPageTop(layout: Layout, pageIndex: number): number {\n const pageGap = layout.pageGap ?? 0;\n let y = 0;\n\n for (let i = 0; i < pageIndex && i < layout.pages.length; i++) {\n const page = layout.pages[i];\n const pageHeight = page.size?.h ?? layout.pageSize.h;\n y += pageHeight + pageGap;\n }\n\n return y;\n}\n\n/**\n * Get the page index at a specific Y coordinate.\n * Returns null if the coordinate is outside all pages.\n */\nexport function getPageIndexAtY(layout: Layout, y: number): number | null {\n const hit = hitTestPage(layout, { x: 0, y });\n return hit?.pageIndex ?? null;\n}\n\n// =============================================================================\n// FRAGMENT HIT TESTING\n// =============================================================================\n\n/**\n * Find a block by its ID in the blocks array.\n */\nfunction findBlockIndexById(blocks: FlowBlock[], blockId: BlockId): number {\n return blocks.findIndex((block) => block.id === blockId);\n}\n\n/**\n * Calculate the actual height of a paragraph fragment from its lines.\n */\nfunction calculateParagraphFragmentHeight(\n fragment: ParagraphFragment,\n measure: ParagraphMeasure\n): number {\n let height = 0;\n for (let i = fragment.fromLine; i < fragment.toLine && i < measure.lines.length; i++) {\n height += measure.lines[i].lineHeight;\n }\n return height;\n}\n\n/**\n * Hit-test fragments on a page to find which fragment contains a point.\n *\n * Fragments are checked in visual order (sorted by Y then X).\n * Only considers paragraph and table fragments (not images for now).\n *\n * @param pageHit - The page hit result from hitTestPage.\n * @param blocks - All flow blocks in the document.\n * @param measures - All measurements corresponding to blocks.\n * @param pagePoint - Point in page-relative coordinates.\n * @returns FragmentHit if a fragment was found, null otherwise.\n */\nexport function hitTestFragment(\n pageHit: PageHit,\n blocks: FlowBlock[],\n measures: Measure[],\n pagePoint: Point\n): FragmentHit | null {\n // Sort fragments by Y, then X for consistent hit testing\n const sortedFragments = [...pageHit.page.fragments].sort((a, b) => {\n const dy = a.y - b.y;\n if (Math.abs(dy) > 0.5) return dy;\n return a.x - b.x;\n });\n\n for (const fragment of sortedFragments) {\n const blockIndex = findBlockIndexById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || !measure) continue;\n\n // Calculate fragment bounds based on type\n let fragmentHeight: number;\n\n if (fragment.kind === 'paragraph') {\n if (block.kind !== 'paragraph' || measure.kind !== 'paragraph') continue;\n fragmentHeight = calculateParagraphFragmentHeight(fragment, measure);\n } else if (fragment.kind === 'table') {\n fragmentHeight = fragment.height;\n } else if (fragment.kind === 'image') {\n fragmentHeight = fragment.height;\n } else {\n continue;\n }\n\n // Check if point is within fragment bounds\n const withinX = pagePoint.x >= fragment.x && pagePoint.x <= fragment.x + fragment.width;\n const withinY = pagePoint.y >= fragment.y && pagePoint.y <= fragment.y + fragmentHeight;\n\n if (withinX && withinY) {\n return {\n fragment,\n block,\n measure,\n pageIndex: pageHit.pageIndex,\n localX: pagePoint.x - fragment.x,\n localY: pagePoint.y - fragment.y,\n };\n }\n }\n\n return null;\n}\n\n/**\n * Hit-test to find image fragments (they may overlap other content).\n */\nexport function hitTestImageFragment(\n pageHit: PageHit,\n blocks: FlowBlock[],\n measures: Measure[],\n pagePoint: Point\n): FragmentHit | null {\n for (const fragment of pageHit.page.fragments) {\n if (fragment.kind !== 'image') continue;\n\n const blockIndex = findBlockIndexById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || !measure) continue;\n\n const withinX = pagePoint.x >= fragment.x && pagePoint.x <= fragment.x + fragment.width;\n const withinY = pagePoint.y >= fragment.y && pagePoint.y <= fragment.y + fragment.height;\n\n if (withinX && withinY) {\n return {\n fragment,\n block,\n measure,\n pageIndex: pageHit.pageIndex,\n localX: pagePoint.x - fragment.x,\n localY: pagePoint.y - fragment.y,\n };\n }\n }\n\n return null;\n}\n\n// =============================================================================\n// TABLE CELL HIT TESTING\n// =============================================================================\n\n/**\n * Hit-test within a table fragment to find the specific cell.\n *\n * @param pageHit - The page hit result.\n * @param blocks - All flow blocks.\n * @param measures - All measurements.\n * @param pagePoint - Point in page-relative coordinates.\n * @returns TableCellHit if a table cell was found, null otherwise.\n */\nexport function hitTestTableCell(\n pageHit: PageHit,\n blocks: FlowBlock[],\n measures: Measure[],\n pagePoint: Point\n): TableCellHit | null {\n for (const fragment of pageHit.page.fragments) {\n if (fragment.kind !== 'table') continue;\n\n const tableFragment = fragment as TableFragment;\n\n // Check if point is within table bounds\n const withinX =\n pagePoint.x >= tableFragment.x && pagePoint.x <= tableFragment.x + tableFragment.width;\n const withinY =\n pagePoint.y >= tableFragment.y && pagePoint.y <= tableFragment.y + tableFragment.height;\n if (!withinX || !withinY) continue;\n\n const blockIndex = findBlockIndexById(blocks, tableFragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || block.kind !== 'table' || !measure || measure.kind !== 'table') continue;\n\n const tableBlock = block as TableBlock;\n const tableMeasure = measure as TableMeasure;\n\n // Calculate local position within table\n const localX = pagePoint.x - tableFragment.x;\n const localY = pagePoint.y - tableFragment.y;\n\n // Find row at localY\n let rowY = 0;\n let rowIndex = -1;\n\n if (tableMeasure.rows.length === 0 || tableBlock.rows.length === 0) continue;\n\n for (\n let r = tableFragment.fromRow;\n r < tableFragment.toRow && r < tableMeasure.rows.length;\n r++\n ) {\n const rowMeasure = tableMeasure.rows[r];\n if (localY >= rowY && localY < rowY + rowMeasure.height) {\n rowIndex = r;\n break;\n }\n rowY += rowMeasure.height;\n }\n\n // If no row found, use last row\n if (rowIndex === -1) {\n rowIndex = Math.min(tableFragment.toRow - 1, tableMeasure.rows.length - 1);\n if (rowIndex < tableFragment.fromRow) continue;\n }\n\n const rowMeasure = tableMeasure.rows[rowIndex];\n const row = tableBlock.rows[rowIndex];\n if (!rowMeasure || !row) continue;\n\n // Find column at localX\n let colX = 0;\n let colIndex = -1;\n\n if (rowMeasure.cells.length === 0 || row.cells.length === 0) continue;\n\n for (let c = 0; c < rowMeasure.cells.length; c++) {\n const cellMeasure = rowMeasure.cells[c];\n if (localX >= colX && localX < colX + cellMeasure.width) {\n colIndex = c;\n break;\n }\n colX += cellMeasure.width;\n }\n\n // If no column found, use last column\n if (colIndex === -1) {\n colIndex = rowMeasure.cells.length - 1;\n if (colIndex < 0) continue;\n }\n\n const cellMeasure = rowMeasure.cells[colIndex];\n const cell = row.cells[colIndex];\n if (!cellMeasure || !cell) continue;\n\n // Find the cumulative row Y for the found row\n let rowTop = 0;\n for (let r = tableFragment.fromRow; r < rowIndex; r++) {\n rowTop += tableMeasure.rows[r]?.height ?? 0;\n }\n\n // Find the cumulative column X for the found column\n let colLeft = 0;\n for (let c = 0; c < colIndex; c++) {\n colLeft += rowMeasure.cells[c]?.width ?? 0;\n }\n\n // Get first paragraph in cell\n let cellBlock: ParagraphBlock | undefined;\n let cellBlockMeasure: ParagraphMeasure | undefined;\n\n if (cell.blocks && cell.blocks.length > 0) {\n const firstBlock = cell.blocks[0];\n const firstMeasure = cellMeasure.blocks[0];\n if (firstBlock.kind === 'paragraph' && firstMeasure?.kind === 'paragraph') {\n cellBlock = firstBlock as ParagraphBlock;\n cellBlockMeasure = firstMeasure as ParagraphMeasure;\n }\n }\n\n // Calculate position within cell (rough - doesn't account for padding)\n const cellLocalX = localX - colLeft;\n const cellLocalY = localY - rowTop;\n\n return {\n fragment: tableFragment,\n block: tableBlock,\n measure: tableMeasure,\n pageIndex: pageHit.pageIndex,\n rowIndex,\n colIndex,\n cellBlock,\n cellMeasure: cellBlockMeasure,\n cellLocalX: Math.max(0, cellLocalX),\n cellLocalY: Math.max(0, cellLocalY),\n };\n }\n\n return null;\n}\n\n// =============================================================================\n// COMBINED HIT TESTING\n// =============================================================================\n\n/**\n * Combined result of all hit testing.\n */\nexport type HitTestResult = {\n /** Page that was hit. */\n pageHit: PageHit | null;\n /** Fragment that was hit (if any). */\n fragmentHit: FragmentHit | null;\n /** Table cell that was hit (if fragment is a table). */\n tableCellHit: TableCellHit | null;\n};\n\n/**\n * Perform complete hit testing from document coordinates to the most specific element.\n *\n * @param layout - The layout containing pages.\n * @param blocks - All flow blocks.\n * @param measures - All measurements.\n * @param point - Point in document coordinates (Y is cumulative from document top).\n * @returns Complete hit test result.\n */\nexport function hitTest(\n layout: Layout,\n blocks: FlowBlock[],\n measures: Measure[],\n point: Point\n): HitTestResult {\n const result: HitTestResult = {\n pageHit: null,\n fragmentHit: null,\n tableCellHit: null,\n };\n\n // First, find the page\n result.pageHit = hitTestPage(layout, point);\n if (!result.pageHit) {\n return result;\n }\n\n // Convert to page-relative coordinates\n const pageTop = getPageTop(layout, result.pageHit.pageIndex);\n const pagePoint: Point = {\n x: point.x,\n y: point.y - pageTop,\n };\n\n // Find the fragment\n result.fragmentHit = hitTestFragment(result.pageHit, blocks, measures, pagePoint);\n\n // If fragment is a table, find the cell\n if (result.fragmentHit?.fragment.kind === 'table') {\n result.tableCellHit = hitTestTableCell(result.pageHit, blocks, measures, pagePoint);\n }\n\n return result;\n}\n\n// =============================================================================\n// UTILITY FUNCTIONS\n// =============================================================================\n\n/**\n * Get the total document height (all pages + gaps).\n */\nexport function getTotalDocumentHeight(layout: Layout): number {\n if (layout.pages.length === 0) return 0;\n\n const pageGap = layout.pageGap ?? 0;\n let height = 0;\n\n for (let i = 0; i < layout.pages.length; i++) {\n const page = layout.pages[i];\n height += page.size?.h ?? layout.pageSize.h;\n if (i < layout.pages.length - 1) {\n height += pageGap;\n }\n }\n\n return height;\n}\n\n/**\n * Get Y coordinate to scroll to for a specific page.\n */\nexport function getScrollYForPage(layout: Layout, pageIndex: number): number {\n return getPageTop(layout, pageIndex);\n}\n\n/**\n * Get page bounds (top and bottom Y coordinates).\n */\nexport function getPageBounds(\n layout: Layout,\n pageIndex: number\n): { top: number; bottom: number } | null {\n if (pageIndex < 0 || pageIndex >= layout.pages.length) {\n return null;\n }\n\n const top = getPageTop(layout, pageIndex);\n const page = layout.pages[pageIndex];\n const height = page.size?.h ?? layout.pageSize.h;\n\n return {\n top,\n bottom: top + height,\n };\n}\n\n/**\n * Check if a point is within the content area of a page (inside margins).\n */\nexport function isPointInContentArea(_layout: Layout, pageHit: PageHit, pagePoint: Point): boolean {\n const page = pageHit.page;\n const margins = page.margins;\n\n const contentLeft = margins.left;\n const contentRight = page.size.w - margins.right;\n const contentTop = margins.top;\n const contentBottom = page.size.h - margins.bottom;\n\n return (\n pagePoint.x >= contentLeft &&\n pagePoint.x <= contentRight &&\n pagePoint.y >= contentTop &&\n pagePoint.y <= contentBottom\n );\n}\n\n/**\n * Find the nearest fragment to a point on a page.\n * Useful when the click is in whitespace.\n */\nexport function findNearestFragment(\n pageHit: PageHit,\n blocks: FlowBlock[],\n measures: Measure[],\n pagePoint: Point\n): FragmentHit | null {\n let nearestHit: FragmentHit | null = null;\n let nearestDistance = Infinity;\n\n for (const fragment of pageHit.page.fragments) {\n const blockIndex = findBlockIndexById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || !measure) continue;\n\n // Calculate fragment height\n let height: number;\n if (fragment.kind === 'paragraph' && measure.kind === 'paragraph') {\n height = calculateParagraphFragmentHeight(fragment, measure);\n } else if (fragment.kind === 'table' || fragment.kind === 'image') {\n height = fragment.height;\n } else {\n continue;\n }\n\n // Calculate distance to fragment center\n const centerX = fragment.x + fragment.width / 2;\n const centerY = fragment.y + height / 2;\n const distance = Math.sqrt(\n Math.pow(pagePoint.x - centerX, 2) + Math.pow(pagePoint.y - centerY, 2)\n );\n\n if (distance < nearestDistance) {\n nearestDistance = distance;\n nearestHit = {\n fragment,\n block,\n measure,\n pageIndex: pageHit.pageIndex,\n localX: Math.max(0, Math.min(pagePoint.x - fragment.x, fragment.width)),\n localY: Math.max(0, Math.min(pagePoint.y - fragment.y, height)),\n };\n }\n }\n\n return nearestHit;\n}\n","/**\n * Selection Rectangles\n *\n * Converts ProseMirror selection ranges into screen rectangles for rendering\n * selection highlights and the caret cursor.\n *\n * The main function `selectionToRects` takes a PM range and returns an array\n * of rectangles that cover the selected text across all pages and fragments.\n */\n\nimport type {\n Layout,\n FlowBlock,\n Measure,\n ParagraphBlock,\n ParagraphFragment,\n ParagraphMeasure,\n MeasuredLine,\n TableBlock,\n TableFragment,\n TableMeasure,\n TextRun,\n TabRun,\n BlockId,\n} from '../layout-engine/types';\n\nimport { measureRun, type FontStyle } from './measuring/measureContainer';\n\nimport { getPageTop } from './hitTest';\n\n// =============================================================================\n// TYPES\n// =============================================================================\n\n/**\n * A rectangle representing part of a selection.\n */\nexport type SelectionRect = {\n /** X coordinate in container space. */\n x: number;\n /** Y coordinate in container space. */\n y: number;\n /** Width of the rectangle. */\n width: number;\n /** Height of the rectangle (typically line height). */\n height: number;\n /** Page index (0-based). */\n pageIndex: number;\n};\n\n/**\n * Caret position for collapsed selection.\n */\nexport type CaretPosition = {\n /** X coordinate in container space. */\n x: number;\n /** Y coordinate in container space. */\n y: number;\n /** Height of the caret (line height). */\n height: number;\n /** Page index (0-based). */\n pageIndex: number;\n};\n\n// =============================================================================\n// HELPER FUNCTIONS\n// =============================================================================\n\n/**\n * Extract FontStyle from a run for measurement.\n */\nfunction runToFontStyle(run: TextRun | TabRun): FontStyle {\n return {\n fontFamily: run.fontFamily ?? 'Arial',\n fontSize: run.fontSize ?? 12,\n bold: run.bold,\n italic: run.italic,\n letterSpacing: run.letterSpacing,\n };\n}\n\n/**\n * Find a block by its ID.\n */\nfunction findBlockById(blocks: FlowBlock[], blockId: BlockId): number {\n return blocks.findIndex((block) => block.id === blockId);\n}\n\n/**\n * Calculate the PM range for a line.\n * Note: ProseMirror positions include node boundaries:\n * - blockPmStart is the position of the paragraph node itself\n * - The actual text content starts at blockPmStart + 1 (after the opening tag)\n */\nfunction computeLinePmRange(\n block: ParagraphBlock,\n line: MeasuredLine\n): { pmStart: number | undefined; pmEnd: number | undefined } {\n const blockPmStart = block.pmStart ?? 0;\n // Text content starts after the paragraph's opening tag\n const contentStart = blockPmStart + 1;\n\n // Calculate character offset to line start\n let charOffset = 0;\n let pmStart: number | undefined;\n\n for (let runIndex = 0; runIndex < block.runs.length && runIndex <= line.toRun; runIndex++) {\n const run = block.runs[runIndex];\n if (!run) continue;\n\n if (runIndex < line.fromRun) {\n if (run.kind === 'text') {\n charOffset += (run.text ?? '').length;\n } else {\n charOffset += 1;\n }\n } else if (runIndex === line.fromRun) {\n charOffset += line.fromChar;\n pmStart = contentStart + charOffset;\n break;\n }\n }\n\n if (pmStart === undefined) {\n pmStart = contentStart;\n }\n\n // Calculate line length\n let lineLength = 0;\n for (\n let runIndex = line.fromRun;\n runIndex <= line.toRun && runIndex < block.runs.length;\n runIndex++\n ) {\n const run = block.runs[runIndex];\n if (!run) continue;\n\n if (run.kind === 'text') {\n const text = run.text ?? '';\n const start = runIndex === line.fromRun ? line.fromChar : 0;\n const end = runIndex === line.toRun ? line.toChar : text.length;\n lineLength += end - start;\n } else {\n lineLength += 1;\n }\n }\n\n const pmEnd = pmStart + lineLength;\n return { pmStart, pmEnd };\n}\n\n/**\n * Find lines in a paragraph that intersect with a PM range.\n */\nfunction findLinesInRange(\n block: ParagraphBlock,\n measure: ParagraphMeasure,\n from: number,\n to: number\n): { line: MeasuredLine; index: number }[] {\n const result: { line: MeasuredLine; index: number }[] = [];\n\n for (let i = 0; i < measure.lines.length; i++) {\n const line = measure.lines[i];\n const range = computeLinePmRange(block, line);\n\n if (range.pmStart === undefined || range.pmEnd === undefined) continue;\n\n // Check if line overlaps with selection\n if (range.pmEnd > from && range.pmStart < to) {\n result.push({ line, index: i });\n }\n }\n\n return result;\n}\n\n/**\n * Convert a PM position to a character offset within a line.\n */\nfunction pmPosToCharOffset(block: ParagraphBlock, line: MeasuredLine, pmPos: number): number {\n const range = computeLinePmRange(block, line);\n if (range.pmStart === undefined) return 0;\n\n return Math.max(0, pmPos - range.pmStart);\n}\n\n/**\n * Get the X coordinate for a character offset within a line.\n */\nfunction charOffsetToX(\n block: ParagraphBlock,\n line: MeasuredLine,\n charOffset: number,\n _availableWidth: number\n): number {\n // Walk through runs measuring up to the character offset\n let x = 0;\n let charsProcessed = 0;\n\n for (\n let runIndex = line.fromRun;\n runIndex <= line.toRun && runIndex < block.runs.length;\n runIndex++\n ) {\n const run = block.runs[runIndex];\n if (!run) continue;\n\n if (run.kind === 'tab') {\n const tabWidth = run.width ?? 48;\n if (charsProcessed + 1 >= charOffset) {\n if (charOffset <= charsProcessed) return x;\n return x + tabWidth;\n }\n x += tabWidth;\n charsProcessed += 1;\n continue;\n }\n\n if (run.kind === 'image') {\n const imageWidth = run.width;\n if (charsProcessed + 1 >= charOffset) {\n if (charOffset <= charsProcessed) return x;\n return x + imageWidth;\n }\n x += imageWidth;\n charsProcessed += 1;\n continue;\n }\n\n if (run.kind === 'lineBreak') {\n if (charOffset <= charsProcessed) return x;\n charsProcessed += 1;\n continue;\n }\n\n if (run.kind === 'text') {\n const text = run.text ?? '';\n\n // Get portion of text for this line\n const isFirstRun = runIndex === line.fromRun;\n const isLastRun = runIndex === line.toRun;\n const start = isFirstRun ? line.fromChar : 0;\n const end = isLastRun ? line.toChar : text.length;\n const lineText = text.slice(start, end);\n\n if (charsProcessed + lineText.length >= charOffset) {\n // Target character is in this run\n const charInRun = charOffset - charsProcessed;\n const style = runToFontStyle(run);\n const measurement = measureRun(lineText.slice(0, charInRun), style);\n return x + measurement.width;\n }\n\n const style = runToFontStyle(run);\n const measurement = measureRun(lineText, style);\n x += measurement.width;\n charsProcessed += lineText.length;\n }\n }\n\n return x;\n}\n\n/**\n * Calculate cumulative line height before a given line index.\n */\nfunction lineHeightBefore(measure: ParagraphMeasure, lineIndex: number): number {\n let height = 0;\n for (let i = 0; i < lineIndex && i < measure.lines.length; i++) {\n height += measure.lines[i].lineHeight;\n }\n return height;\n}\n\n// =============================================================================\n// MAIN FUNCTIONS\n// =============================================================================\n\n/**\n * Convert a ProseMirror selection range to screen rectangles.\n *\n * @param layout - The document layout.\n * @param blocks - All flow blocks.\n * @param measures - All measurements.\n * @param from - Start PM position.\n * @param to - End PM position.\n * @returns Array of rectangles covering the selection.\n */\nexport function selectionToRects(\n layout: Layout,\n blocks: FlowBlock[],\n measures: Measure[],\n from: number,\n to: number\n): SelectionRect[] {\n // Empty selection\n if (from === to) {\n return [];\n }\n\n // Ensure from < to\n const selFrom = Math.min(from, to);\n const selTo = Math.max(from, to);\n\n const rects: SelectionRect[] = [];\n\n // Walk through all pages and fragments\n for (let pageIndex = 0; pageIndex < layout.pages.length; pageIndex++) {\n const page = layout.pages[pageIndex];\n const pageTopY = getPageTop(layout, pageIndex);\n\n for (const fragment of page.fragments) {\n // Handle paragraph fragments\n if (fragment.kind === 'paragraph') {\n const blockIndex = findBlockById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || block.kind !== 'paragraph') continue;\n if (!measure || measure.kind !== 'paragraph') continue;\n\n const paragraphBlock = block as ParagraphBlock;\n const paragraphMeasure = measure as ParagraphMeasure;\n const paragraphFragment = fragment as ParagraphFragment;\n\n // Find lines that intersect with selection\n const intersectingLines = findLinesInRange(\n paragraphBlock,\n paragraphMeasure,\n selFrom,\n selTo\n );\n\n for (const { line, index } of intersectingLines) {\n // Skip lines not in this fragment\n if (index < paragraphFragment.fromLine || index >= paragraphFragment.toLine) {\n continue;\n }\n\n const range = computeLinePmRange(paragraphBlock, line);\n if (range.pmStart === undefined || range.pmEnd === undefined) continue;\n\n // Calculate overlap with selection\n const sliceFrom = Math.max(range.pmStart, selFrom);\n const sliceTo = Math.min(range.pmEnd, selTo);\n if (sliceFrom >= sliceTo) continue;\n\n // Convert PM positions to character offsets\n const charOffsetFrom = pmPosToCharOffset(paragraphBlock, line, sliceFrom);\n const charOffsetTo = pmPosToCharOffset(paragraphBlock, line, sliceTo);\n\n // Calculate indentation\n const indent = paragraphBlock.attrs?.indent;\n const indentLeft = indent?.left ?? 0;\n const indentRight = indent?.right ?? 0;\n const availableWidth = Math.max(0, fragment.width - indentLeft - indentRight);\n\n // Get X coordinates for selection bounds\n const startX = charOffsetToX(paragraphBlock, line, charOffsetFrom, availableWidth);\n const endX = charOffsetToX(paragraphBlock, line, charOffsetTo, availableWidth);\n\n // Calculate alignment offset\n const alignment = paragraphBlock.attrs?.alignment ?? 'left';\n let alignmentOffset = 0;\n if (alignment === 'center') {\n alignmentOffset = Math.max(0, (availableWidth - line.width) / 2);\n } else if (alignment === 'right') {\n alignmentOffset = Math.max(0, availableWidth - line.width);\n }\n\n // Calculate line Y offset within fragment\n const lineOffset =\n lineHeightBefore(paragraphMeasure, index) -\n lineHeightBefore(paragraphMeasure, paragraphFragment.fromLine);\n\n // Create selection rectangle\n const rectX = fragment.x + indentLeft + alignmentOffset + Math.min(startX, endX);\n const rectWidth = Math.max(1, Math.abs(endX - startX));\n const rectY = fragment.y + lineOffset;\n\n rects.push({\n x: rectX,\n y: rectY + pageTopY,\n width: rectWidth,\n height: line.lineHeight,\n pageIndex,\n });\n }\n }\n\n // Handle table fragments\n if (fragment.kind === 'table') {\n const blockIndex = findBlockById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || block.kind !== 'table') continue;\n if (!measure || measure.kind !== 'table') continue;\n\n const tableBlock = block as TableBlock;\n const tableMeasure = measure as TableMeasure;\n const tableFragment = fragment as TableFragment;\n\n // Walk through visible rows\n let rowY = 0;\n for (\n let rowIndex = tableFragment.fromRow;\n rowIndex < tableFragment.toRow && rowIndex < tableBlock.rows.length;\n rowIndex++\n ) {\n const row = tableBlock.rows[rowIndex];\n const rowMeasure = tableMeasure.rows[rowIndex];\n if (!row || !rowMeasure) continue;\n\n // Walk through cells\n let cellX = 0;\n for (let cellIndex = 0; cellIndex < row.cells.length; cellIndex++) {\n const cell = row.cells[cellIndex];\n const cellMeasure = rowMeasure.cells[cellIndex];\n if (!cell || !cellMeasure) continue;\n\n // Check each paragraph in the cell\n for (let blockIdx = 0; blockIdx < cell.blocks.length; blockIdx++) {\n const cellBlock = cell.blocks[blockIdx];\n const cellBlockMeasure = cellMeasure.blocks[blockIdx];\n\n if (!cellBlock || cellBlock.kind !== 'paragraph') continue;\n if (!cellBlockMeasure || cellBlockMeasure.kind !== 'paragraph') continue;\n\n const paragraphBlock = cellBlock as ParagraphBlock;\n const paragraphMeasure = cellBlockMeasure as ParagraphMeasure;\n\n // Find lines that intersect with selection\n const intersectingLines = findLinesInRange(\n paragraphBlock,\n paragraphMeasure,\n selFrom,\n selTo\n );\n\n let blockY = 0;\n for (const { line, index } of intersectingLines) {\n const range = computeLinePmRange(paragraphBlock, line);\n if (range.pmStart === undefined || range.pmEnd === undefined) continue;\n\n const sliceFrom = Math.max(range.pmStart, selFrom);\n const sliceTo = Math.min(range.pmEnd, selTo);\n if (sliceFrom >= sliceTo) continue;\n\n const charOffsetFrom = pmPosToCharOffset(paragraphBlock, line, sliceFrom);\n const charOffsetTo = pmPosToCharOffset(paragraphBlock, line, sliceTo);\n\n const startX = charOffsetToX(\n paragraphBlock,\n line,\n charOffsetFrom,\n cellMeasure.width\n );\n const endX = charOffsetToX(paragraphBlock, line, charOffsetTo, cellMeasure.width);\n\n const lineY = lineHeightBefore(paragraphMeasure, index);\n\n rects.push({\n x: tableFragment.x + cellX + Math.min(startX, endX),\n y: tableFragment.y + rowY + blockY + lineY + pageTopY,\n width: Math.max(1, Math.abs(endX - startX)),\n height: line.lineHeight,\n pageIndex,\n });\n }\n\n blockY += paragraphMeasure.totalHeight;\n }\n\n cellX += cellMeasure.width;\n }\n\n rowY += rowMeasure.height;\n }\n }\n\n // Handle image fragments\n if (fragment.kind === 'image') {\n const blockPmStart = fragment.pmStart ?? 0;\n const blockPmEnd = fragment.pmEnd ?? blockPmStart + 1;\n\n // Check if image overlaps with selection\n if (blockPmEnd > selFrom && blockPmStart < selTo) {\n rects.push({\n x: fragment.x,\n y: fragment.y + pageTopY,\n width: fragment.width,\n height: fragment.height,\n pageIndex,\n });\n }\n }\n }\n }\n\n return rects;\n}\n\n/**\n * Get caret position for a collapsed selection.\n *\n * @param layout - The document layout.\n * @param blocks - All flow blocks.\n * @param measures - All measurements.\n * @param pmPosition - The PM position.\n * @returns Caret position, or null if not found.\n */\nexport function getCaretPosition(\n layout: Layout,\n blocks: FlowBlock[],\n measures: Measure[],\n pmPosition: number\n): CaretPosition | null {\n // Search through pages and fragments to find the position\n for (let pageIndex = 0; pageIndex < layout.pages.length; pageIndex++) {\n const page = layout.pages[pageIndex];\n const pageTopY = getPageTop(layout, pageIndex);\n\n for (const fragment of page.fragments) {\n if (fragment.kind === 'paragraph') {\n const blockIndex = findBlockById(blocks, fragment.blockId);\n if (blockIndex === -1) continue;\n\n const block = blocks[blockIndex];\n const measure = measures[blockIndex];\n if (!block || block.kind !== 'paragraph') continue;\n if (!measure || measure.kind !== 'paragraph') continue;\n\n const paragraphBlock = block as ParagraphBlock;\n const paragraphMeasure = measure as ParagraphMeasure;\n const paragraphFragment = fragment as ParagraphFragment;\n\n const blockPmStart = paragraphBlock.pmStart ?? 0;\n const blockPmEnd = paragraphBlock.pmEnd ?? blockPmStart;\n\n // Check if position is in this block\n if (pmPosition < blockPmStart || pmPosition > blockPmEnd) continue;\n\n // Find which line contains this position\n for (\n let lineIndex = paragraphFragment.fromLine;\n lineIndex < paragraphFragment.toLine;\n lineIndex++\n ) {\n const line = paragraphMeasure.lines[lineIndex];\n if (!line) continue;\n\n const range = computeLinePmRange(paragraphBlock, line);\n if (range.pmStart === undefined || range.pmEnd === undefined) continue;\n\n if (pmPosition >= range.pmStart && pmPosition <= range.pmEnd) {\n // Position is in this line\n const charOffset = pmPosToCharOffset(paragraphBlock, line, pmPosition);\n\n // Calculate indentation\n const indent = paragraphBlock.attrs?.indent;\n const indentLeft = indent?.left ?? 0;\n const indentRight = indent?.right ?? 0;\n const availableWidth = Math.max(0, fragment.width - indentLeft - indentRight);\n\n const x = charOffsetToX(paragraphBlock, line, charOffset, availableWidth);\n\n // Calculate alignment offset\n const alignment = paragraphBlock.attrs?.alignment ?? 'left';\n let alignmentOffset = 0;\n if (alignment === 'center') {\n alignmentOffset = Math.max(0, (availableWidth - line.width) / 2);\n } else if (alignment === 'right') {\n alignmentOffset = Math.max(0, availableWidth - line.width);\n }\n\n // Calculate Y offset\n const lineOffset =\n lineHeightBefore(paragraphMeasure, lineIndex) -\n lineHeightBefore(paragraphMeasure, paragraphFragment.fromLine);\n\n return {\n x: fragment.x + indentLeft + alignmentOffset + x,\n y: fragment.y + lineOffset + pageTopY,\n height: line.lineHeight,\n pageIndex,\n };\n }\n }\n }\n\n // Check images\n if (fragment.kind === 'image') {\n const fragPmStart = fragment.pmStart ?? 0;\n const fragPmEnd = fragment.pmEnd ?? fragPmStart + 1;\n\n if (pmPosition >= fragPmStart && pmPosition <= fragPmEnd) {\n const xOffset = pmPosition === fragPmStart ? 0 : fragment.width;\n return {\n x: fragment.x + xOffset,\n y: fragment.y + pageTopY,\n height: fragment.height,\n pageIndex,\n };\n }\n }\n }\n }\n\n return null;\n}\n\n/**\n * Check if a selection spans multiple pages.\n *\n * @param rects - Selection rectangles.\n * @returns True if selection spans multiple pages.\n */\nexport function isMultiPageSelection(rects: SelectionRect[]): boolean {\n if (rects.length <= 1) return false;\n\n const pageIndices = new Set(rects.map((r) => r.pageIndex));\n return pageIndices.size > 1;\n}\n\n/**\n * Get selection rectangles grouped by page.\n *\n * @param rects - Selection rectangles.\n * @returns Map of page index to rectangles on that page.\n */\nexport function groupRectsByPage(rects: SelectionRect[]): Map<number, SelectionRect[]> {\n const map = new Map<number, SelectionRect[]>();\n\n for (const rect of rects) {\n const pageRects = map.get(rect.pageIndex) ?? [];\n pageRects.push(rect);\n map.set(rect.pageIndex, pageRects);\n }\n\n return map;\n}\n"]}
|