diff --git a/.gitignore b/.gitignore index 836122edbef..d5ccc97537f 100644 --- a/.gitignore +++ b/.gitignore @@ -79,6 +79,7 @@ npm-debug.log # Intermediate directories for webview assets /ios/webview # /android/app/build/... is already covered above +/staging # fastlane # See: https://docs.fastlane.tools/best-practices/source-control/ diff --git a/package.json b/package.json index c81020039f8..ca4c9d0e690 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "blueimp-md5": "^2.10.0", "color": "^3.0.0", "date-fns": "^1.29.0", + "katex": "^0.10.2", "lodash.escape": "^4.0.1", "lodash.isequal": "^4.4.0", "lodash.omit": "^4.5.0", diff --git a/src/webview/css/css.js b/src/webview/css/css.js index 2bed42de1f2..16d1bcc34d1 100644 --- a/src/webview/css/css.js +++ b/src/webview/css/css.js @@ -1,11 +1,76 @@ /* @flow strict-local */ +import { Platform } from 'react-native'; import type { ThemeName } from '../../types'; import cssPygments from './cssPygments'; import cssEmojis from './cssEmojis'; import cssNight from './cssNight'; +/** CSS fragment to support scrolling of KaTeX formulae. */ +/* + By default, KaTeX renders (non-inline) math into a div of fixed precomputed + width. This will be cut off by the edge of the screen when the formula is too + long -- and on a mobile device, that's very nearly always. + + The naïve solution of simply giving some part of the KaTeX fragment itself an + `overflow-x: auto` style breaks terribly: + * Margin collapsing no longer works, causing rendering artifacts. (This is + particularly visible on integral signs, which are truncated into near- + illegibility.) + * `overflow-y: hidden` isn't respected. If KaTeX has used negative-position + struts in its rendering (which it does frequently), there will always be + vertical scrollability. (This may be a Chrome bug.) + + Instead, we modify the provided DOM to wrap each `.katex-display` div with two + additional elements: the outer element is scrollable and `display: block`, + while the inner element is fixed and `display: inline-block`. This suffices to + insulate the KaTeX elements from the deleterious effects of scrollability. + + The inner of these elements also receives a border, to act as a UI hint + indicating that scrolling is necessary: the right border will be cut off when + the rendered element is too large. (The KaTeX itself will also be truncated, + of course, but this may not be apparent if the cutoff falls between two + symbols.) + + We also cut the KaTeX-provided margin somewhat. (Since the KaTeX fragment is + isolated in the new divs, margin-collapsing can no longer occur.) +*/ +const katexScrollStyle = ``; + +/** + * Fix KaTeX frac-line elements disappearing. + * + * This is a hack, but it's probably better than not having fraction lines on + * low-resolution phones. It's only known to be useful under Chrome and Android, + * so we only include it there. + * + * See, among others: + * https://github.com/KaTeX/KaTeX/issues/824 + * https://github.com/KaTeX/KaTeX/issues/916 + * https://github.com/KaTeX/KaTeX/pull/1249 + * https://github.com/KaTeX/KaTeX/issues/1775 + */ +const katexFraclineHackStyle = ``; + export default (theme: ThemeName) => ` + +${katexScrollStyle} +${Platform.OS === 'android' ? katexFraclineHackStyle : ''} `; diff --git a/src/webview/js/fixup-katex.js b/src/webview/js/fixup-katex.js new file mode 100644 index 00000000000..c40567918aa --- /dev/null +++ b/src/webview/js/fixup-katex.js @@ -0,0 +1,36 @@ +/* @flow strict */ + +// Auxiliary function, for brevity. +const makeDiv = (className: string): Element => { + const element = document.createElement('div'); + element.classList.add(className); + return element; +}; + +/** + * Adjust non-inline KaTeX equation element structure. + * + * This surrounds existing `.katex-display` elements (the KaTeX wrapper for + * non-inline equations) with shim `