katex 0.13.22 → 0.14.1

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.
Files changed (46) hide show
  1. package/README.md +5 -5
  2. package/cli.js +17 -46
  3. package/contrib/copy-tex/README.md +3 -3
  4. package/contrib/mathtex-script-type/README.md +5 -5
  5. package/contrib/mhchem/README.md +1 -1
  6. package/dist/README.md +5 -5
  7. package/dist/fonts/KaTeX_Main-Bold.ttf +0 -0
  8. package/dist/fonts/KaTeX_Main-Bold.woff +0 -0
  9. package/dist/fonts/KaTeX_Main-Bold.woff2 +0 -0
  10. package/dist/fonts/KaTeX_Main-Regular.ttf +0 -0
  11. package/dist/fonts/KaTeX_Main-Regular.woff +0 -0
  12. package/dist/fonts/KaTeX_Main-Regular.woff2 +0 -0
  13. package/dist/katex.css +1 -1
  14. package/dist/katex.js +1769 -1614
  15. package/dist/katex.min.css +1 -1
  16. package/dist/katex.min.js +1 -1
  17. package/dist/katex.mjs +2222 -2093
  18. package/katex.js +5 -1
  19. package/package.json +34 -1
  20. package/src/Settings.js +183 -32
  21. package/src/buildCommon.js +12 -12
  22. package/src/buildHTML.js +5 -4
  23. package/src/delimiter.js +11 -10
  24. package/src/domTree.js +2 -1
  25. package/src/environments/array.js +9 -9
  26. package/src/environments/cd.js +2 -1
  27. package/src/fontMetricsData.js +2 -1
  28. package/src/fonts/makeFF +2 -0
  29. package/src/functions/accent.js +4 -3
  30. package/src/functions/cr.js +3 -3
  31. package/src/functions/delimsizing.js +4 -2
  32. package/src/functions/enclose.js +7 -7
  33. package/src/functions/genfrac.js +2 -2
  34. package/src/functions/includegraphics.js +7 -9
  35. package/src/functions/lap.js +3 -2
  36. package/src/functions/op.js +2 -1
  37. package/src/functions/rule.js +10 -10
  38. package/src/functions/sizing.js +2 -1
  39. package/src/functions/sqrt.js +2 -1
  40. package/src/functions/supsub.js +3 -2
  41. package/src/functions/utils/assembleSupSub.js +6 -5
  42. package/src/macros.js +3 -2
  43. package/src/mathMLTree.js +3 -2
  44. package/src/metrics/extract_ttfs.py +3 -0
  45. package/src/stretchy.js +8 -7
  46. package/src/units.js +8 -0
@@ -4,7 +4,7 @@
4
4
  import defineFunction from "../defineFunction";
5
5
  import buildCommon from "../buildCommon";
6
6
  import mathMLTree from "../mathMLTree";
7
- import {calculateSize} from "../units";
7
+ import {calculateSize, makeEm} from "../units";
8
8
  import {assertNodeType} from "../parseNode";
9
9
 
10
10
  // \DeclareRobustCommand\\{...\@xnewline}
