Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Embed local MathJax + some fixes

uwx ddfd0645 530740b5

+777 -13
+2 -1
package.json
··· 111 111 "@ipld/dag-cbor": "^9.2.0", 112 112 "@lingui/core": "^5.9.2", 113 113 "@lingui/react": "^5.9.2", 114 + "@mathjax/src": "^4.1.1", 114 115 "@miblanchard/react-native-slider": "^2.6.0", 115 116 "@mozzius/expo-dynamic-app-icon": "^1.8.0", 116 117 "@react-native-async-storage/async-storage": "2.2.0", ··· 186 187 "fast-text-encoding": "^1.0.6", 187 188 "fuse.js": "^7.1.0", 188 189 "hls.js": "^1.6.2", 190 + "html-entities": "^2.6.0", 189 191 "idb-keyval": "^6.2.2", 190 192 "js-sha256": "^0.9.0", 191 193 "jwt-decode": "^4.0.0", ··· 217 219 "react-native-edge-to-edge": "^1.6.0", 218 220 "react-native-gesture-handler": "~2.28.0", 219 221 "react-native-keyboard-controller": "^1.21.0", 220 - "react-native-mathjax-html-to-svg": "^1.1.0", 221 222 "react-native-pager-view": "6.8.0", 222 223 "react-native-progress": "bluesky-social/react-native-progress", 223 224 "react-native-qrcode-styled": "^0.3.3",
+6 -2
src/components/Post/MastodonHtmlContent.tsx
··· 6 6 View, 7 7 type ViewStyle, 8 8 } from 'react-native' 9 - import {MathJaxSvg} from 'react-native-mathjax-html-to-svg' 10 9 import {type AppBskyFeedPost} from '@atproto/api' 11 10 import {msg} from '@lingui/core/macro' 12 11 import {useLingui} from '@lingui/react' 13 12 import {Trans} from '@lingui/react/macro' 14 13 14 + import {MathJaxSvg} from '#/lib/mathjax' 15 15 import {useRenderMastodonHtml} from '#/state/preferences/render-mastodon-html' 16 16 import {atoms as a} from '#/alf' 17 17 import {Button, ButtonText} from '#/components/Button' ··· 362 362 return <Text key={key}>{children}</Text> 363 363 } 364 364 case 'br': 365 - return '\n' 365 + return ( 366 + <Text key={key} style={textStyle}> 367 + {'\n'} 368 + </Text> 369 + ) 366 370 case 'span': { 367 371 const children = [...element.childNodes].map((child, i) => 368 372 renderNode(child, String(i), insideLink),
+169
src/lib/mathjax/HTMLStyles.ts
··· 1 + import {type StyleProp, type TextStyle} from 'react-native' 2 + 3 + import { 4 + ABSOLUTE_FONT_SIZE, 5 + PERC_SUPPORTED_STYLES, 6 + stylePropTypes, 7 + STYLESETS, 8 + } from './HTMLUtils' 9 + 10 + /** 11 + * Converts a html style string to an object 12 + * @param str: the style string 13 + * @return the style as an object 14 + */ 15 + export function cssStringToObject(str: string): Record<string, string> { 16 + return str 17 + .split(';') 18 + .map(prop => prop.split(':')) 19 + .reduce( 20 + (acc, prop) => { 21 + if (prop.length === 2) { 22 + acc[prop[0].trim()] = prop[1].trim() 23 + } 24 + return acc 25 + }, 26 + {} as Record<string, string>, 27 + ) 28 + } 29 + 30 + /** 31 + * Converts a html style to its equivalent react native style 32 + * @param {object} css: object of key value css strings 33 + * @param {string} styleset: the styleset to convert the styles against 34 + * @param {object} { parentTag, emSize, ignoredStyles } 35 + * @returns {object} 36 + */ 37 + function cssToRNStyle( 38 + css: Record<string, string>, 39 + styleset: string, 40 + { 41 + emSize, 42 + ptSize, 43 + ignoredStyles, 44 + allowedStyles, 45 + }: { 46 + emSize: number 47 + ptSize: number 48 + ignoredStyles?: string[] 49 + allowedStyles?: string[] 50 + }, 51 + ) { 52 + const styleProps = stylePropTypes[styleset as keyof typeof stylePropTypes] 53 + return Object.keys(css) 54 + .filter(key => (allowedStyles ? allowedStyles.indexOf(key) !== -1 : true)) 55 + .filter(key => (ignoredStyles || []).indexOf(key) === -1) 56 + .map(key => [key, css[key]]) 57 + .map(([key, value]) => { 58 + // Key convert 59 + return [ 60 + key 61 + .split('-') 62 + .map((item, index) => 63 + index === 0 ? item : item[0].toUpperCase() + item.substr(1), 64 + ) 65 + .join(''), 66 + value, 67 + ] 68 + }) 69 + .map(([key, value]) => { 70 + if (styleProps.indexOf(key) === -1) { 71 + return undefined 72 + } 73 + 74 + if (typeof value === 'string') { 75 + value = value.replace(/\s*!\s*important/, '') 76 + 77 + if (key === 'textDecoration') { 78 + key = 'textDecorationLine' 79 + } 80 + 81 + if (key === 'display' && ['flex', 'none'].indexOf(value) === -1) { 82 + return [key, 'flex'] 83 + } 84 + if (key === 'textAlign') { 85 + if ( 86 + ['left', 'right', 'justify', 'auto', 'center'].indexOf(value) !== -1 87 + ) { 88 + return [key, value] 89 + } 90 + if (value === 'start') { 91 + return [key, 'left'] 92 + } 93 + if (value === 'end') { 94 + return [key, 'right'] 95 + } 96 + return undefined 97 + } 98 + if ( 99 + value 100 + .replace(/[-_]/g, '') 101 + .search(/\binherit\b|\bnormal\b|\bnone\b|(calc|var)\(.*\)/) !== -1 102 + ) { 103 + return undefined 104 + } 105 + // See if we can use the percentage directly 106 + if ( 107 + value.search(/[\d.]+%/) !== -1 && 108 + PERC_SUPPORTED_STYLES.indexOf(key) !== -1 109 + ) { 110 + return [key, value] 111 + } 112 + if (value.search(/[\d.]+em/) !== -1) { 113 + const pxSize = parseFloat(value.replace('em', '')) * emSize 114 + return [key, pxSize] 115 + } 116 + if (value.search(/[\d.]+pt/) !== -1) { 117 + const pxSize = parseFloat(value.replace('pt', '')) * ptSize 118 + return [key, pxSize] 119 + } 120 + // See if we can convert a 20px to a 20 automagically 121 + const numericValue = parseFloat(value.replace('px', '')) 122 + if (key !== 'fontWeight' && !isNaN(numericValue)) { 123 + if (styleProps.indexOf(key) !== -1) { 124 + return [key, numericValue] 125 + } 126 + } 127 + if (key === 'fontSize') { 128 + return mapAbsoluteFontSize(key, value) 129 + } 130 + } 131 + return [key, value] 132 + }) 133 + .filter(prop => prop !== undefined) 134 + .reduce( 135 + (acc, [key, value]) => { 136 + acc[key] = value 137 + return acc 138 + }, 139 + {} as Record<string, string | number | null>, 140 + ) 141 + } 142 + 143 + /** 144 + * @param {string} key: the key of style 145 + * @param {string} value: the value of style 146 + * @return {array} 147 + */ 148 + function mapAbsoluteFontSize( 149 + key: string, 150 + value: string, 151 + ): [string, string | number | null] { 152 + let fontSize: string | number | null = value 153 + if (ABSOLUTE_FONT_SIZE.hasOwnProperty(value)) { 154 + fontSize = ABSOLUTE_FONT_SIZE[value as keyof typeof ABSOLUTE_FONT_SIZE] 155 + } 156 + return [key, fontSize] 157 + } 158 + 159 + /** 160 + * @param str: the css style string 161 + * @param styleset=STYLESETS.TEXT: the styleset to convert the styles against 162 + * @return a react native style object 163 + */ 164 + export function cssStringToRNStyle( 165 + str: string, 166 + styleset = STYLESETS.TEXT, 167 + ): StyleProp<TextStyle> { 168 + return cssToRNStyle(cssStringToObject(str), styleset, {emSize: 1, ptSize: 1}) 169 + }
+155
src/lib/mathjax/HTMLUtils.ts
··· 1 + const TextStylePropTypes = [ 2 + 'display', 3 + 'width', 4 + 'height', 5 + 'start', 6 + 'end', 7 + 'top', 8 + 'left', 9 + 'right', 10 + 'bottom', 11 + 'minWidth', 12 + 'maxWidth', 13 + 'minHeight', 14 + 'maxHeight', 15 + 'margin', 16 + 'marginVertical', 17 + 'marginHorizontal', 18 + 'marginTop', 19 + 'marginBottom', 20 + 'marginLeft', 21 + 'marginRight', 22 + 'marginStart', 23 + 'marginEnd', 24 + 'padding', 25 + 'paddingVertical', 26 + 'paddingHorizontal', 27 + 'paddingTop', 28 + 'paddingBottom', 29 + 'paddingLeft', 30 + 'paddingRight', 31 + 'paddingStart', 32 + 'paddingEnd', 33 + 'borderWidth', 34 + 'borderTopWidth', 35 + 'borderStartWidth', 36 + 'borderEndWidth', 37 + 'borderRightWidth', 38 + 'borderBottomWidth', 39 + 'borderLeftWidth', 40 + 'position', 41 + 'flexDirection', 42 + 'flexWrap', 43 + 'justifyContent', 44 + 'alignItems', 45 + 'alignSelf', 46 + 'alignContent', 47 + 'overflow', 48 + 'flex', 49 + 'flexGrow', 50 + 'flexShrink', 51 + 'flexBasis', 52 + 'aspectRatio', 53 + 'zIndex', 54 + 'direction', 55 + 'shadowColor', 56 + 'shadowOffset', 57 + 'shadowOpacity', 58 + 'shadowRadius', 59 + 'transform', 60 + 'transformMatrix', 61 + 'decomposedMatrix', 62 + 'scaleX', 63 + 'scaleY', 64 + 'rotation', 65 + 'translateX', 66 + 'translateY', 67 + 'backfaceVisibility', 68 + 'backgroundColor', 69 + 'borderColor', 70 + 'borderTopColor', 71 + 'borderRightColor', 72 + 'borderBottomColor', 73 + 'borderLeftColor', 74 + 'borderStartColor', 75 + 'borderEndColor', 76 + 'borderRadius', 77 + 'borderTopLeftRadius', 78 + 'borderTopRightRadius', 79 + 'borderTopStartRadius', 80 + 'borderTopEndRadius', 81 + 'borderBottomLeftRadius', 82 + 'borderBottomRightRadius', 83 + 'borderBottomStartRadius', 84 + 'borderBottomEndRadius', 85 + 'borderStyle', 86 + 'opacity', 87 + 'elevation', 88 + 'color', 89 + 'fontFamily', 90 + 'fontSize', 91 + 'fontStyle', 92 + 'fontWeight', 93 + 'fontVariant', 94 + 'textShadowOffset', 95 + 'textShadowRadius', 96 + 'textShadowColor', 97 + 'letterSpacing', 98 + 'lineHeight', 99 + 'textAlign', 100 + 'textAlignVertical', 101 + 'includeFontPadding', 102 + 'textDecoration', 103 + 'textDecorationLine', 104 + 'textDecorationStyle', 105 + 'textDecorationColor', 106 + 'textTransform', 107 + 'writingDirection', 108 + ] 109 + 110 + export const ABSOLUTE_FONT_SIZE = { 111 + medium: 14, 112 + 'xx-small': 8.5, 113 + 'x-small': 10, 114 + small: 12, 115 + large: 17, 116 + 'x-large': 20, 117 + 'xx-large': 24, 118 + smaller: 13.3, 119 + larger: 16, 120 + length: null, 121 + initial: null, 122 + inherit: null, 123 + unset: null, 124 + } 125 + 126 + // As of react-native 0.48, this might change in the future 127 + export const PERC_SUPPORTED_STYLES = [ 128 + 'width', 129 + 'height', 130 + 'top', 131 + 'bottom', 132 + 'left', 133 + 'right', 134 + 'margin', 135 + 'marginBottom', 136 + 'marginTop', 137 + 'marginLeft', 138 + 'marginRight', 139 + 'marginHorizontal', 140 + 'marginVertical', 141 + 'padding', 142 + 'paddingBottom', 143 + 'paddingTop', 144 + 'paddingLeft', 145 + 'paddingRight', 146 + 'paddingHorizontal', 147 + 'paddingVertical', 148 + ] 149 + 150 + export const STYLESETS = Object.freeze({ 151 + TEXT: 'text', 152 + }) 153 + export const stylePropTypes = { 154 + [STYLESETS.TEXT]: TextStylePropTypes, 155 + }
+11
src/lib/mathjax/env.d.ts
··· 1 + declare module '@mathjax/src/components/mjs/source.js' { 2 + export const source: { 3 + [key: string]: string 4 + } 5 + } 6 + 7 + declare module '@mathjax/src/components/cjs/source.js' { 8 + export const source: { 9 + [key: string]: string 10 + } 11 + }
+356
src/lib/mathjax/index.tsx
··· 1 + /*! 2 + MIT License 3 + 4 + Copyright (c) 2021 G.Burak 5 + 6 + Permission is hereby granted, free of charge, to any person obtaining a copy 7 + of this software and associated documentation files (the "Software"), to deal 8 + in the Software without restriction, including without limitation the rights 9 + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 + copies of the Software, and to permit persons to whom the Software is 11 + furnished to do so, subject to the following conditions: 12 + 13 + The above copyright notice and this permission notice shall be included in all 14 + copies or substantial portions of the Software. 15 + 16 + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 + SOFTWARE. 23 + */ 24 + 25 + import React, {Fragment, memo, type ReactNode} from 'react' 26 + import { 27 + type StyleProp, 28 + Text, 29 + type TextStyle, 30 + View, 31 + type ViewStyle, 32 + } from 'react-native' 33 + import {SvgFromXml} from 'react-native-svg' 34 + import {liteAdaptor} from '@mathjax/src/js/adaptors/liteAdaptor.js' 35 + import {RegisterHTMLHandler} from '@mathjax/src/js/handlers/html.js' 36 + import {TeX} from '@mathjax/src/js/input/tex.js' 37 + import {mathjax} from '@mathjax/src/js/mathjax.js' 38 + import {SVG} from '@mathjax/src/js/output/svg.js' 39 + import {decode} from 'html-entities' 40 + 41 + import {cssStringToRNStyle} from './HTMLStyles' 42 + 43 + const packageList = [ 44 + '[tex]/action', 45 + '[tex]/ams', 46 + '[tex]/amscd', 47 + '[tex]/autoload', 48 + '[tex]/bbm', 49 + '[tex]/bboldx', 50 + '[tex]/bbox', 51 + '[tex]/begingroup', 52 + '[tex]/boldsymbol', 53 + '[tex]/braket', 54 + '[tex]/bussproofs', 55 + '[tex]/cancel', 56 + '[tex]/cases', 57 + '[tex]/centernot', 58 + '[tex]/color', 59 + '[tex]/colortbl', 60 + '[tex]/colorv2', 61 + '[tex]/configmacros', 62 + '[tex]/dsfont', 63 + '[tex]/empheq', 64 + '[tex]/enclose', 65 + '[tex]/extpfeil', 66 + '[tex]/gensymb', 67 + '[tex]/html', 68 + '[tex]/mathtools', 69 + '[tex]/mhchem', 70 + '[tex]/newcommand', 71 + '[tex]/noerrors', 72 + '[tex]/noundefined', 73 + '[tex]/physics', 74 + '[tex]/require', 75 + '[tex]/setoptions', 76 + '[tex]/tagformat', 77 + '[tex]/texhtml', 78 + '[tex]/textcomp', 79 + '[tex]/textmacros', 80 + '[tex]/unicode', 81 + '[tex]/units', 82 + '[tex]/upgreek', 83 + '[tex]/verb', 84 + ].sort() 85 + 86 + import '@mathjax/src/js/util/entities/all.js' 87 + 88 + import { 89 + type LiteElement, 90 + type LiteNode, 91 + } from '@mathjax/src/js/adaptors/lite/Element.js' 92 + 93 + const adaptor = liteAdaptor() 94 + 95 + RegisterHTMLHandler(adaptor) 96 + 97 + const tagToStyle: Record<string, StyleProp<TextStyle>> = { 98 + u: {textDecorationLine: 'underline'}, 99 + ins: {textDecorationLine: 'underline'}, 100 + s: {textDecorationLine: 'line-through'}, 101 + del: {textDecorationLine: 'line-through'}, 102 + b: {fontWeight: 'bold'}, 103 + strong: {fontWeight: 'bold'}, 104 + i: {fontStyle: 'italic'}, 105 + cite: {fontStyle: 'italic'}, 106 + dfn: {fontStyle: 'italic'}, 107 + em: {fontStyle: 'italic'}, 108 + mark: {backgroundColor: 'yellow'}, 109 + small: {fontSize: 8}, 110 + } 111 + 112 + const getScale = (_svgString: string): [number, number] => { 113 + const svgString = _svgString.match(/<svg([^\>]+)>/gi)?.join('') 114 + 115 + let [width, height] = (svgString || '') 116 + .replace( 117 + /.* width=\"([\d\.]*)[ep]x\".*height=\"([\d\.]*)[ep]x\".*/gi, 118 + '$1,$2', 119 + ) 120 + .split(/\,/gi) 121 + 122 + let [width2, height2] = [parseFloat(width), parseFloat(height)] 123 + 124 + return [width2, height2] 125 + } 126 + 127 + const applyScale = (svgString: string, [width, height]: [number, number]) => { 128 + let retSvgString = svgString.replace( 129 + /(<svg[^\>]+height=\")([\d\.]+)([ep]x\"[^\>]+>)/gi, 130 + `$1${height}$3`, 131 + ) 132 + 133 + retSvgString = retSvgString.replace( 134 + /(<svg[^\>]+width=\")([\d\.]+)([ep]x\"[^\>]+>)/gi, 135 + `$1${width}$3`, 136 + ) 137 + 138 + retSvgString = retSvgString.replace( 139 + /(<svg[^\>]+width=\")([0]+[ep]?x?)(\"[^\>]+>)/gi, 140 + '$10$3', 141 + ) 142 + retSvgString = retSvgString.replace( 143 + /(<svg[^\>]+height=\")([0]+[ep]?x?)(\"[^\>]+>)/gi, 144 + '$10$3', 145 + ) 146 + 147 + return retSvgString 148 + } 149 + 150 + const applyColor = (svgString: string, fillColor?: string) => { 151 + return svgString.replace(/currentColor/gim, `${fillColor}`) 152 + } 153 + 154 + const GenerateSvgComponent = ({ 155 + item, 156 + fontSize, 157 + color, 158 + }: { 159 + item: LiteElement 160 + fontSize: number 161 + color?: string 162 + }) => { 163 + let svgText = adaptor.innerHTML(item) 164 + 165 + const [width, height] = getScale(svgText) 166 + 167 + svgText = svgText.replace(/font-family=\"([^\"]*)\"/gim, '') 168 + 169 + svgText = applyScale(svgText, [width * fontSize, height * fontSize]) 170 + 171 + svgText = applyColor(svgText, color) 172 + 173 + return ( 174 + <Text> 175 + <SvgFromXml xml={svgText} /> 176 + </Text> 177 + ) 178 + } 179 + 180 + const GenerateTextComponent = ({ 181 + fontSize, 182 + color, 183 + index, 184 + item, 185 + parentStyle = null, 186 + textStyle, 187 + }: { 188 + fontSize: number 189 + color?: string 190 + index: number 191 + item: LiteNode 192 + parentStyle?: StyleProp<TextStyle> | null 193 + textStyle?: StyleProp<TextStyle> 194 + }) => { 195 + let rnStyle: StyleProp<TextStyle> | null = null 196 + let text = null 197 + 198 + if ( 199 + item?.kind !== '#text' && 200 + item?.kind !== 'mjx-container' && 201 + item?.kind !== '#comment' 202 + ) { 203 + let htmlStyle = adaptor.allStyles(item as LiteElement) || null 204 + 205 + if (htmlStyle) { 206 + rnStyle = cssStringToRNStyle(htmlStyle) 207 + } 208 + 209 + rnStyle = [tagToStyle[item?.kind] || null, rnStyle] 210 + } 211 + 212 + if (item?.kind === '#text') { 213 + text = decode(adaptor.value(item) || '') 214 + rnStyle = parentStyle ? parentStyle : null 215 + } else if (item?.kind === 'br') { 216 + text = '\n\n' 217 + rnStyle = {width: '100%', overflow: 'hidden', height: 0} 218 + } 219 + 220 + return ( 221 + <Fragment> 222 + {text ? ( 223 + <Text 224 + key={`sub-${index}`} 225 + style={[{fontSize: fontSize * 2, color}, rnStyle ?? {}, textStyle]}> 226 + {text} 227 + </Text> 228 + ) : item?.kind === 'mjx-container' ? ( 229 + <GenerateSvgComponent 230 + key={`sub-${index}`} 231 + item={item as LiteElement} 232 + fontSize={fontSize} 233 + color={color} 234 + /> 235 + ) : (item as LiteElement).children?.length ? ( 236 + (item as LiteElement).children.map((subItem, subIndex) => ( 237 + <GenerateTextComponent 238 + key={`sub-${index}-${subIndex}`} 239 + color={color} 240 + fontSize={fontSize} 241 + item={subItem} 242 + index={subIndex} 243 + parentStyle={rnStyle} 244 + /> 245 + )) 246 + ) : null} 247 + </Fragment> 248 + ) 249 + } 250 + 251 + const ConvertToComponent = ({ 252 + texString = '', 253 + fontSize = 12, 254 + fontCache = false, 255 + color, 256 + textStyle, 257 + }: { 258 + texString?: ReactNode 259 + fontSize?: number 260 + fontCache?: boolean 261 + color?: string 262 + textStyle?: TextStyle 263 + }) => { 264 + if (!texString) { 265 + return '' 266 + } 267 + 268 + const tex = new TeX({ 269 + packages: packageList, 270 + inlineMath: [ 271 + ['$', '$'], 272 + ['\\(', '\\)'], 273 + ], 274 + displayMath: [ 275 + ['$$', '$$'], 276 + ['\\[', '\\]'], 277 + ], 278 + processEscapes: true, 279 + }) 280 + 281 + const svg = new SVG({ 282 + fontCache: fontCache ? 'local' : 'none', 283 + mtextInheritFont: true, 284 + merrorInheritFont: true, 285 + }) 286 + 287 + const html = mathjax.document(texString, { 288 + InputJax: tex, 289 + OutputJax: svg, 290 + renderActions: {assistiveMml: []}, 291 + }) 292 + 293 + html.render() 294 + 295 + if (Array.from(html.math).length === 0) { 296 + adaptor.remove(html.outputJax.styleSheet(html.document)) 297 + const cache = adaptor.elementById( 298 + adaptor.body(html.document), 299 + 'MJX-SVG-global-cache', 300 + ) 301 + if (cache) adaptor.remove(cache) 302 + } 303 + 304 + const nodes = adaptor.childNodes(adaptor.body(html.document)) 305 + 306 + return ( 307 + <> 308 + {nodes?.map((item, index) => ( 309 + <GenerateTextComponent 310 + key={index} 311 + textStyle={textStyle} 312 + item={item} 313 + index={index} 314 + fontSize={fontSize} 315 + color={color} 316 + /> 317 + ))} 318 + </> 319 + ) 320 + } 321 + 322 + export const MathJaxSvg = memo(function MathJaxSvg(props: { 323 + fontSize?: number 324 + color?: string 325 + fontCache?: boolean 326 + style?: ViewStyle 327 + textStyle?: TextStyle 328 + children?: ReactNode 329 + }) { 330 + const textext = props.children || '' 331 + const fontSize = props.fontSize ? props.fontSize / 2 : 14 332 + const color = props.color ? props.color : 'black' 333 + const fontCache = props.fontCache 334 + const style = props.style ? props.style : null 335 + 336 + return ( 337 + <View 338 + style={{ 339 + flexDirection: 'row', 340 + flexWrap: 'wrap', 341 + flexShrink: 1, 342 + alignItems: 'center', 343 + ...style, 344 + }}> 345 + {textext ? ( 346 + <ConvertToComponent 347 + textStyle={props.textStyle} 348 + fontSize={fontSize} 349 + color={color} 350 + texString={textext} 351 + fontCache={fontCache} 352 + /> 353 + ) : null} 354 + </View> 355 + ) 356 + })
+78 -10
yarn.lock
··· 3967 3967 "@babel/runtime" "^7.20.13" 3968 3968 "@lingui/core" "5.9.2" 3969 3969 3970 + "@mathjax/mathjax-newcm-font@4.1.1": 3971 + version "4.1.1" 3972 + resolved "https://registry.yarnpkg.com/@mathjax/mathjax-newcm-font/-/mathjax-newcm-font-4.1.1.tgz#4e82b3ef8e570b6c8eefb3a8063a656c15e3ee35" 3973 + integrity sha512-LeV5AWzoR7k/k2tg5mW0Ad3Jr9oK9guW/zBUIP8aoiIZcZIhvAV9dlbtUSqSe1wgEBUP1KOcJXcrE/NxOqkxlQ== 3974 + 3975 + "@mathjax/src@^4.1.1": 3976 + version "4.1.1" 3977 + resolved "https://registry.yarnpkg.com/@mathjax/src/-/src-4.1.1.tgz#288884a9b414ae79a78ae7d72bd7c4ebea26b82f" 3978 + integrity sha512-YW01BuT+un9l4ZADYZ3K+VCVImEuwI82376gfua3Ycjsp7r0TvXeU61Z5M8rRlGY2jrTjBMskcw98LHV6zIC6A== 3979 + dependencies: 3980 + "@mathjax/mathjax-newcm-font" "4.1.1" 3981 + mhchemparser "^4.2.1" 3982 + mj-context-menu "^1.0.0" 3983 + speech-rule-engine "5.0.0-beta.6" 3984 + 3970 3985 "@messageformat/parser@^5.0.0": 3971 3986 version "5.1.0" 3972 3987 resolved "https://registry.yarnpkg.com/@messageformat/parser/-/parser-5.1.0.tgz#05e4851c782d633ad735791dd0a68ee65d2a7201" ··· 6045 6060 "@webassemblyjs/ast" "1.11.6" 6046 6061 "@xtuc/long" "4.2.2" 6047 6062 6063 + "@xmldom/xmldom@0.9.8": 6064 + version "0.9.8" 6065 + resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.9.8.tgz#1471e82bdff9e8f20ee8bbe60d4ffa8a516e78d8" 6066 + integrity sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A== 6067 + 6048 6068 "@xmldom/xmldom@^0.8.8": 6049 6069 version "0.8.10" 6050 6070 resolved "https://registry.yarnpkg.com/@xmldom/xmldom/-/xmldom-0.8.10.tgz#a1337ca426aa61cef9fe15b5b28e340a72f6fa99" ··· 7332 7352 resolved "https://registry.yarnpkg.com/commander/-/commander-11.0.0.tgz#43e19c25dbedc8256203538e8d7e9346877a6f67" 7333 7353 integrity sha512-9HMlXtt/BNoYr8ooyjjNRdIilOTkVJXB+GhxMTtOKwk0R4j4lS4NpjuqmRxroBfnfTSHQIHQB7wryHhXarNjmQ== 7334 7354 7355 + commander@14.0.2: 7356 + version "14.0.2" 7357 + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.2.tgz#b71fd37fe4069e4c3c7c13925252ada4eba14e8e" 7358 + integrity sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ== 7359 + 7335 7360 commander@2.20.0: 7336 7361 version "2.20.0" 7337 7362 resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" ··· 9889 9914 minipass "^7.1.2" 9890 9915 path-scurry "^2.0.0" 9891 9916 9917 + glob@^13.0.3: 9918 + version "13.0.6" 9919 + resolved "https://registry.yarnpkg.com/glob/-/glob-13.0.6.tgz#078666566a425147ccacfbd2e332deb66a2be71d" 9920 + integrity sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw== 9921 + dependencies: 9922 + minimatch "^10.2.2" 9923 + minipass "^7.1.3" 9924 + path-scurry "^2.0.2" 9925 + 9892 9926 glob@^7.0.3, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: 9893 9927 version "7.2.3" 9894 9928 resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" ··· 10174 10208 resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.4.0.tgz#edd0cee70402584c8c76cc2c0556db09d1f45061" 10175 10209 integrity sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ== 10176 10210 10177 - html-entities@^2.4.0: 10211 + html-entities@^2.6.0: 10178 10212 version "2.6.0" 10179 10213 resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.6.0.tgz#7c64f1ea3b36818ccae3d3fb48b6974208e984f8" 10180 10214 integrity sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ== ··· 12501 12535 resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" 12502 12536 integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== 12503 12537 12538 + minipass@^7.1.3: 12539 + version "7.1.3" 12540 + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.3.tgz#79389b4eb1bb2d003a9bba87d492f2bd37bdc65b" 12541 + integrity sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A== 12542 + 12504 12543 minizlib@^3.1.0: 12505 12544 version "3.1.0" 12506 12545 resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-3.1.0.tgz#6ad76c3a8f10227c9b51d1c9ac8e30b27f5a251c" ··· 12508 12547 dependencies: 12509 12548 minipass "^7.1.2" 12510 12549 12550 + mj-context-menu@^1.0.0: 12551 + version "1.0.0" 12552 + resolved "https://registry.yarnpkg.com/mj-context-menu/-/mj-context-menu-1.0.0.tgz#143edb0a57161d1743fabf0f8459f4cb65ef19bc" 12553 + integrity sha512-OSgBFQRCVhrZwRa9lhqnKcJU92dd/YXgBjup0uyeuj9bOaVsf4myOyrjU4PfhYkdDk6AqVUTov7v5uFMvIbduA== 12554 + dependencies: 12555 + rimraf "^6.0.1" 12556 + 12511 12557 mkdirp@^1.0.4: 12512 12558 version "1.0.4" 12513 12559 resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" ··· 13017 13063 resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 13018 13064 integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 13019 13065 13020 - package-json-from-dist@^1.0.0: 13066 + package-json-from-dist@^1.0.0, package-json-from-dist@^1.0.1: 13021 13067 version "1.0.1" 13022 13068 resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" 13023 13069 integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== ··· 13141 13187 version "2.0.1" 13142 13188 resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.1.tgz#4b6572376cfd8b811fca9cd1f5c24b3cbac0fe10" 13143 13189 integrity sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA== 13190 + dependencies: 13191 + lru-cache "^11.0.0" 13192 + minipass "^7.1.2" 13193 + 13194 + path-scurry@^2.0.2: 13195 + version "2.0.2" 13196 + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-2.0.2.tgz#6be0d0ee02a10d9e0de7a98bae65e182c9061f85" 13197 + integrity sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg== 13144 13198 dependencies: 13145 13199 lru-cache "^11.0.0" 13146 13200 minipass "^7.1.2" ··· 14099 14153 integrity sha512-mLHJysehhSzYoM8BAD2DSjVZEcF69t16ZCJrCAos6sfVtbB3tL+kgGZFX+jNVz/f9BEhqnBFO0EA1tc/V6Hkgw== 14100 14154 dependencies: 14101 14155 react-native-is-edge-to-edge "^1.2.1" 14102 - 14103 - react-native-mathjax-html-to-svg@^1.1.0: 14104 - version "1.1.0" 14105 - resolved "https://registry.yarnpkg.com/react-native-mathjax-html-to-svg/-/react-native-mathjax-html-to-svg-1.1.0.tgz#0016881c8977e7c4032dc78c4f10a928affd525a" 14106 - integrity sha512-xqP/DS2Ya05yJUKw4w8liTgKl7R9j94aA/HonAZ4QMuFyj/aqrGgoSmYB1xnqtc1bw/YoqiZ+lz13hmRrjFoQg== 14107 - dependencies: 14108 - html-entities "^2.4.0" 14109 - mhchemparser "^4.2.1" 14110 14156 14111 14157 react-native-pager-view@6.8.0: 14112 14158 version "6.8.0" ··· 14678 14724 dependencies: 14679 14725 glob "^7.1.3" 14680 14726 14727 + rimraf@^6.0.1: 14728 + version "6.1.3" 14729 + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-6.1.3.tgz#afbee236b3bd2be331d4e7ce4493bac1718981af" 14730 + integrity sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA== 14731 + dependencies: 14732 + glob "^13.0.3" 14733 + package-json-from-dist "^1.0.1" 14734 + 14681 14735 rope-sequence@^1.3.0: 14682 14736 version "1.3.4" 14683 14737 resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.4.tgz#df85711aaecd32f1e756f76e43a415171235d425" ··· 15281 15335 http-deceiver "^1.2.7" 15282 15336 select-hose "^2.0.0" 15283 15337 spdy-transport "^3.0.0" 15338 + 15339 + speech-rule-engine@5.0.0-beta.6: 15340 + version "5.0.0-beta.6" 15341 + resolved "https://registry.yarnpkg.com/speech-rule-engine/-/speech-rule-engine-5.0.0-beta.6.tgz#4b82e5972aab382d8fd9b71f017420918fe4d47c" 15342 + integrity sha512-ohK2DizQ9s/JeiHhIraATNBwYpg2jSlSIF4Sq8pgHgSqMq2tkLRZLUq1BT2DjnmCWzkKeGSOaz6t/KzDGRGhPg== 15343 + dependencies: 15344 + "@xmldom/xmldom" "0.9.8" 15345 + commander "14.0.2" 15346 + wicked-good-xpath "1.3.0" 15284 15347 15285 15348 split-on-first@^1.0.0: 15286 15349 version "1.1.0" ··· 16722 16785 integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 16723 16786 dependencies: 16724 16787 isexe "^2.0.0" 16788 + 16789 + wicked-good-xpath@1.3.0: 16790 + version "1.3.0" 16791 + resolved "https://registry.yarnpkg.com/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz#81b0e95e8650e49c94b22298fff8686b5553cf6c" 16792 + integrity sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw== 16725 16793 16726 16794 wonka@^6.3.2: 16727 16795 version "6.3.4"