From d8be23cf68a25c1956a2d0066ea02d45453f8183 Mon Sep 17 00:00:00 2001 From: Steffen Becker Date: Sun, 6 Sep 2026 21:19:09 +0200 Subject: [PATCH] fix: a bracket typed without \left keeps its glyph height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The MathML operator dictionary makes ( [ { | stretchy, so a plain bracket grew to the tallest thing in its row — next to a sum with a fraction, C(b) came out in full row height. Only a fence node emits stretchy brackets now. --- docs/showcase/book.docx | Bin 126468 -> 126468 bytes docs/showcase/book.odt | Bin 60977 -> 60977 bytes docs/showcase/newsletter.docx | Bin 96694 -> 96696 bytes docs/showcase/newsletter.odt | Bin 96079 -> 96078 bytes docs/showcase/thesis-review.docx | Bin 60097 -> 60096 bytes docs/showcase/thesis-review.odt | Bin 21415 -> 21475 bytes docs/showcase/thesis.docx | Bin 57333 -> 57334 bytes docs/showcase/thesis.odt | Bin 20354 -> 20417 bytes src/lib/math/mathml.ts | 6 +++++- tests/unit/math.test.ts | 2 ++ 10 files changed, 7 insertions(+), 1 deletion(-) diff --git a/docs/showcase/book.docx b/docs/showcase/book.docx index 2fa1eba9174c59cb304f19a26c84b07a5e2b6c57..9e72df39e53fec250812d812ea0ee672a6274a50 100644 GIT binary patch delta 4577 zcmZ9OdtA+D7{GhGa3mDXqH|7hDydYA7Bgium)gi;ximYrk=aTgVJn;p>9(Y^`k67; zLSg0hv-ymiq9}Bcu1mBjiazFUjlI9;eLLsjpWgF*p6~O#x8LuaHZ=C!(Ad*rroV}) zwULpL%*ZBZi-pRV{vA1-{>@+Tk1-vN%`|!5E{*=3K4x^(raT%Zv&nG^*=qJw(4Kx| zuL;w6TKfIk|NEWZv6-39z4inh^34fy$+_0UE7YHmPbw6%@DgX)86B^AVC@LPip&&nA+e(CJk zlk$M($bHk6X6*gp#O$Q}-L}q&iSi*K5m}Mb4r!wAjyWP*J8W6OAKuF5{%-1`{*AKu z+4~bdPET2tUOlI`M}cz>;y88L^8Sv`%I1}4{Z`-X>Qj>5FzIiv-{Vf6Pi?Yoid`8p zW#x^%S2S@8TaPU{`*q1zT5GeQFH^EJ=acin%gq3O$u>>FRA3l|QQ^qiZzFxIu%edZwDlj3z$XcS=zcc zSn~?L7gvHUPDa zgY`iNVMZ05=LcIh52Rh>C|!YJ#5J@(>Z$~#lASd`!8Lj>p)%@$lgat zT&_hsgve%R)@hd)QHUPH$+yy%gZPUpDJ0T`J{U*CF(b&QQdj`#i3gJeDk;RcQ6$@7 zP8rQik(x<2E zVaH0*`8$3Uu~9?~v&c5mzGMwK3`D~U@$yb}o4WOkL~33#GZ z*S#x+xa0sQSYqixY;MiPX4fHXetra-Bl1{IjLat;@I)*+PR>a$spAQ9mX7;xpCAx# z6G=8@G3^w22&HjB&MTWxL!nD^T&@GI)ieMdvVhon$NSljc4~BLOqbpbqy+(Kv;W~>e&>F2O z5zNPsg`pF}*eX=Bo_YGu-)ICjtQyi{J@RS2+UX4gw$pN(E96)=BwNZbv8qgv*fR@Jr zChf$UdlRdn8ho8m14h~dMksf=fflor1I%)O18A*Sb81G5`HBN*`#8X2TCg_srhYMU zLCpcQT^wN28ywc%qNk?3#qPxS7CU4bgu{kptsyBF2DUI0GC>&9InW+*p&V!W{>5*+ zm1Y9|V#~8{qmazurj)saq1WF?o5}&SO&Bg<&FnU-0c|pd^&DVQ9nO$eRO8D5G!4$2 zF#y~sHDH9PqT5i9-#I{!=Q!hi2WhK0fOZmR9%C4Nm(_r_f&)x?ltcAh;v>BZ1KZj7 wX*;{RjCS^;nSYNS?SpnQLXzw|*s|fhjqYIY?Li)F!^uhaSTf?CzRf5914Kz!1^@s6 delta 4577 zcmZ9OdtA)v8o=l6u8XbB3e8NdsSq8Pl}&E7LWr6@sK`2LovjXbJ1At8&@#D?{B{>f zySbb;TP=PrpVc;{gj90rc2F%vb&~s~!@j@geVcjsr+2>3^L?K8_WRAWq27E$y}5PJ zbYqiVGMUUm)~VfTtums2hYzBEbHg4P(c!ls9wv&GSaMb~?s2~&dhqE+iqFr4yn(EMJ$4`9Ib|H3eY>DS7<$!{iy}Lh) z87s?@f(^FwKByhV)K`N1ADl7C;C30?YnoM zyG`I+&vXxSdoM-QziW3#Ml8`rEN(H2Uf6$%e{k5K`SuB|X{)z7es;UG-@}31J_%dz zx+NrOOhHcHUX@dKRr==DL^qiBIq#fq7G*Ot!{k7y)tOPjj%)6khc1hcte+fQan7qE zzR)~pN!^hd;~sPkc(G!9{Ijg&u-K_;pV655NyF<#=g(`;Ya9{c zUg~4zu(+Xk|D9u7qZ6Fx+>bW%__Sa{WcG%K0SoTy9Ez$>pS`Lvj`!+Herq&;d$OYA zN|3%PT$Y7O@t#-k^0(;8o7KaM*X z(>puR?M-HF%B)*2@0MqsBlw!!<|_x?pS#9LCi~J__FKra{nABgpTBUC?n&{|hR{*i zX-^cXPQ+Xr^eVBNwH>d%L!ZsGdta}^EPQ*OSZb$t#o?f~x$9l&gJNPS^fMvvTA#dm z$I{lk#|dvC-(X5yQr(FDv#_=Vb(6Bfa)Q#1MhL<#Q1`MCn;G0FW0bZvLEv5be%~)l z_32D$gS3H4$TA~IdidNNLDofLrQasF=@uwG;S#axJ}SumuLsJeS|U(fe!o+b6-sNY z8K`aP=DRM_WskLCTZBlB4O=!qVowCMWz@~GK<lIXWXq z_q5l$Kl6t`CCu%m532TjWcVx`La?Wj_NtTXp9+=ms5evX`q6#;;DErV4}xY4+xqG= zumPy8@23yC2!T~}o~@2-9!R^(QMwX?$2GJ+>Z$~#lASfcAJ^!;R4DbWRKj8>l(u(9 zkapd0-B29NAN3#IVzN~y@?)#buI+9NJkeTz?JO*pyMW8_Wxbkx*+l+e`6%j z`m*;C5@pqBhY;C5kabEQMHJ%DL1c;aMQUoG1f;2>nIzJ7%OO16k0`~B<9Mf>NZQHHha84ZJ~5PT`jQY>3N=%p z1f;sjSUTv>Bmvs>osQdO&cNos0D%>1Gt7 z8gwReDSRir-r1Wt4ckWP^k&`;a>*&!e6WSLqvj=O2a@9s9;UPq!qBN{7w(j^8+Yop zhZ8jwVw^yZL7h5-u3*v+JO_02M{HW}!)EP%Y>q#G&4cO86loW>C}>yp6P8A0@^*CP z3eos5nbf^2h4|GGPO!vFN3r>R7B;(n!R9}XVbddr<;3N=qz#^kg~v&O^pd)sAo+AW zeD4H-c#B95Q5JWcB9CDe^yfz*XxfNf_s^9$4W7`#U3!dc&)?z5ZU|WH-Pz)IuS}}~QWHs~};Yoz+ zEU83mw7ZI69)?T|9T-Mep_=s^a;wl34%d(ojv))fQw$TXqngbasyL7vXo|0HAUzku zYYdZaB5gZ{8Vssxrm3sZ6e178sgW9H46Pw!r8lFYmcAyNYlyQ1PIVMYI8Z|_nAWlk zXcIYrwvGd6`34QTQUgZyE!tyM9r;-5zC(gj9Lgnl&H=Ph^+;R60kq>BKzod}5&va1 zpv7xMti#UMxGY42q z6W01S=ocdw!a0DJ&H*O9&0%dLJvC(`yAz*AcE~gchYiVULsBmEZek{6W?|UHf%cFK z6*$xLPk!UgG!yVATb^?Zg%l1AQsyFt9(R%E&jGaWFcf3W^d74L%@4zR4lt<>XGk-u z@!0Nf}wV1%jSTTqWP9H7TbobkGkv^Wl+oy3`^7)Cx|HJ~ly0F&l%xc-1l zkY0t}t!xZ#WmlKl%6>F++v(AEwh|9Xa&BYGhW9qUjlH)=d9Vd1C$_U>OuN3#-~R%Q CzEO<; diff --git a/docs/showcase/book.odt b/docs/showcase/book.odt index c8b51100920ac3eb85cad9688aa8f81920b5b7a8..db2c39387ff6abe12312612bee47a735694f1ffd 100644 GIT binary patch delta 439 zcmdmZhk4^2W}X0VW)=|!5Rh0kk;j`!V%5gTf470u=EyslJoOT*)MEQ)I{RxgGBCt4 zF)(ld73QXvBep-*;&OeRd)oKB&;UrkySR6fl%!26uUO}^Bd z*tg-q&np)0bwq5+Q&siVsR;+*MxmJbWN+RRBT4>&f&tKo3 zjFNqHY%jCF$t3e`t~r7$UfoDsxaWW%t&M W0~YL)Yu@UC#MZpE08!80dIJD(?#J{1 delta 439 zcmdmZhk4^2W}X0VW)=|!5coKGB9AxI$H^Nb|J?>snY=!W7c5<0oU)AtrzZ1n=7(iaGSHn+f}EhIF&oiTEbK*qGEY= z)Abi$t0tY===;`Tfp_M;|MmLwU;VZym!&9Pk{*y`i6rP!rr)mGXzVdU=^6syU0&_U7UG?WGV1FL4 zY4t$|FLouD?Jk`RUyY*0Jh%C6N}4WSGxhV;*jZ1%zi+PM)Av%Xyl~KAuW4vu^ZfPs z{@Y%OnCHn>ESk6{GUP#zL+CL(<~!`!R~)$~$Jji!)Bmv2wo>F=WOCb{>}A}04*ILf zmhSf5*q7_JDCP5U>Hf|C1OGF@!kGgY&YMMF?PUZ8@#HJ7e}bssxaWW%t&M W0~YL)Yu@UC#MZpE08!80dIJDPLCh%t diff --git a/docs/showcase/newsletter.docx b/docs/showcase/newsletter.docx index df77eddc33bfde3180cbdf4417318fbcf0499537..9a1b286b3bc0e3311572f0c87eb6ccf883e8c8d1 100644 GIT binary patch delta 1275 zcmdn?nRUl!R-OQFW)=|!1_llWg;f)Il$n5}p(c>r7&CzpNNs+{cu^Qc9~6Dg0;DIe zl2YeXSfv)b?zg{7&E#8Ba`mzPPZUJj{&PL7ijGPzkC`obW}SR^mXFNhk9-d;n#D36 zWW3!kUJzyfeviug!-r2d9{smD^Q7>P1#@FB?OLP3s6F>m+1@47S3iEFugcgOx~Noa zT1kV$_n%H>y(Mzz_P#!_xXoeF@iwq>eS+X%Jl4)6)BJ?q|1zm|v!^>sx9B zvJ-_!oK814UUS6USurFYfW3TQ9;}_1{68!3$PrN@P zesSMfAyK*f_l`>TK?x`KH{6R%XDfQRgsoo2$VQ2Cx*Utu`EY54OEV*c8I4TUUS`TA zyqFu_*d6$zyXE2!JO2Xdg_nOkD3`kO|KaAJ+7rH2R9t#_{DYP7Wuve&$#uERT}KX@ zu1}Vmy!z(Bhp%RQGU;A)OMBJNRrj)A-Cefo^!?rSd6!b{Ebc8yi+<#OE$~qB=l=OK z_A>xuj}sn!n`>kaGlAmBQC6Yb;f|E~al!L_YYg>WMkk_islza+g}(l-e3c=w;!@(d}0A)OkYvNXb7Tj7crWHXpv$@ z4-g$!%xDXu=N2>CFto-6h)1Cnn`Z*>B25umY0I|~_mM}_zjQ9&OF=x6|DWg^_D3SXl zOh5CPk%6I#je$V`p#jJeQet!k98i>B zP^_O=P=L)Hb2?8>yaaT|TA(k4fF>Y7|MbK%NZ=(@0DV4j`oc0s9Z*1=F9UKdr@tv< zQ~+`L%7I+H>DuLt+8}NOhTazd9C^G>`LroyLF=hfIklOr?@uDz@J}CN}1xQa` zC8f@JYqDDG+10mhRZYGnC0Fn3|3*Qi?LSvyZS<|ocTaAeNq9G1+f=RZ;tpqva|>9d zETVqDXPtBH{9Nx(b~bxtB4q7m_SrP?-@0kK_H>ufhD(~c+q0`ST58n=3I#-{TBRrY zx^sM)us-F!*Yk&GcFWmhai~<~WTft2W_@H|s?G^n3BgkyHze*^<+B`HdVf<~{fX+0 ztlL(sQZ;UH;uO*0?5;Drv^VHvOspEF{ zUT~LirT@}=At}?gP-a%ov45t!tt{=%hwEllsSl`KBxEAG?1}S9tsJ!-~uO4@=darLLKA{Ldvek>V6=# zc(xi?>s*axAT_RWVmoo}ZKBG|%5`U;|1vW!g?;litDM@xj-38M^S)^wRtMlFy-JxYOGf$6EGjPeQ~V-IX9p1qurfnf&+1A{P%v4+Z% z{gp+h?<{5H0lPAy^0v|>po%9zjH;4z`jb*dC6MVHWkA!J$Iffxb$H72hG#+OeyBM->*iy+g@r@t#>Q~+@W z%7I*+>AK~N+8}Nekjr#gd-6wZ;pyE_9Wy~n_@{3xN9bVUH<+wzAUE9#=C9Gc(iIv@uC(})b?#_6Xj7^T4e;*y(_)XK)l@Q;&`!5rZ! iAnT6N$)S;%%yc3wY6tU z@wk~TP*{7VqE7GWmiofB=!aXMyIpx;>6Q0AfsIrC@}BIHeVk$2S20^()0%l%_R&1! zZTT^x(c4qKj8-Ug*mysl5_svmjPK3`^~S8{zg>yUKiD9g5&Ln?fhh$?dSXSYf~*8? z>~i%|5c!<4uV+%|6rIy0M=!I_Tk`R4&CiRgmw(U+p0xNFS68^j4=#a&^%GgS)gq<$ zuV+1FK0jVzqqp-s8>{S`TBZE3tOLR9{3k50na|<7w$h0wXMVzt`9XCbezsq9TPzlO zB{l!KUb(}Pwb^%{S2& delta 648 zcmX^2j`jRIR-OQFW)=|!5V$pYB9AxIt;riBd4+-0<_zJb?De-MtHnAB=Pq()WMDYT z#K6D-RG6DulBidao6|eVFu&PAp!NG7uG7{MO;W020;L(p^_F^@U*D&acd+lxV$XlI zhK!<%++Jne|9)?;we|gZvuD*bf4()VX<4BYr$pvdv)@hoLeF2Em3P`TuiRR`%9>RrM>n_Fr+lp1TO)s^xMHIA$-rdZr`&UDcsm}{dmL->ymwSS ztMSv@CdpKPPoN=EUl$QXeiIRxaxO$~t{==_(OrYZZz2&!@=O{!7?$afPew z*PFX{u4Wd6<4MjxkH>}I_)p8j!k+^e{%WyP zcy+E!1qO8u8v_FmFsL_o%B*GtMTVK26o_sPlHVRAau<2Q)j3yv@ zK`Em-h`w3MXvPVTx#<#RjJh`1Ob5j}1mwstFchbjlw{_m7lWcUz?+dtgaMQ;K<=8} zSjH&Bs6BmN8Ka6k$RIAcIZ6LG85uxW7-j~TcAx&Rj8O@!=*wMg&u!ie3?PiEsBF4Y NIing|Y$?#E3;>{6_$mMZ diff --git a/docs/showcase/thesis-review.docx b/docs/showcase/thesis-review.docx index eddb636178667b475ced17ae6fbd87d58801f0ef..c4047cbaf3968ceabdeee69c1c0999c394ab1d19 100644 GIT binary patch delta 1329 zcmZ8gX;4#F6n=R@gaQf{i9ABHK|)2Hu$e%FM!;d276sI#AcHUj1}Fjn%P2dB zYq2E-71?Apq@Z+c5g8+P6sdqeNG&0OEEN!xVW1Z2y|Gp4`*FYfo%7xEo%hbW1LNe| z<7DH|V6vV$hG7Pnd8^Ra0f(!*3tYuVx=0WtCU~GD!boSIO%TCFs*|C4tK-q`oU=`0 zaF0q6q>a){&#sq9Hy`TZHJi4ij(vYYTa0-W8V+*UGUiw{{mY)@*NmM#8PS@KJtvo+ z#!s$khM%9Ud+P72oNY~L{V6W)+fnI!)ZNNC-s+XO9gXANnIA>oHM{O*QTw8UPx@t( z+Kx#cDmo#K$crG3FHzMkTWIWd_A!^NnLD-)g51Hn)7Ls@Y*y+!FXrSs_movR#cAV@ zFXoRW2K*%&iO-KDvUl7LnC6Tx1fD9S$x99QzF_YCE^BG*H>1ZcUTx1u9^6SK+7{`- z_XUH3WN*Qvj%sPsK^JFcbA%OV)^D~f!{O?xxNCsYz_S>Z%Co<6jo!S+zK~Bfqs#g( z3oK2-N%ow62aBy`%t6tlz?UT!vdeD?|CkEo%E*@oTx<0Xw&O#ZGb@TS-2F7h_@jE4 z^UIkg_k=<93;dM!vUJQT>GO=m!oH+xn_rJ{zZo6L{QKl#`=x2#fo49>x2tkJ{FP7L zVf^=+^u+r6C9A=mFZ1TDAJY>Qb8C4`jG_4@#prUkX=%3D^_iqQCRrru{h~MJS!>?< zd{p9srP3_uwWK&I%&BN-_)={DiqZQcmt1k(`I6G5!yAQ7Wqm(Q(#GT{#iQ8mI${P$-qnL<-4` zAcamT;xr=ae<)0+q_QaB$B=U{By_g`;i215G9fgx6ycQYCTdn9nl#dhTjUFnf|@BA zf=q=w0+N;hQiT=TDiv%5R3!sJl5#(SYf8`e{$RE8GZdsu6Zi!;Aa*m~5*iF^WB=U= z5IaqHzS@mpv3y=qn%l;t<59}hs%jOyKEpVM89{va*n#WQAEVL_U}+j1aOl<`L1X-H zg!BaLp7|7!m>GhU15VFS5cvU;T+sK1Ow17Ypf`|vZwDqS-9alAL3#+hRQ5=F1d{XM zYnAR`4J2XUhRP0QCR7A&%K{AeDWRhux~@J!73ESAhE?ffnAy7~;cke9VVNm>t{X3z zo1Bu)OWT!oDrw_u0#^+|`WY0cccSW@Y69o7K>_t>6QVElNWzUcmuv z92;a#LFOmsVxBla^8;iI+qS{n69CQImWx6_V~DP0R0occL<2Tj-8b9^Ni>Mk2B6F( zErE~8z@lvX|7RtKvI?-Kb+SdaOrKl9z0l4PTH9=}70JO(x$WEjH0Ol54NzbOg_awH O<)HFUSN#M93jPDApa}l} delta 1304 zcmX?bmHFURW}X0VW)=|!1_lm>y;COgC^G>`LroyLF=jm@klM`4MoI%~>*i)8ym2^7X;D4FuZ$cO7e=SCFEf%e789&8a>3a@n$%OD@mW((UZh z&D_E?x&Hpt18iL8d6(YoKELnx#d-I?%I|RZ*Yh7F{v&n%A&&e#cSfpw*l&^PQ$MMistTz%D)U`sP{oS;{SP@xCV} zs-L=dWbyL8xQTrSJ!{+3g!m2{NQ*^!{mcHB{rRbT-c}PcUoS_+sI{{)lGu~dw@6Ez z?XTtjr=YvLz>Mv>Ve(C@9gK=ovO5>tJjYspHe&&oK;|#qofQcxQuqG+g3cV%od5xo4VD{ zq;CEaz^D9rZri%2{*#3kD(g#IP1RUm+9|3_j_l#$K?f` z=HGuy+9~fodi43*RK;gkYa+waQ@7r^b~^3j#-9aNtMAYM>&I)CY~ysY-t42=D-OY% zKR>?~|IdIN=bIPkr!s>gmfctd6wkWGyr6iWY-6$nLMcyXHEjgRbeR5U0nwdSE@1k+ z9S0Lg$xVlYAZm`|evoXe(^;^nj_WcI_loOhuyM0|WheJN7n~gJS`HE}@NfaC+Pux{ z5m@ys-=!d~qhBCcwT`R&}5 zKLp!&p1H>Zv@4GaJaMo4f4@Fr`*xy}d7gotCG|{(@!VwdXG$Qo(Lm0`$raDQ8fOAIL6f&VQv}J}d?v%B z=sMX37?|^)^T>m8t-V)Y?=eOOhDmG;41x&v0$C>~J3dzc>C%27!?Mga{{1EU7T}a_3CA~@4WMS-}m?b7Z*d{7eiqLGhRM8 z1YGb^3e1cLURp)0QR0|~yAE0ili{T($8qt*jvy!ma)cKG5#%`fy9c|V!~Ok|(k!fF zR7Kk6NeM7<3wX(3m1Mp~$nw-3Uc6^Ro10l-s(YI3mmw*o#GVJzDIM!0FNWT>mPHa% zkMtPcHEr+`i{OJB$=T$EQwL(mvlXvyN<6afh!&m*5$aq++8XAZk&GZKA|L>57BEnCcA<5MXx}Sa;^X*|FdaPxh4&z}B$vJ-nVsAv6uQRJ|^%~K5di>Y%>t-h%+@QBh{QP+f5r(Gx$UxCh=1e%8zOZ)I9MJ;2X#nn=nw=<~kg3 zq2FV^mzKTuH}7NI{_Lv!BRe`m$2JqBICZ5;J_dorbV_Vr3hj~-ciei{|Tmb{^pMY=w& zv${C5>%a99&n0#A&akvrVGa zHG6LL$h*?#-bTPfW~7hD9;m`*OI|>AwKHPAHBnEF_*xH_A-kW7s=$Hfn670(oyuY0Ux^sW6>9Q&A{{C)CL;_<7h zbhj+MxkH`tJ%`W4+0Z-nD`NA_e$zIx7A`WH;J^k-D1P-A=;N;5y?U8pimY1>CqBk^&kiSem6`P}dYuRnA0 zEO%Neq@S8CFTeD5S9MzJHmPAUyGf@`{FAFw&R{(IXv2v((yYKJyC!QxSHfoMDx&+g zM|FHf8^6$_spK#QW5M64(rkTLC_05bHMH&*xgx7)jH{`OwEvboaizVvHsO{iE>pxQ z<(k?;6xCFhYTZp__%!j53|&v~=yoi{u3XQ*T|5R^fiiKZdcRXTfmUR9t0&Gk^;3Qi zG7J}?Nb7Gij~a#9J^vhRGrF(9{+F_pbLhcfe}MtoP|2$0*#50OfpUyQ_(m*p#+1gX zCOFxKfkFNuelEWpaSaRzb`J>VjxOa{K#VFZ&I#F>y{8BLk#EMo_)G2E)Y3!`B#&P# z`QdL51{=HU4rCuRcfEb+%hGJ--;cqrEj}ub zFuqAtJ^))+-Z1|uLs+hL9NoTN@`~Y65t``W_D!knnPq=giUYId!d-n4R!?%BNime%)OHb;?+va@ERF~0ATLi9 z4Y!k{?y2j>S15w4VmYOL&T-&riqSbR+c69l0P)D5??q_J`f zb_*qP?HK~MR~jT4!6T50vy?{Otpx;#W^}H8xB1+$e8K5ibpUOSAiJkNE9H@c$2l2v zl}c%jJpP@gQ!8l4{G&G7oF&m^*=~*3pC9p-7asiU25F<%=;-XeBVDyPw6oCrcjB>a zhvpD6rf!SeV%KR-7swRXjO z?JDeo?CIkp&z(_*^QEM7p$gT~A6CC&8g?W*khE==76VpS_#?Lw%sAT?SINLL3INAx zg57C~(*{ipPD^O>i~=;{RKSOeI0SSK*ol_{fifNeEdz}4iXaH!09)WDULFKgJc8#g z26%=M15^kw?uVS$g}_b=h5ca6=(K^REDoi8oa_4$iF3nUR{(;A!XePdROcDxE$3O( zzhe8Z1IL^`u_?WpfE+^N z#O6lL_j6XGSYRD12H>q>-1L9m2Y#g12n>IZ47Ef+#{d~iMeYYe<2w5}QULkLxxhjH zvC04!OGWOl|J9S=_MG!V?O%!f;S*y3BpZl>Omc($tffC3BY|m4ZZURPA)pt5Lsncs z-~eO5e-rSCngCT+3d&rPe^Q_yu|`ZbNmkPaSqAx%v_?Q904?k9|7vqE{wHI7;EJ`9 JfF2GE_YZgYo(cc} delta 2841 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 delta 1355 zcmeyipZV*4W}X0VW)=|!1_lm>(^Dq$C^G>`LroyLF{YgnNNs+~xKZl8yo}w1pXW>)8cgyym~dS*go+;Ps}MPmE0gN*r>HJ7;&^WDYth`7*C&K7&`$i$n(D3E{3s z<+n2aX~<68OsHR3t^yO#g*G+}-8Z{0(aAkQ~* zEHadtWDiJ6FOIcIHk-M$eT&461ko?L^|M4cZ7XkHS{aiWF#B?M*80bWM-Q*8M z>SQcY`o=uu&mWtknH65Hp@WV>9(K2ihAsqg1E*GE?~WtPXD07vXiH|bbvLw z27-m&+sIFjzb7zxmwh=o!+j;|6PJyZ#Btom_Rp z5JauLVGg36-S7ZW1~+X%RQ^qC5Vhu}DJMM1PJVUMOdiBzE%CW-4otjFz|=1U%m4^* zakBj_MX(x>7!y>24WR(YvY1?dOVk=C~;ecQFyZHZF#V@JIbOa9tGwt8%_oWVH6{0PAD}{zZk!1;6xF}NR+9~^ zL?(OO;Q=eWRQ_jsF3{9!AeIGU1bAdK`9Cn4WbX2Sj9++1hOuk%zB>va&I2H)e)8Wt z+8~bBT^UBT$?kW-GMPY5&g3=-2dIoG$7OP-i`-8B)^TjrVR9~GcYdD+%=j1 z9wZ)cJ1K3l|2-X$oojE%F!D{Fbx#WHheDUjhAQ0*44dXMFqk7e0AyLZPY!dpoXmS4 z><8)lGEAE;O+J4~bg~~rB<4QIxs~_T!H#pW-{ZXvs7np#Ksgk1Dkty1Z^)K?10)Cl D{`>;a diff --git a/docs/showcase/thesis.odt b/docs/showcase/thesis.odt index 207ec0827b8f99a55c7dec62bb57dde5c5fc91b1..36f6978663efe268c9a849d96502558cb0decc14 100644 GIT binary patch delta 2475 zcmZWqc|6ox6rUM;O(OHMFUbtTSVPldXfTEuRI-ySS%+k6F=Io^ztELmym+!YxcWI1vzV!Ha2dQy9Fs z!gdYChN|Q8lRUieVwB^a&s`zFVO3c!PW(Vo1>mi!yuDv}iB}=fp!mR|Qx(q!6DUwM zg=HB6EL8>S^!SC@OG0SHUZuRDl#L4$Zal!(JrbNnJL5gRySs1FGhW@UzLc_i~QN4T*x2=@{ zz${lG{?+HR7mj)6w=7rjj!?K|`EQT9=#nTGRyqF3053ZORZO)eC>VUIM#&}`XyIXO z8Hm^303ktV00dXv4p2#D-!@PQIDi2~fP4Qt5Lo*eR4{EF6MjOaPzc0|69NG#i$|L>Cb}p3gz7KeA9w;%n%W-e=eD65~-opm)0li z+A%+J4iP*nc_2o<0-Gs%64le*9lhL4*L&@AbhrfBdtXQe0X&TES>lE5F%VU+SQvXt zZS9_raB@i(%7MH^bVkQ9zakB+tcWGR9p#-Jb@z0Qm)oDkuI=ZQz0Hb0a9*v$EyG}b zPiI`8^08Q}j!s-G-O=sFQ=~y$Q50!aCASqtX{%H9ttr}F^!8In$RIuM5E7R`% z+GKE^M)sGE&zMNbPpERfrnpd)R$lNMYKT(30?&I&lkL4u6TE(#Y);sM=ez7&OMc7U zDf)AzrKd->S6+R@BR;&=tXn7i!PPl?C~j?UN9qNwT% z5p=>K`q5t7ZtrFo#mMy_?9dZd%*v&_timzK3Y0-aHTdf5`X6yW(sJSoF6mmJQJ4Tt z631f}F$%YP{3*z4R4m_qUrCZRdML<``(^#BqOX=?(mzuL^>*xb>qEQ5Ze65f!k zi7(#5+Fn`KCsJ~HHRGc$_=npr-lE^$CAFkgi~&*#}umRhT~X7q1+Cy2d7&^B^q8_7o+F5K!42+XGI~S4H&~A zfIdAsSQn94CJ46rE8D>Gm}5Ys?z6Lp2Am8esKLoicOR<3FFGSxk5cpMX3zntu?c+I zVG#R~qX}hAd@gn&ykqig4fKhs7DlB~c-U8l9rg#hQ%>Dt2kH@7-Bmc{_Mm zVVB}ypIYdKUHXw?mUY4Ut?8$e2L4>4?hVl3`@@EzWl%*~u5#2Rrr^z9jZ$+%M465q zaiH47{R79E5!_g~YC*`WK=7fwTOobuYs2C+boTKM^`&xo+dPrNm>GO;*L)9}&d10I`pjX8c;Qt6OdzC#yKeXqQxdyiw@|dJJ(W9arBSpy=ryG5IIZcIHji># zUujTChX8MII{=dL-AzKad0)4D$|j@+z=xNhx+gy{Q#J~X_s)r__S6v3C-~mJ5sqowGcO@Ucu^{Rldr4V z8_tL_F+&dE7M(k@&(Jn5_eo8JVRAZt+Z|q-CKG}-^hYCgm-tmYQ+-{N9a3$Wv0a%Y zJKFQvx~tj6eCIk!^7iE#>&tnoSnWOkrCpv0&*l8|*m_QU^{m(GdH6}0!v|hJK7lg& zSWK}F*Fb zmdQ@{-|HGsYqlGFf7na{+6;U(lLG~5q691s3(&B_Kr;cp`NW@nm)#z-FR8Pu=(m4v zZ=wr8CCVxN(p&zgV{hh@n$;Q!ih1bY6~`OYo~WPt70uRhuUg648EppQT3_CFtG@c=(w81OY0;Fd7~ GBl`<4eJCaX delta 2449 zcmZ8i2{@GN7dOUI7=~y=C3_e`%vfibVHRU4OZKfy%b+Z!q(OEeePgc}OR~jeNknDn zA7g3C?zZqxZe3B7s|9zy(RT0qJm2$s&U@bPJ>8fapv~wxx9E%%R!D>{oJ!Flik!%S>Z4GjLeUMUy0!J>(v+1&Ox61R_7gN*Cr^il=$*Id zd$jq`q{>rK+svlF7ME{4wxG>Zm?2-cB_VUqCr%v`{ec5MW{int+h;TM!nEhiD*eY(i$<4G15fo&X;o z$gov#NMJbC7pd(Z929mqC=3x1NNsc^*|K!tZ7I`E8b`?Jsq#)wM+?u#^0URxwo?Yq ze#R;C`=!GNvP<|#bN3aH8*QgPDmrpt1<5mgy=>WxhjT}|4!p;Pc9p&_(lfabonmig zqiMRlOgmxNoS--xQta=e8^7RF9eyg+-Zh)G;HS2z91;|ClQUSVA8=Lz)9ILfnIa)n zA+{;W6Ni$_kMB7#eM>)kl9_rj{7$E7=w;YuYF&Gm($Z{2jRqDQdQ{qwIiEAqrpD?{ zU{q}y-K!dt_U3X#LEO^lc#!~c#xarUP`eo0L6Z;n4$k&CtW;WbC^OwO!XOM$tCn~} zTp9zoj(4W*IAkeRNPY7>qYSX-M9GoL#h5vexskhdG6P@bBYDWs{^w z5G!G^Xm3L|t=HWx`MGF!R8{{7V!YBIZI+6tEQEZ6{w@<0Pfl*M-6XfDx!eN(R$SD2 zacS$-O}oTA#zMofwCQHIVL~bMLfG8?F3%?$dvRv7xF6h8=vuUwBs+SzbRV?2=|nR(&EF zna}uW@^(kbTKQ7}z|2-WyhD7x(!P9THn?|ixfP=nY+`31%WepSO)ERCbWC`?t*hCM zxzHS_EP{5B1MsDSBhQSQPc@})ZyKijn-pgGP**OOltEy~yd7+XEc7r4ftY1pN6`2y zy_j6T7?(7eUmdYm@AsAHU_8=_jwJ{&n_w%u0&tguM=pBGuXWLTt@1Z z?%3U4n}DIfS+@_TEYWr-xq9dZ>){-{lX&e+6fL2^`D${bk7~T!+pS-#=;~#fS1G#Y zjtdcYt{i@lO-K<=lCpe}Zzqn|x(uy}{Ywnj5W^NKJm}!A?CLc0DM8zOug7SRZ(m1~ z9uOL@u)x83wU1N3wBw8&P;(`+mbA`AfKFpy27scCcx_B< ztFF*#xpn`>sBY<2)*p3d?P9FQ=!8%C0v!|S(hVq9@zQipcwfx;|I^*$jU+h_Uz;du zy0mBoI?5dItSabzL31gB)h^ke4one42A6G77k?F~PMDdkROs)SQ4o^fWAyQM$|TME z1IsJ5f#pGOjTPOPMLd_n&PFk4BQVC8fcKXSa@Y}#-bRCKk$0<83#M?H>L+`itUO|y z`m%E@*G4CV;Fyb|k)~=lPD3XYJM+#hnjYD@CmND;Z99L6f0aRnL;{>fH#xcuXc5jw zYLw)qPLzDgtkeFzE-Id@%dKiTpg6hTckux)%msn-);D2bc~<-Q7VdI=Z~%puqj6Oz z(!o>VEJ0AVE0wriLeOsMx{E>sgM8GGk$ipkYU}aTakl^1)olTv8NmgA-ZUzQsnn&r zz}0)n45rP?5HrN>6Y#rP?J4+VL`+X)D@8L7o=B#)T&_9Ys>R0Z?lQ(W9-+v7#-sg9 z9AaMDHcGYi%g2YSz@PO=ks9$R#f9M{L9!M6As|_Q5;OBfHJ^sFOu_1Vo!w(zp;Z$Y zW=3_r_pwqq)2lFbq*`V11x5jIo?R@7;EpN?zcg@Nmc?4FRl>|M6MeQu0aOc$x1uHTmL&pe%#5&XAMAX zl{COJWfXZz8Q1Za`+?>DwKOb$M&7IcBXo_e90Up^+VVnk4gP*C0K;toR)}J}kpFJp zUzhRm const TAG_BY_KIND: Record = { i: 'mi', n: 'mn', o: 'mo', f: 'mi' }; +const BRACKETS = /^[([{|‖⟨⌊⌈)\]}⟩⌋⌉]$/; + // A row that MathML needs as a single element (mfrac, msup, … each take exactly one // child per slot), so a multi-node row is wrapped in . function slot(n: MathNode): string { @@ -27,7 +29,9 @@ export function astToMathml(n: MathNode): string { if (n.kind === 'f') return `${esc(n.s)}`; // Multi-letter identifiers stay upright in MathML unless split, and a number // like 3.14 is one token — so emit the run whole and let the class pick the tag. - return `<${TAG_BY_KIND[n.kind]}>${esc(n.s)}`; + // A bracket typed without \left stays glyph-height; only a fence stretches. + const attr = n.kind === 'o' && BRACKETS.test(n.s) ? ' stretchy="false"' : ''; + return `<${TAG_BY_KIND[n.kind]}${attr}>${esc(n.s)}`; } case 'frac': return `${slot(n.num)}${slot(n.den)}`; case 'script': { diff --git a/tests/unit/math.test.ts b/tests/unit/math.test.ts index 4b70122..4491cf3 100644 --- a/tests/unit/math.test.ts +++ b/tests/unit/math.test.ts @@ -54,6 +54,8 @@ describe('MathML', () => { expect(astToMathml(parseLatex('\\int_{0}^{1} x'))).toContain(''); // Brackets must be stretchy or they stay glyph-height next to a fraction. expect(astToMathml(parseLatex('\\left(x\\right)'))).toContain('('); + // A plain bracket must not: the dictionary would stretch it to the row's tallest. + expect(astToMathml(parseLatex('C(b) = \\frac{1}{2}'))).toContain('('); }); it('round-trips through the document element', () => {