Treat svg-wrapping spans differently from DOM-wrapping spans. (#1239)

* Treat svg-wrapping spans differently from DOM-wrapping spans.

In preparation for the conversion of buildHTML to @flow, separate the two
different uses of domTree.span -- one to wrap a single SVG and one to wrap
arbitrary DOM nodes. This separation is to help avoid type issues that pop up
due to buildHTML methods accessing the .children field of spans as if they are
DOM elements and not SVG ones.

* Simplify the domTree DOM definitions based on separation of two span types.
This commit is contained in:
Ashish Myles
2018-03-27 22:47:15 -04:00
committed by GitHub
parent e31cceed58
commit 850a0713cb
6 changed files with 90 additions and 76 deletions

View File

@@ -16,7 +16,7 @@ import type Options from "./Options";
import type ParseNode from "./ParseNode"; import type ParseNode from "./ParseNode";
import type {CharacterMetrics} from "./fontMetrics"; import type {CharacterMetrics} from "./fontMetrics";
import type {Mode} from "./types"; import type {Mode} from "./types";
import type {DomChildNode, CombinableDomNode, CssStyle} from "./domTree"; import type {HtmlDomNode, DomSpan, SvgSpan, CssStyle} from "./domTree";
import type {Measurement} from "./units"; import type {Measurement} from "./units";
// The following have to be loaded from Main-Italic font, using class mainit // The following have to be loaded from Main-Italic font, using class mainit
@@ -269,9 +269,7 @@ const makeOrd = function(
* Combine as many characters as possible in the given array of characters * Combine as many characters as possible in the given array of characters
* via their tryCombine method. * via their tryCombine method.
*/ */
const tryCombineChars = function( const tryCombineChars = function(chars: HtmlDomNode[]): HtmlDomNode[] {
chars: CombinableDomNode[],
): CombinableDomNode[] {
for (let i = 0; i < chars.length - 1; i++) { for (let i = 0; i < chars.length - 1; i++) {
if (chars[i].tryCombine(chars[i + 1])) { if (chars[i].tryCombine(chars[i + 1])) {
chars.splice(i + 1, 1); chars.splice(i + 1, 1);
@@ -286,7 +284,7 @@ const tryCombineChars = function(
* children. * children.
*/ */
const sizeElementFromChildren = function( const sizeElementFromChildren = function(
elem: domTree.span | domTree.anchor | domTree.documentFragment, elem: DomSpan | domTree.anchor | domTree.documentFragment,
) { ) {
let height = 0; let height = 0;
let depth = 0; let depth = 0;
@@ -319,10 +317,10 @@ const sizeElementFromChildren = function(
*/ */
const makeSpan = function( const makeSpan = function(
classes?: string[], classes?: string[],
children?: DomChildNode[], children?: HtmlDomNode[],
options?: Options, options?: Options,
style?: CssStyle, style?: CssStyle,
): domTree.span { ): DomSpan {
const span = new domTree.span(classes, children, options, style); const span = new domTree.span(classes, children, options, style);
sizeElementFromChildren(span); sizeElementFromChildren(span);
@@ -330,6 +328,15 @@ const makeSpan = function(
return span; return span;
}; };
// SVG one is simpler -- doesn't require height, depth, max-font setting.
// This is also a separate method for typesafety.
const makeSvgSpan = (
classes?: string[],
children?: domTree.svgNode[],
options?: Options,
style?: CssStyle,
): SvgSpan => new domTree.span(classes, children, options, style);
const makeLineSpan = function( const makeLineSpan = function(
className: string, className: string,
options: Options, options: Options,
@@ -352,7 +359,7 @@ const makeLineSpan = function(
const makeAnchor = function( const makeAnchor = function(
href: string, href: string,
classes: string[], classes: string[],
children: DomChildNode[], children: HtmlDomNode[],
options: Options, options: Options,
) { ) {
const anchor = new domTree.anchor(href, classes, children, options); const anchor = new domTree.anchor(href, classes, children, options);
@@ -366,7 +373,7 @@ const makeAnchor = function(
* Makes a document fragment with the given list of children. * Makes a document fragment with the given list of children.
*/ */
const makeFragment = function( const makeFragment = function(
children: DomChildNode[], children: HtmlDomNode[],
): domTree.documentFragment { ): domTree.documentFragment {
const fragment = new domTree.documentFragment(children); const fragment = new domTree.documentFragment(children);
@@ -379,7 +386,7 @@ const makeFragment = function(
// These are exact object types to catch typos in the names of the optional fields. // These are exact object types to catch typos in the names of the optional fields.
export type VListElem = {| export type VListElem = {|
type: "elem", type: "elem",
elem: DomChildNode, elem: HtmlDomNode,
marginLeft?: string, marginLeft?: string,
marginRight?: string, marginRight?: string,
wrapperClasses?: string[], wrapperClasses?: string[],
@@ -387,7 +394,7 @@ export type VListElem = {|
|}; |};
type VListElemAndShift = {| type VListElemAndShift = {|
type: "elem", type: "elem",
elem: DomChildNode, elem: HtmlDomNode,
shift: number, shift: number,
marginLeft?: string, marginLeft?: string,
marginRight?: string, marginRight?: string,
@@ -491,7 +498,7 @@ const getVListChildrenAndDepth = function(params: VListParam): {
* *
* See VListParam documentation above. * See VListParam documentation above.
*/ */
const makeVList = function(params: VListParam, options: Options): domTree.span { const makeVList = function(params: VListParam, options: Options): DomSpan {
const {children, depth} = getVListChildrenAndDepth(params); const {children, depth} = getVListChildrenAndDepth(params);
// Create a strut that is taller than any list item. The strut is added to // Create a strut that is taller than any list item. The strut is added to
@@ -595,7 +602,7 @@ const makeVerb = function(group: ParseNode, options: Options): string {
// Glue is a concept from TeX which is a flexible space between elements in // Glue is a concept from TeX which is a flexible space between elements in
// either a vertical or horizontal list. In KaTeX, at least for now, it's // either a vertical or horizontal list. In KaTeX, at least for now, it's
// static space between elements in a horizontal layout. // static space between elements in a horizontal layout.
const makeGlue = (measurement: Measurement, options: Options): domTree.span => { const makeGlue = (measurement: Measurement, options: Options): DomSpan => {
// Make an empty span for the rule // Make an empty span for the rule
const rule = makeSpan(["mord", "rule"], [], options); const rule = makeSpan(["mord", "rule"], [], options);
const size = calculateSize(measurement, options); const size = calculateSize(measurement, options);
@@ -752,7 +759,7 @@ const svgData: {
vec: ["vec", 0.471, 0.714], // values from the font glyph vec: ["vec", 0.471, 0.714], // values from the font glyph
}; };
const staticSvg = function(value: string, options: Options): domTree.span { const staticSvg = function(value: string, options: Options): SvgSpan {
// Create a span with inline SVG for the element. // Create a span with inline SVG for the element.
const [pathName, width, height] = svgData[value]; const [pathName, width, height] = svgData[value];
const path = new domTree.pathNode(pathName); const path = new domTree.pathNode(pathName);
@@ -764,7 +771,7 @@ const staticSvg = function(value: string, options: Options): domTree.span {
"viewBox": "0 0 " + 1000 * width + " " + 1000 * height, "viewBox": "0 0 " + 1000 * width + " " + 1000 * height,
"preserveAspectRatio": "xMinYMin", "preserveAspectRatio": "xMinYMin",
}); });
const span = makeSpan(["overlay"], [svgNode], options); const span = makeSvgSpan(["overlay"], [svgNode], options);
span.height = height; span.height = height;
span.style.height = height + "em"; span.style.height = height + "em";
span.style.width = width + "em"; span.style.width = width + "em";
@@ -776,6 +783,7 @@ export default {
makeSymbol, makeSymbol,
mathsym, mathsym,
makeSpan, makeSpan,
makeSvgSpan,
makeLineSpan, makeLineSpan,
makeAnchor, makeAnchor,
makeFragment, makeFragment,

View File

@@ -7,7 +7,7 @@ import Settings from "./Settings";
import Style from "./Style"; import Style from "./Style";
import type ParseNode from "./ParseNode"; import type ParseNode from "./ParseNode";
import type domTree from "./domTree"; import type {DomSpan} from "./domTree";
const optionsFromSettings = function(settings: Settings) { const optionsFromSettings = function(settings: Settings) {
return new Options({ return new Options({
@@ -20,7 +20,7 @@ export const buildTree = function(
tree: ParseNode[], tree: ParseNode[],
expression: string, expression: string,
settings: Settings, settings: Settings,
): domTree.span { ): DomSpan {
const options = optionsFromSettings(settings); const options = optionsFromSettings(settings);
// `buildHTML` sometimes messes with the parse tree (like turning bins -> // `buildHTML` sometimes messes with the parse tree (like turning bins ->
// ords), so we build the MathML version first. // ords), so we build the MathML version first.
@@ -42,7 +42,7 @@ export const buildHTMLTree = function(
tree: ParseNode[], tree: ParseNode[],
expression: string, expression: string,
settings: Settings, settings: Settings,
): domTree.span { ): DomSpan {
const options = optionsFromSettings(settings); const options = optionsFromSettings(settings);
const htmlNode = buildHTML(tree, options); const htmlNode = buildHTML(tree, options);
const katexNode = buildCommon.makeSpan(["katex"], [htmlNode]); const katexNode = buildCommon.makeSpan(["katex"], [htmlNode]);

View File

@@ -32,7 +32,7 @@ import utils from "./utils";
import type Options from "./Options"; import type Options from "./Options";
import type {CharacterMetrics} from "./fontMetrics"; import type {CharacterMetrics} from "./fontMetrics";
import type {DomChildNode} from "./domTree"; import type {HtmlDomNode, DomSpan, SvgSpan} from "./domTree";
import type {Mode} from "./types"; import type {Mode} from "./types";
import type {StyleInterface} from "./Style"; import type {StyleInterface} from "./Style";
import type {VListElem} from "./buildCommon"; import type {VListElem} from "./buildCommon";
@@ -60,11 +60,11 @@ const getMetrics = function(
* and maxFontSizes. * and maxFontSizes.
*/ */
const styleWrap = function( const styleWrap = function(
delim: DomChildNode, delim: HtmlDomNode,
toStyle: StyleInterface, toStyle: StyleInterface,
options: Options, options: Options,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
const newOptions = options.havingBaseStyle(toStyle); const newOptions = options.havingBaseStyle(toStyle);
const span = buildCommon.makeSpan( const span = buildCommon.makeSpan(
@@ -81,7 +81,7 @@ const styleWrap = function(
}; };
const centerSpan = function( const centerSpan = function(
span: domTree.span, span: DomSpan,
options: Options, options: Options,
style: StyleInterface, style: StyleInterface,
) { ) {
@@ -108,7 +108,7 @@ const makeSmallDelim = function(
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options); const text = buildCommon.makeSymbol(delim, "Main-Regular", mode, options);
const span = styleWrap(text, style, options, classes); const span = styleWrap(text, style, options, classes);
if (center) { if (center) {
@@ -140,7 +140,7 @@ const makeLargeDelim = function(delim,
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
const inner = mathrmSize(delim, size, mode, options); const inner = mathrmSize(delim, size, mode, options);
const span = styleWrap( const span = styleWrap(
buildCommon.makeSpan(["delimsizing", "size" + size], [inner], options), buildCommon.makeSpan(["delimsizing", "size" + size], [inner], options),
@@ -188,7 +188,7 @@ const makeStackedDelim = function(
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
// There are four parts, the top, an optional middle, a repeated part, and a // There are four parts, the top, an optional middle, a repeated part, and a
// bottom. // bottom.
let top; let top;
@@ -378,7 +378,7 @@ const sqrtSvg = function(
height: number, height: number,
viewBoxHeight: number, viewBoxHeight: number,
options: Options, options: Options,
): domTree.span { ): SvgSpan {
let alternate; let alternate;
if (sqrtName === "sqrtTall") { if (sqrtName === "sqrtTall") {
// sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular // sqrtTall is from glyph U23B7 in the font KaTeX_Size4-Regular
@@ -401,7 +401,7 @@ const sqrtSvg = function(
"preserveAspectRatio": "xMinYMin slice", "preserveAspectRatio": "xMinYMin slice",
}); });
return buildCommon.makeSpan(["hide-tail"], [svg], options); return buildCommon.makeSvgSpan(["hide-tail"], [svg], options);
}; };
/** /**
@@ -411,7 +411,7 @@ const makeSqrtImage = function(
height: number, height: number,
options: Options, options: Options,
): { ): {
span: domTree.span, span: SvgSpan,
ruleWidth: number, ruleWidth: number,
advanceWidth: number, advanceWidth: number,
} { } {
@@ -516,7 +516,7 @@ const makeSizedDelim = function(
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
// < and > turn into \langle and \rangle in delimiters // < and > turn into \langle and \rangle in delimiters
if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { if (delim === "<" || delim === "\\lt" || delim === "\u27e8") {
delim = "\\langle"; delim = "\\langle";
@@ -654,7 +654,7 @@ const makeCustomSizedDelim = function(
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
if (delim === "<" || delim === "\\lt" || delim === "\u27e8") { if (delim === "<" || delim === "\\lt" || delim === "\u27e8") {
delim = "\\langle"; delim = "\\langle";
} else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") { } else if (delim === ">" || delim === "\\gt" || delim === "\u27e9") {
@@ -700,7 +700,7 @@ const makeLeftRightDelim = function(
options: Options, options: Options,
mode: Mode, mode: Mode,
classes: string[], classes: string[],
): domTree.span { ): DomSpan {
// We always center \left/\right delimiters, so the axis is always shifted // We always center \left/\right delimiters, so the axis is always shifted
const axisHeight = const axisHeight =
options.fontMetrics().axisHeight * options.sizeMultiplier; options.fontMetrics().axisHeight * options.sizeMultiplier;

View File

@@ -29,23 +29,31 @@ const createClass = function(classes: string[]): string {
}; };
// To ensure that all nodes have compatible signatures for these methods. // To ensure that all nodes have compatible signatures for these methods.
interface VirtualDomNode { interface VirtualNodeInterface {
toNode(): Node; toNode(): Node;
toMarkup(): string; toMarkup(): string;
} }
export interface CombinableDomNode extends VirtualDomNode { interface HtmlDomInterface extends VirtualNodeInterface {
tryCombine(sibling: CombinableDomNode): boolean; classes: string[];
height: number;
depth: number;
maxFontSize: number;
tryCombine(sibling: HtmlDomNode): boolean;
} }
/** /**
* All `DomChildNode`s MUST have `height`, `depth`, and `maxFontSize` numeric * All `HtmlDomNode`s must implement HtmlDomInterface.
* fields.
* *
* `DomChildNode` is not defined as an interface since `documentFragment` also * `HtmlDomNode` is not defined as an interface since `documentFragment` also
* has these fields but should not be considered a `DomChildNode`. * has these fields but should not be considered a `HtmlDomNode`.
*/ */
export type DomChildNode = span | anchor | svgNode | symbolNode; export type HtmlDomNode = DomSpan | SvgSpan | anchor | symbolNode;
// Span wrapping other DOM nodes.
export type DomSpan = span<HtmlDomNode>;
// Span wrapping an SVG node.
export type SvgSpan = span<svgNode>;
export type SvgChildNode = pathNode | lineNode; export type SvgChildNode = pathNode | lineNode;
@@ -55,10 +63,14 @@ export type CssStyle = {[name: string]: string};
* This node represents a span node, with a className, a list of children, and * This node represents a span node, with a className, a list of children, and
* an inline style. It also contains information about its height, depth, and * an inline style. It also contains information about its height, depth, and
* maxFontSize. * maxFontSize.
*
* Represents two types with different uses: SvgSpan to wrap an SVG and DomSpan
* otherwise. This typesafety is important when HTML builders access a span's
* children.
*/ */
class span implements CombinableDomNode { class span<ChildType: VirtualNodeInterface> implements HtmlDomInterface {
classes: string[]; classes: string[];
children: DomChildNode[]; children: ChildType[];
height: number; height: number;
depth: number; depth: number;
width: ?number; width: ?number;
@@ -68,7 +80,7 @@ class span implements CombinableDomNode {
constructor( constructor(
classes?: string[], classes?: string[],
children?: DomChildNode[], children?: ChildType[],
options?: Options, options?: Options,
style?: CssStyle, style?: CssStyle,
) { ) {
@@ -99,7 +111,7 @@ class span implements CombinableDomNode {
this.attributes[attribute] = value; this.attributes[attribute] = value;
} }
tryCombine(sibling: CombinableDomNode): boolean { tryCombine(sibling: HtmlDomNode): boolean {
return false; return false;
} }
@@ -188,10 +200,10 @@ class span implements CombinableDomNode {
* a list of children, and an inline style. It also contains information about its * a list of children, and an inline style. It also contains information about its
* height, depth, and maxFontSize. * height, depth, and maxFontSize.
*/ */
class anchor implements CombinableDomNode { class anchor implements HtmlDomInterface {
href: string; href: string;
classes: string[]; classes: string[];
children: DomChildNode[]; children: HtmlDomNode[];
height: number; height: number;
depth: number; depth: number;
maxFontSize: number; maxFontSize: number;
@@ -201,7 +213,7 @@ class anchor implements CombinableDomNode {
constructor( constructor(
href: string, href: string,
classes: string[], classes: string[],
children: DomChildNode[], children: HtmlDomNode[],
options: Options, options: Options,
) { ) {
this.href = href; this.href = href;
@@ -230,7 +242,7 @@ class anchor implements CombinableDomNode {
this.attributes[attribute] = value; this.attributes[attribute] = value;
} }
tryCombine(sibling: CombinableDomNode): boolean { tryCombine(sibling: HtmlDomNode): boolean {
return false; return false;
} }
@@ -324,13 +336,13 @@ class anchor implements CombinableDomNode {
* contains children and doesn't have any HTML properties. It also keeps track * contains children and doesn't have any HTML properties. It also keeps track
* of a height, depth, and maxFontSize. * of a height, depth, and maxFontSize.
*/ */
class documentFragment implements VirtualDomNode { class documentFragment implements VirtualNodeInterface {
children: DomChildNode[]; children: HtmlDomNode[];
height: number; height: number;
depth: number; depth: number;
maxFontSize: number; maxFontSize: number;
constructor(children?: DomChildNode[]) { constructor(children?: HtmlDomNode[]) {
this.children = children || []; this.children = children || [];
this.height = 0; this.height = 0;
this.depth = 0; this.depth = 0;
@@ -380,7 +392,7 @@ const iCombinations = {
* to a single text node, or a span with a single text node in it, depending on * to a single text node, or a span with a single text node in it, depending on
* whether it has CSS classes, styles, or needs italic correction. * whether it has CSS classes, styles, or needs italic correction.
*/ */
class symbolNode implements CombinableDomNode { class symbolNode implements HtmlDomInterface {
value: string; value: string;
height: number; height: number;
depth: number; depth: number;
@@ -428,7 +440,7 @@ class symbolNode implements CombinableDomNode {
} }
} }
tryCombine(sibling: CombinableDomNode): boolean { tryCombine(sibling: HtmlDomNode): boolean {
if (!sibling if (!sibling
|| !(sibling instanceof symbolNode) || !(sibling instanceof symbolNode)
|| this.italic > 0 || this.italic > 0
@@ -538,20 +550,13 @@ class symbolNode implements CombinableDomNode {
/** /**
* SVG nodes are used to render stretchy wide elements. * SVG nodes are used to render stretchy wide elements.
*/ */
class svgNode implements VirtualDomNode { class svgNode implements VirtualNodeInterface {
children: SvgChildNode[]; children: SvgChildNode[];
attributes: {[string]: string}; attributes: {[string]: string};
// Required for all `DomChildNode`s. Are always 0 for svgNode.
height: number;
depth: number;
maxFontSize: number;
constructor(children?: SvgChildNode[], attributes?: {[string]: string}) { constructor(children?: SvgChildNode[], attributes?: {[string]: string}) {
this.children = children || []; this.children = children || [];
this.attributes = attributes || {}; this.attributes = attributes || {};
this.height = 0;
this.depth = 0;
this.maxFontSize = 0;
} }
toNode(): Node { toNode(): Node {
@@ -594,7 +599,7 @@ class svgNode implements VirtualDomNode {
} }
} }
class pathNode implements VirtualDomNode { class pathNode implements VirtualNodeInterface {
pathName: string; pathName: string;
alternate: ?string; alternate: ?string;
@@ -625,7 +630,7 @@ class pathNode implements VirtualDomNode {
} }
} }
class lineNode implements VirtualDomNode { class lineNode implements VirtualNodeInterface {
attributes: {[string]: string}; attributes: {[string]: string};
constructor(attributes?: {[string]: string}) { constructor(attributes?: {[string]: string}) {

View File

@@ -41,9 +41,6 @@ defineFunction({
buildCommon.tryCombineChars(body); buildCommon.tryCombineChars(body);
return buildCommon.makeSpan( return buildCommon.makeSpan(
["mord", "text"].concat(newOptions.sizingClasses(options)), ["mord", "text"].concat(newOptions.sizingClasses(options)),
// tryCombinChars expects CombinableDomNode[] while makeSpan expects
// DomChildNode[].
// $FlowFixMe: CombinableDomNode[] is not compatible with DomChildNode[]
body, newOptions); body, newOptions);
}, },
mathmlBuilder(group, options) { mathmlBuilder(group, options) {

View File

@@ -12,6 +12,7 @@ import utils from "./utils";
import type Options from "./Options"; import type Options from "./Options";
import type ParseNode from "./ParseNode"; import type ParseNode from "./ParseNode";
import type {DomSpan, SvgSpan} from "./domTree";
const stretchyCodePoint: {[string]: string} = { const stretchyCodePoint: {[string]: string} = {
widehat: "^", widehat: "^",
@@ -166,10 +167,10 @@ const groupLength = function(arg: ParseNode): number {
} }
}; };
const svgSpan = function(group: ParseNode, options: Options): domTree.span { const svgSpan = function(group: ParseNode, options: Options): DomSpan | SvgSpan {
// Create a span with inline SVG for the element. // Create a span with inline SVG for the element.
function buildSvgSpan_(): { function buildSvgSpan_(): {
span: domTree.span, span: DomSpan | SvgSpan,
minWidth: number, minWidth: number,
height: number, height: number,
} { } {
@@ -211,7 +212,7 @@ const svgSpan = function(group: ParseNode, options: Options): domTree.span {
"preserveAspectRatio": "none", "preserveAspectRatio": "none",
}); });
return { return {
span: buildCommon.makeSpan([], [svgNode], options), span: buildCommon.makeSvgSpan([], [svgNode], options),
minWidth: 0, minWidth: 0,
height, height,
}; };
@@ -249,8 +250,8 @@ const svgSpan = function(group: ParseNode, options: Options): domTree.span {
"preserveAspectRatio": aligns[i] + " slice", "preserveAspectRatio": aligns[i] + " slice",
}); });
const span = const span = buildCommon.makeSvgSpan(
buildCommon.makeSpan([widthClasses[i]], [svgNode], options); [widthClasses[i]], [svgNode], options);
if (numSvgChildren === 1) { if (numSvgChildren === 1) {
return {span, minWidth, height}; return {span, minWidth, height};
} else { } else {
@@ -280,11 +281,11 @@ const svgSpan = function(group: ParseNode, options: Options): domTree.span {
}; };
const encloseSpan = function( const encloseSpan = function(
inner: domTree.span, inner: DomSpan,
label: string, label: string,
pad: number, pad: number,
options: Options, options: Options,
): domTree.span { ): DomSpan | SvgSpan {
// Return an image span for \cancel, \bcancel, \xcancel, or \fbox // Return an image span for \cancel, \bcancel, \xcancel, or \fbox
let img; let img;
const totalHeight = inner.height + inner.depth + 2 * pad; const totalHeight = inner.height + inner.depth + 2 * pad;
@@ -330,7 +331,7 @@ const encloseSpan = function(
"height": totalHeight + "em", "height": totalHeight + "em",
}); });
img = buildCommon.makeSpan([], [svgNode], options); img = buildCommon.makeSvgSpan([], [svgNode], options);
} }
img.height = totalHeight; img.height = totalHeight;
@@ -339,8 +340,11 @@ const encloseSpan = function(
return img; return img;
}; };
const ruleSpan = function(className: string, lineThickness: number, const ruleSpan = function(
options: Options): domTree.span { className: string,
lineThickness: number,
options: Options,
): SvgSpan {
// Get a span with an SVG path that fills the middle fifth of the span. // Get a span with an SVG path that fills the middle fifth of the span.
// We're using an extra wide span so Chrome won't round it down to zero. // We're using an extra wide span so Chrome won't round it down to zero.
@@ -378,7 +382,7 @@ const ruleSpan = function(className: string, lineThickness: number,
}); });
} }
return buildCommon.makeSpan([parentClass], [svgNode], options); return buildCommon.makeSvgSpan([parentClass], [svgNode], options);
}; };
export default { export default {