@@ -19,6 +19,18 @@ import { useACSSettings } from '../hooks/use_acs_settings.js';
1919import { usePublicationStrings } from '../hooks/use_publication_strings.js' ;
2020import { PublicationStringModal } from '../modal/PublicationStringModal.js' ;
2121
22+ const MARKERS : Record < string , React . SVGProps < SVGTSpanElement > > = {
23+ '++' : { baselineShift : 'super' } ,
24+ '--' : { baselineShift : 'sub' } ,
25+ '**' : { fontStyle : 'italic' } ,
26+ } ;
27+
28+ function getMarker ( word : string ) {
29+ return Object . keys ( MARKERS ) . find (
30+ ( marker ) => word . startsWith ( marker ) && word . endsWith ( marker ) ,
31+ ) ;
32+ }
33+
2234const ReactRnd = styled ( Rnd ) `
2335 border: 1px solid transparent;
2436
@@ -51,10 +63,11 @@ function useWrapSVGText(params: UseWrapSVGTextParams) {
5163 labelWeight : style . fontWeight ,
5264 debugCanvasWidth : debugCanvas ? width : undefined ,
5365 } ) ;
54-
5566 const formattedText = text
56- . replaceAll ( / < s u p > (?< n > .* ?) < \/ s u p > / g, '++$1++ ' )
57- . replaceAll ( / < i > (?< j > .* ?) < \/ i > / g, '**$1**' ) ;
67+ . replaceAll ( / < s u p > (?< n > .* ?) < \/ s u p > / g, ' ++$1++ ' )
68+ . replaceAll ( / < s u b > (?< k > .* ?) < \/ s u b > / g, ' --$1-- ' )
69+ . replaceAll ( / < i > (?< j > .* ?) < \/ i > / g, ' **$1** ' )
70+ . trim ( ) ;
5871
5972 const lineHeight = labelSize * 1.6 ;
6073
@@ -63,10 +76,12 @@ function useWrapSVGText(params: UseWrapSVGTextParams) {
6376 let lineWidth = 0 ;
6477
6578 const spaceWidth = getTextWidth ( ' ' ) ;
66- const words = formattedText . split ( ' ' ) ;
79+ const words = formattedText . split ( / \s + / ) ;
6780
6881 for ( const word of words ) {
69- const wordWidth = getTextWidth ( word ) ;
82+ const marker = getMarker ( word ) ;
83+ const cleanWord = marker ? word . replaceAll ( marker , '' ) : word ;
84+ const wordWidth = getTextWidth ( cleanWord ) ;
7085 if ( lineWidth + wordWidth > width ) {
7186 lines . push ( line ) ;
7287 line = [ word ] ;
@@ -87,27 +102,22 @@ function useWrapSVGText(params: UseWrapSVGTextParams) {
87102 for ( const line of lines ) {
88103 let x = 0 ;
89104 for ( const word of line ) {
90- const isSuper = word . startsWith ( '++' ) && word . endsWith ( '++' ) ;
91- const isItalic = word . startsWith ( '**' ) && word . endsWith ( '**' ) ;
92- const baseLine = ctx . textBaseline ;
93-
94- let finalWord = `${ word } ` ;
95- if ( isSuper ) {
96- finalWord = word . replaceAll ( '++' , '' ) ;
97-
98- ctx . textBaseline = 'bottom' ;
99- } else if ( isItalic ) {
100- finalWord = word . replaceAll ( '**' , '' ) ;
105+ const marker = getMarker ( word ) ;
106+ const finalWord = marker ? word . replaceAll ( marker , '' ) : word ;
107+
108+ if ( marker === '++' ) {
109+ ctx . fillText ( finalWord , x , y - lineHeight * 0.3 ) ;
110+ } else if ( marker === '--' ) {
111+ ctx . fillText ( finalWord , x , y + lineHeight * 0.3 ) ;
112+ } else {
113+ ctx . fillText ( finalWord , x , y ) ;
101114 }
102115
103- ctx ?. fillText ( finalWord , x , y ) ;
104116 x += getTextWidth ( finalWord ) ;
105-
106- ctx . textBaseline = baseLine ;
107117 }
108-
109118 y += lineHeight ;
110119 }
120+ ctx . fillStyle = 'black' ;
111121 } ) ;
112122
113123 return { lines, lineHeight } ;
@@ -146,28 +156,35 @@ function PublicationText(props: PublicationTextProps) {
146156 dominantBaseline = "hanging"
147157 >
148158 { line . map ( ( word , wordIndex ) => {
149- if ( word . startsWith ( '++' ) && word . endsWith ( '++' ) ) {
159+ const marker = getMarker ( word ) ;
160+
161+ if ( marker ) {
162+ const props = MARKERS [ marker ] ;
163+ const isBaselineShift = 'baselineShift' in props ;
164+ const fontSize = isBaselineShift
165+ ? Math . floor ( ( 5 / 6 ) * textStyleWithSize . fontSize )
166+ : undefined ;
167+
150168 return (
151169 < tspan
152170 // eslint-disable-next-line react/no-array-index-key
153171 key = { wordIndex }
154- baselineShift = "super"
155- fontSize = { Math . floor ( ( 5 / 6 ) * textStyleWithSize . fontSize ) }
172+ fontSize = { fontSize }
173+ { ... props }
156174 >
157- { word . replaceAll ( '++' , '' ) }
158- </ tspan >
159- ) ;
160- } else if ( word . startsWith ( '**' ) && word . endsWith ( '**' ) ) {
161- return (
162- // eslint-disable-next-line react/no-array-index-key
163- < tspan key = { wordIndex } fontStyle = "italic" >
164- { word . replaceAll ( '**' , '' ) }
175+ { word . replaceAll ( marker , '' ) }
165176 </ tspan >
166177 ) ;
167- } else {
168- // eslint-disable-next-line react/no-array-index-key
169- return < tspan key = { wordIndex } > { word } </ tspan > ;
170178 }
179+
180+ const addSpace =
181+ ! line [ wordIndex + 1 ] ?. startsWith ( '--' ) ||
182+ / \s $ / . test ( word ) ||
183+ / [ ^ a - z A - Z 0 - 9 ] $ / . test ( word ) ;
184+ return (
185+ // eslint-disable-next-line react/no-array-index-key
186+ < tspan key = { wordIndex } > { addSpace ? `${ word } ` : word } </ tspan >
187+ ) ;
171188 } ) }
172189 </ SVGStyledText >
173190 ) ) }
0 commit comments