@@ -41,7 +41,7 @@ defineFunction({
41
41
  span.classes.push("newline");
42
42
  if (group.size) {
43
43
  span.style.marginTop =
44
- calculateSize(group.size, options) + "em";
44
+ makeEm(calculateSize(group.size, options));
45
45
  }
46
46
  }
47
47
  return span;
@@ -53,7 +53,7 @@ defineFunction({
53
53
  node.setAttribute("linebreak", "newline");
54
54
  if (group.size) {
55
55
  node.setAttribute("height",
56
- calculateSize(group.size, options) + "em");
56
+ makeEm(calculateSize(group.size, options)));
57
57
  }
58
58
  }
59
59
  return node;
@@ -6,6 +6,7 @@ import mathMLTree from "../mathMLTree";
6
6
  import ParseError from "../ParseError";
7
7
  import utils from "../utils";
8
8
  import {assertNodeType, checkSymbolNodeType} from "../parseNode";
9
+ import {makeEm} from "../units";
9
10
 
10
11
  import * as html from "../buildHTML";
11
12
  import * as mml from "../buildMathML";
@@ -126,8 +127,9 @@ defineFunction({
126
127
  }
127
128
 
128
129
  node.setAttribute("stretchy", "true");
129
- node.setAttribute("minsize", delimiter.sizeToMaxHeight[group.size] + "em");
130
- node.setAttribute("maxsize", delimiter.sizeToMaxHeight[group.size] + "em");
130
+ const size = makeEm(delimiter.sizeToMaxHeight[group.size]);
131
+ node.setAttribute("minsize", size);
132
+ node.setAttribute("maxsize", size);
131
133
 
132
134
  return node;
133
135
  },
@@ -6,7 +6,7 @@ import utils from "../utils";
6
6
  import stretchy from "../stretchy";
7
7
  import {phasePath} from "../svgGeometry";
8
8
  import {PathNode, SvgNode} from "../domTree";
9
- import {calculateSize} from "../units";
9
+ import {calculateSize, makeEm} from "../units";
10
10
  import {assertNodeType} from "../parseNode";
11
11
 
12
12
  import * as html from "../buildHTML";
@@ -48,20 +48,20 @@ const htmlBuilder = (group, options) => {
48
48
 
49
49
  const angleHeight = inner.height + inner.depth + lineWeight + clearance;
50
50
  // Reserve a left pad for the angle.
51
- inner.style.paddingLeft = (angleHeight / 2 + lineWeight) + "em";
51
+ inner.style.paddingLeft = makeEm(angleHeight / 2 + lineWeight);
52
52
 
53
53
  // Create an SVG
54
54
  const viewBoxHeight = Math.floor(1000 * angleHeight * scale);
55
55
  const path = phasePath(viewBoxHeight);
56
56
  const svgNode = new SvgNode([new PathNode("phase", path)], {
57
57
  "width": "400em",
58
- "height": `${viewBoxHeight / 1000}em`,
58
+ "height": makeEm(viewBoxHeight / 1000),
59
59
  "viewBox": `0 0 400000 ${viewBoxHeight}`,
60
60
  "preserveAspectRatio": "xMinYMin slice",
61
61
  });
62
62
  // Wrap it in a span with overflow: hidden.
63
63
  img = buildCommon.makeSvgSpan(["hide-tail"], [svgNode], options);
64
- img.style.height = angleHeight + "em";
64
+ img.style.height = makeEm(angleHeight);
65
65
  imgShift = inner.depth + lineWeight + clearance;
66
66
 
67
67
  } else {
@@ -104,10 +104,10 @@ const htmlBuilder = (group, options) => {
104
104
  img = stretchy.encloseSpan(inner, label, topPad, bottomPad, options);
105
105
  if (/fbox|boxed|fcolorbox/.test(label)) {
106
106
  img.style.borderStyle = "solid";
107
- img.style.borderWidth = `${ruleThickness}em`;
107
+ img.style.borderWidth = makeEm(ruleThickness);
108
108
  } else if (label === "angl" && ruleThickness !== 0.049) {
109
- img.style.borderTopWidth = `${ruleThickness}em`;
110
- img.style.borderRightWidth = `${ruleThickness}em`;
109
+ img.style.borderTopWidth = makeEm(ruleThickness);
110
+ img.style.borderRightWidth = makeEm(ruleThickness);
111
111
  }
112
112
  imgShift = inner.depth + bottomPad;
113
113
 
@@ -9,7 +9,7 @@ import {assert} from "../utils";
9
9
 
10
10
  import * as html from "../buildHTML";
11
11
  import * as mml from "../buildMathML";
12
- import {calculateSize} from "../units";
12
+ import {calculateSize, makeEm} from "../units";
13
13
 
14
14
  const adjustStyle = (size, originalStyle) => {
15
15
  // Figure out what style this fraction should be in based on the
@@ -196,7 +196,7 @@ const mathmlBuilder = (group, options) => {
196
196
  node.setAttribute("linethickness", "0px");
197
197
  } else if (group.barSize) {
198
198
  const ruleWidth = calculateSize(group.barSize, options);
199
- node.setAttribute("linethickness", ruleWidth + "em");
199
+ node.setAttribute("linethickness", makeEm(ruleWidth));
200
200
  }
201
201
 
202
202
  const style = adjustStyle(group.size, options.style);
@@ -1,7 +1,7 @@
1
1
  // @flow
2
2
  import defineFunction from "../defineFunction";
3
3
  import type {Measurement} from "../units";
4
- import {calculateSize, validUnit} from "../units";
4
+ import {calculateSize, validUnit, makeEm} from "../units";
5
5
  import ParseError from "../ParseError";
6
6
  import {Img} from "../domTree";
7
7
  import mathMLTree from "../mathMLTree";
@@ -108,7 +108,6 @@ defineFunction({
108
108
 
109
109
  if (group.totalheight.number > 0) {
110
110
  depth = calculateSize(group.totalheight, options) - height;
111
- depth = Number(depth.toFixed(2));
112
111
  }
113
112
 
114
113
  let width = 0;
@@ -116,12 +115,12 @@ defineFunction({
116
115
  width = calculateSize(group.width, options);
117
116
  }
118
117
 
119
- const style: CssStyle = {height: height + depth + "em"};
118
+ const style: CssStyle = {height: makeEm(height + depth)};
120
119
  if (width > 0) {
121
- style.width = width + "em";
120
+ style.width = makeEm(width);
122
121
  }
123
122
  if (depth > 0) {
124
- style.verticalAlign = -depth + "em";
123
+ style.verticalAlign = makeEm(-depth);
125
124
  }
126
125
 
127
126
  const node = new Img(group.src, group.alt, style);
@@ -138,14 +137,13 @@ defineFunction({
138
137
  let depth = 0;
139
138
  if (group.totalheight.number > 0) {
140
139
  depth = calculateSize(group.totalheight, options) - height;
141
- depth = depth.toFixed(2);
142
- node.setAttribute("valign", "-" + depth + "em");
140
+ node.setAttribute("valign", makeEm(-depth));
143
141
  }
144
- node.setAttribute("height", height + depth + "em");
142
+ node.setAttribute("height", makeEm(height + depth));
145
143
 
146
144
  if (group.width.number > 0) {
147
145
  const width = calculateSize(group.width, options);
148
- node.setAttribute("width", width + "em");
146
+ node.setAttribute("width", makeEm(width));
149
147
  }
150
148
  node.setAttribute("src", group.src);
151
149
  return node;
@@ -3,6 +3,7 @@
3
3
  import defineFunction from "../defineFunction";
4
4
  import buildCommon from "../buildCommon";
5
5
  import mathMLTree from "../mathMLTree";
6
+ import {makeEm} from "../units";
6
7
 
7
8
  import * as html from "../buildHTML";
8
9
  import * as mml from "../buildMathML";
@@ -46,9 +47,9 @@ defineFunction({
46
47
  // Otherwise, a tall argument may be misplaced.
47
48
  // This code resolved issue #1153
48
49
  const strut = buildCommon.makeSpan(["strut"]);
49
- strut.style.height = (node.height + node.depth) + "em";
50
+ strut.style.height = makeEm(node.height + node.depth);
50
51
  if (node.depth) {
51
- strut.style.verticalAlign = -node.depth + "em";
52
+ strut.style.verticalAlign = makeEm(-node.depth);
52
53
  }
53
54
  node.children.unshift(strut);
54
55
 
@@ -8,6 +8,7 @@ import utils from "../utils";
8
8
  import Style from "../Style";
9
9
  import {assembleSupSub} from "./utils/assembleSupSub";
10
10
  import {assertNodeType} from "../parseNode";
11
+ import {makeEm} from "../units";
11
12
 
12
13
  import * as html from "../buildHTML";
13
14
  import * as mml from "../buildMathML";
@@ -132,7 +133,7 @@ export const htmlBuilder: HtmlBuilderSupSub<"op"> = (grp, options) => {
132
133
  } else {
133
134
  if (baseShift) {
134
135
  base.style.position = "relative";
135
- base.style.top = baseShift + "em";
136
+ base.style.top = makeEm(baseShift);
136
137
  }
137
138
 
138
139
  return base;
@@ -3,7 +3,7 @@ import buildCommon from "../buildCommon";
3
3
  import defineFunction from "../defineFunction";
4
4
  import mathMLTree from "../mathMLTree";
5
5
  import {assertNodeType} from "../parseNode";
6
- import {calculateSize} from "../units";
6
+ import {calculateSize, makeEm} from "../units";
7
7
 
8
8
  defineFunction({
9
9
  type: "rule",
@@ -35,9 +35,9 @@ defineFunction({
35
35
  const shift = (group.shift) ? calculateSize(group.shift, options) : 0;
36
36
 
37
37
  // Style the rule to the right size
38
- rule.style.borderRightWidth = width + "em";
39
- rule.style.borderTopWidth = height + "em";
40
- rule.style.bottom = shift + "em";
38
+ rule.style.borderRightWidth = makeEm(width);
39
+ rule.style.borderTopWidth = makeEm(height);
40
+ rule.style.bottom = makeEm(shift);
41
41
 
42
42
  // Record the height and width
43
43
  rule.width = width;
@@ -58,17 +58,17 @@ defineFunction({
58
58
 
59
59
  const rule = new mathMLTree.MathNode("mspace");
60
60
  rule.setAttribute("mathbackground", color);
61
- rule.setAttribute("width", width + "em");
62
- rule.setAttribute("height", height + "em");
61
+ rule.setAttribute("width", makeEm(width));
62
+ rule.setAttribute("height", makeEm(height));
63
63
 
64
64
  const wrapper = new mathMLTree.MathNode("mpadded", [rule]);
65
65
  if (shift >= 0) {
66
- wrapper.setAttribute("height", "+" + shift + "em");
66
+ wrapper.setAttribute("height", makeEm(shift));
67
67
  } else {
68
- wrapper.setAttribute("height", shift + "em");
69
- wrapper.setAttribute("depth", "+" + (-shift) + "em");
68
+ wrapper.setAttribute("height", makeEm(shift));
69
+ wrapper.setAttribute("depth", makeEm(-shift));
70
70
  }
71
- wrapper.setAttribute("voffset", shift + "em");
71
+ wrapper.setAttribute("voffset", makeEm(shift));
72
72
 
73
73
  return wrapper;
74
74
  },
@@ -2,6 +2,7 @@
2
2
  import buildCommon from "../buildCommon";
3
3
  import defineFunction from "../defineFunction";
4
4
  import mathMLTree from "../mathMLTree";
5
+ import {makeEm} from "../units";
5
6
 
6
7
  import * as html from "../buildHTML";
7
8
  import * as mml from "../buildMathML";
@@ -83,7 +84,7 @@ defineFunction({
83
84
  // in, so we can't reset the size to normal before changing it. Now
84
85
  // that we're passing an options parameter we should be able to fix
85
86
  // this.
86
- node.setAttribute("mathsize", newOptions.sizeMultiplier + "em");
87
+ node.setAttribute("mathsize", makeEm(newOptions.sizeMultiplier));
87
88
 
88
89
  return node;
89
90
  },
@@ -4,6 +4,7 @@ import buildCommon from "../buildCommon";
4
4
  import mathMLTree from "../mathMLTree";
5
5
  import delimiter from "../delimiter";
6
6
  import Style from "../Style";
7
+ import {makeEm} from "../units";
7
8
 
8
9
  import * as html from "../buildHTML";
9
10
  import * as mml from "../buildMathML";
@@ -70,7 +71,7 @@ defineFunction({
70
71
  // Shift the sqrt image
71
72
  const imgShift = img.height - inner.height - lineClearance - ruleWidth;
72
73
 
73
- inner.style.paddingLeft = advanceWidth + "em";
74
+ inner.style.paddingLeft = makeEm(advanceWidth);
74
75
 
75
76
  // Overlay the image and the argument.
76
77
  const body = buildCommon.makeVList({
@@ -4,6 +4,7 @@ import buildCommon from "../buildCommon";
4
4
  import {SymbolNode} from "../domTree";
5
5
  import mathMLTree from "../mathMLTree";
6
6
  import utils from "../utils";
7
+ import {makeEm} from "../units";
7
8
  import Style from "../Style";
8
9
 
9
10
  import * as html from "../buildHTML";
@@ -111,7 +112,7 @@ defineFunctionBuilders({
111
112
  // scriptspace is a font-size-independent size, so scale it
112
113
  // appropriately for use as the marginRight.
113
114
  const multiplier = options.sizeMultiplier;
114
- const marginRight = (0.5 / metrics.ptPerEm) / multiplier + "em";
115
+ const marginRight = makeEm((0.5 / metrics.ptPerEm) / multiplier);
115
116
 
116
117
  let marginLeft = null;
117
118
  if (subm) {
@@ -123,7 +124,7 @@ defineFunctionBuilders({
123
124
  (group.base.name === "\\oiint" || group.base.name === "\\oiiint");
124
125
  if (base instanceof SymbolNode || isOiint) {
125
126
  // $FlowFixMe
126
- marginLeft = -base.italic + "em";
127
+ marginLeft = makeEm(-base.italic);
127
128
  }
128
129
  }
129
130
 
@@ -6,6 +6,7 @@ import type {StyleInterface} from "../../Style";
6
6
  import type Options from "../../Options";
7
7
  import type {DomSpan, SymbolNode} from "../../domTree";
8
8
  import type {AnyParseNode} from "../../parseNode";
9
+ import {makeEm} from "../../units";
9
10
 
10
11
  // For an operator with limits, assemble the base, sup, and sub into a span.
11
12
 
@@ -62,11 +63,11 @@ export const assembleSupSub = (
62
63
  positionData: bottom,
63
64
  children: [
64
65
  {type: "kern", size: options.fontMetrics().bigOpSpacing5},
65
- {type: "elem", elem: sub.elem, marginLeft: -slant + "em"},
66
+ {type: "elem", elem: sub.elem, marginLeft: makeEm(-slant)},
66
67
  {type: "kern", size: sub.kern},
67
68
  {type: "elem", elem: base},
68
69
  {type: "kern", size: sup.kern},
69
- {type: "elem", elem: sup.elem, marginLeft: slant + "em"},
70
+ {type: "elem", elem: sup.elem, marginLeft: makeEm(slant)},
70
71
  {type: "kern", size: options.fontMetrics().bigOpSpacing5},
71
72
  ],
72
73
  }, options);
@@ -82,7 +83,7 @@ export const assembleSupSub = (
82
83
  positionData: top,
83
84
  children: [
84
85
  {type: "kern", size: options.fontMetrics().bigOpSpacing5},
85
- {type: "elem", elem: sub.elem, marginLeft: -slant + "em"},
86
+ {type: "elem", elem: sub.elem, marginLeft: makeEm(-slant)},
86
87
  {type: "kern", size: sub.kern},
87
88
  {type: "elem", elem: base},
88
89
  ],
@@ -96,7 +97,7 @@ export const assembleSupSub = (
96
97
  children: [
97
98
  {type: "elem", elem: base},
98
99
  {type: "kern", size: sup.kern},
99
- {type: "elem", elem: sup.elem, marginLeft: slant + "em"},
100
+ {type: "elem", elem: sup.elem, marginLeft: makeEm(slant)},
100
101
  {type: "kern", size: options.fontMetrics().bigOpSpacing5},
101
102
  ],
102
103
  }, options);
@@ -112,7 +113,7 @@ export const assembleSupSub = (
112
113
  // A negative margin-left was applied to the lower limit.
113
114
  // Avoid an overlap by placing a spacer on the left on the group.
114
115
  const spacer = buildCommon.makeSpan(["mspace"], [], options);
115
- spacer.style.marginRight = `${slant}em`;
116
+ spacer.style.marginRight = makeEm(slant);
116
117
  parts.unshift(spacer);
117
118
  }
118
119
  return buildCommon.makeSpan(["mop", "op-limits"], parts, options);
package/src/macros.js CHANGED
@@ -13,6 +13,7 @@ import fontMetricsData from "./fontMetricsData";
13
13
  import functions from "./functions";
14
14
  import symbols from "./symbols";
15
15
  import utils from "./utils";
16
+ import {makeEm} from "./units";
16
17
  import ParseError from "./ParseError";
17
18
 
18
19
 
@@ -634,8 +635,8 @@ defineMacro("\\TeX", "\\textrm{\\html@mathml{" +
634
635
  // boxes, though visually the A appears to extend above slightly).
635
636
  // We compute the corresponding \raisebox when A is rendered in \normalsize
636
637
  // \scriptstyle, which has a scale factor of 0.7 (see Options.js).
637
- const latexRaiseA = fontMetricsData['Main-Regular']["T".charCodeAt(0)][1] -
638
- 0.7 * fontMetricsData['Main-Regular']["A".charCodeAt(0)][1] + "em";
638
+ const latexRaiseA = makeEm(fontMetricsData['Main-Regular']["T".charCodeAt(0)][1] -
639
+ 0.7 * fontMetricsData['Main-Regular']["A".charCodeAt(0)][1]);
639
640
  defineMacro("\\LaTeX", "\\textrm{\\html@mathml{" +
640
641
  `L\\kern-.36em\\raisebox{${latexRaiseA}}{\\scriptstyle A}` +
641
642
  "\\kern-.15em\\TeX}{LaTeX}}");
package/src/mathMLTree.js CHANGED
@@ -12,6 +12,7 @@
12
12
  import utils from "./utils";
13
13
  import {DocumentFragment} from "./tree";
14
14
  import {createClass} from "./domTree";
15
+ import {makeEm} from "./units";
15
16
 
16
17
  import type {VirtualNode} from "./tree";
17
18
 
@@ -219,7 +220,7 @@ class SpaceNode implements MathDomNode {
219
220
  } else {
220
221
  const node = document.createElementNS(
221
222
  "http://www.w3.org/1998/Math/MathML", "mspace");
222
- node.setAttribute("width", this.width + "em");
223
+ node.setAttribute("width", makeEm(this.width));
223
224
  return node;
224
225
  }
225
226
  }
@@ -231,7 +232,7 @@ class SpaceNode implements MathDomNode {
231
232
  if (this.character) {
232
233
  return `<mtext>${this.character}</mtext>`;
233
234
  } else {
234
- return `<mspace width="${this.width}em"/>`;
235
+ return `<mspace width="${makeEm(this.width)}"/>`;
235
236
  }
236
237
  }
237
238
 
@@ -44,6 +44,9 @@ metrics_to_extract = {
44
44
  u"\u21aa": None, # \hookrightarrow
45
45
  u"\u21cc": None, # \rightleftharpoons
46
46
  },
47
+ "Main-Bold": {
48
+ u"\u2245": None, # \cong
49
+ },
47
50
  "Size1-Regular": {
48
51
  u"\u222c": u"\u222b", # \iint, based on \int
49
52
  u"\u222d": u"\u222b", # \iiint, based on \int
package/src/stretchy.js CHANGED
@@ -9,6 +9,7 @@ import {LineNode, PathNode, SvgNode} from "./domTree";
9
9
  import buildCommon from "./buildCommon";
10
10
  import mathMLTree from "./mathMLTree";
11
11
  import utils from "./utils";
12
+ import {makeEm} from "./units";
12
13
 
13
14
  import type Options from "./Options";
14
15
  import type {ParseNode, AnyParseNode} from "./parseNode";
@@ -233,7 +234,7 @@ const svgSpan = function(
233
234
  const path = new PathNode(pathName);
234
235
  const svgNode = new SvgNode([path], {
235
236
  "width": "100%",
236
- "height": height + "em",
237
+ "height": makeEm(height),
237
238
  "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
238
239
  "preserveAspectRatio": "none",
239
240
  });
@@ -274,7 +275,7 @@ const svgSpan = function(
274
275
 
275
276
  const svgNode = new SvgNode([path], {
276
277
  "width": "400em",
277
- "height": height + "em",
278
+ "height": makeEm(height),
278
279
  "viewBox": `0 0 ${viewBoxWidth} ${viewBoxHeight}`,
279
280
  "preserveAspectRatio": aligns[i] + " slice",
280
281
  });
@@ -284,7 +285,7 @@ const svgSpan = function(
284
285
  if (numSvgChildren === 1) {
285
286
  return {span, minWidth, height};
286
287
  } else {
287
- span.style.height = height + "em";
288
+ span.style.height = makeEm(height);
288
289
  spans.push(span);
289
290
  }
290
291
  }
@@ -301,9 +302,9 @@ const svgSpan = function(
301
302
  // Note that we are returning span.depth = 0.
302
303
  // Any adjustments relative to the baseline must be done in buildHTML.
303
304
  span.height = height;
304
- span.style.height = height + "em";
305
+ span.style.height = makeEm(height);
305
306
  if (minWidth > 0) {
306
- span.style.minWidth = minWidth + "em";
307
+ span.style.minWidth = makeEm(minWidth);
307
308
  }
308
309
 
309
310
  return span;
@@ -358,14 +359,14 @@ const encloseSpan = function(
358
359
 
359
360
  const svgNode = new SvgNode(lines, {
360
361
  "width": "100%",
361
- "height": totalHeight + "em",
362
+ "height": makeEm(totalHeight),
362
363
  });
363
364
 
364
365
  img = buildCommon.makeSvgSpan([], [svgNode], options);
365
366
  }
366
367
 
367
368
  img.height = totalHeight;
368
- img.style.height = totalHeight + "em";
369
+ img.style.height = makeEm(totalHeight);
369
370
 
370
371
  return img;
371
372
  };
package/src/units.js CHANGED
@@ -96,3 +96,11 @@ export const calculateSize = function(
96
96
  }
97
97
  return Math.min(sizeValue.number * scale, options.maxSize);
98
98
  };
99
+
100
+ /**
101
+ * Round `n` to 4 decimal places, or to the nearest 1/10,000th em. See
102
+ * https://github.com/KaTeX/KaTeX/pull/2460.
103
+ */
104
+ export const makeEm = function(n: number): string {
105
+ return +n.toFixed(4) + "em";
106
+ };