Commit node_modules
This commit is contained in:
284
paige/node_modules/katex/src/functions/accent.js
generated
vendored
Normal file
284
paige/node_modules/katex/src/functions/accent.js
generated
vendored
Normal file
@@ -0,0 +1,284 @@
|
||||
// @flow
|
||||
import defineFunction, {normalizeArgument} from "../defineFunction";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import utils from "../utils";
|
||||
import stretchy from "../stretchy";
|
||||
import {assertNodeType} from "../parseNode";
|
||||
import {assertSpan, assertSymbolDomNode} from "../domTree";
|
||||
import {makeEm} from "../units";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type {ParseNode, AnyParseNode} from "../parseNode";
|
||||
import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
||||
|
||||
// NOTE: Unlike most `htmlBuilder`s, this one handles not only "accent", but
|
||||
// also "supsub" since an accent can affect super/subscripting.
|
||||
export const htmlBuilder: HtmlBuilderSupSub<"accent"> = (grp, options) => {
|
||||
// Accents are handled in the TeXbook pg. 443, rule 12.
|
||||
let base: AnyParseNode;
|
||||
let group: ParseNode<"accent">;
|
||||
|
||||
let supSubGroup;
|
||||
if (grp && grp.type === "supsub") {
|
||||
// If our base is a character box, and we have superscripts and
|
||||
// subscripts, the supsub will defer to us. In particular, we want
|
||||
// to attach the superscripts and subscripts to the inner body (so
|
||||
// that the position of the superscripts and subscripts won't be
|
||||
// affected by the height of the accent). We accomplish this by
|
||||
// sticking the base of the accent into the base of the supsub, and
|
||||
// rendering that, while keeping track of where the accent is.
|
||||
|
||||
// The real accent group is the base of the supsub group
|
||||
group = assertNodeType(grp.base, "accent");
|
||||
// The character box is the base of the accent group
|
||||
base = group.base;
|
||||
// Stick the character box into the base of the supsub group
|
||||
grp.base = base;
|
||||
|
||||
// Rerender the supsub group with its new base, and store that
|
||||
// result.
|
||||
supSubGroup = assertSpan(html.buildGroup(grp, options));
|
||||
|
||||
// reset original base
|
||||
grp.base = group;
|
||||
} else {
|
||||
group = assertNodeType(grp, "accent");
|
||||
base = group.base;
|
||||
}
|
||||
|
||||
// Build the base group
|
||||
const body = html.buildGroup(base, options.havingCrampedStyle());
|
||||
|
||||
// Does the accent need to shift for the skew of a character?
|
||||
const mustShift = group.isShifty && utils.isCharacterBox(base);
|
||||
|
||||
// Calculate the skew of the accent. This is based on the line "If the
|
||||
// nucleus is not a single character, let s = 0; otherwise set s to the
|
||||
// kern amount for the nucleus followed by the \skewchar of its font."
|
||||
// Note that our skew metrics are just the kern between each character
|
||||
// and the skewchar.
|
||||
let skew = 0;
|
||||
if (mustShift) {
|
||||
// If the base is a character box, then we want the skew of the
|
||||
// innermost character. To do that, we find the innermost character:
|
||||
const baseChar = utils.getBaseElem(base);
|
||||
// Then, we render its group to get the symbol inside it
|
||||
const baseGroup = html.buildGroup(baseChar, options.havingCrampedStyle());
|
||||
// Finally, we pull the skew off of the symbol.
|
||||
skew = assertSymbolDomNode(baseGroup).skew;
|
||||
// Note that we now throw away baseGroup, because the layers we
|
||||
// removed with getBaseElem might contain things like \color which
|
||||
// we can't get rid of.
|
||||
// TODO(emily): Find a better way to get the skew
|
||||
}
|
||||
|
||||
const accentBelow = group.label === "\\c";
|
||||
|
||||
// calculate the amount of space between the body and the accent
|
||||
let clearance = accentBelow
|
||||
? body.height + body.depth
|
||||
: Math.min(
|
||||
body.height,
|
||||
options.fontMetrics().xHeight);
|
||||
|
||||
// Build the accent
|
||||
let accentBody;
|
||||
if (!group.isStretchy) {
|
||||
let accent;
|
||||
let width: number;
|
||||
if (group.label === "\\vec") {
|
||||
// Before version 0.9, \vec used the combining font glyph U+20D7.
|
||||
// But browsers, especially Safari, are not consistent in how they
|
||||
// render combining characters when not preceded by a character.
|
||||
// So now we use an SVG.
|
||||
// If Safari reforms, we should consider reverting to the glyph.
|
||||
accent = buildCommon.staticSvg("vec", options);
|
||||
width = buildCommon.svgData.vec[1];
|
||||
} else {
|
||||
accent = buildCommon.makeOrd({mode: group.mode, text: group.label},
|
||||
options, "textord");
|
||||
accent = assertSymbolDomNode(accent);
|
||||
// Remove the italic correction of the accent, because it only serves to
|
||||
// shift the accent over to a place we don't want.
|
||||
accent.italic = 0;
|
||||
width = accent.width;
|
||||
if (accentBelow) {
|
||||
clearance += accent.depth;
|
||||
}
|
||||
}
|
||||
|
||||
accentBody = buildCommon.makeSpan(["accent-body"], [accent]);
|
||||
|
||||
// "Full" accents expand the width of the resulting symbol to be
|
||||
// at least the width of the accent, and overlap directly onto the
|
||||
// character without any vertical offset.
|
||||
const accentFull = (group.label === "\\textcircled");
|
||||
if (accentFull) {
|
||||
accentBody.classes.push('accent-full');
|
||||
clearance = body.height;
|
||||
}
|
||||
|
||||
// Shift the accent over by the skew.
|
||||
let left = skew;
|
||||
|
||||
// CSS defines `.katex .accent .accent-body:not(.accent-full) { width: 0 }`
|
||||
// so that the accent doesn't contribute to the bounding box.
|
||||
// We need to shift the character by its width (effectively half
|
||||
// its width) to compensate.
|
||||
if (!accentFull) {
|
||||
left -= width / 2;
|
||||
}
|
||||
|
||||
accentBody.style.left = makeEm(left);
|
||||
|
||||
// \textcircled uses the \bigcirc glyph, so it needs some
|
||||
// vertical adjustment to match LaTeX.
|
||||
if (group.label === "\\textcircled") {
|
||||
accentBody.style.top = ".2em";
|
||||
}
|
||||
|
||||
accentBody = buildCommon.makeVList({
|
||||
positionType: "firstBaseline",
|
||||
children: [
|
||||
{type: "elem", elem: body},
|
||||
{type: "kern", size: -clearance},
|
||||
{type: "elem", elem: accentBody},
|
||||
],
|
||||
}, options);
|
||||
|
||||
} else {
|
||||
accentBody = stretchy.svgSpan(group, options);
|
||||
|
||||
accentBody = buildCommon.makeVList({
|
||||
positionType: "firstBaseline",
|
||||
children: [
|
||||
{type: "elem", elem: body},
|
||||
{
|
||||
type: "elem",
|
||||
elem: accentBody,
|
||||
wrapperClasses: ["svg-align"],
|
||||
wrapperStyle: skew > 0
|
||||
? {
|
||||
width: `calc(100% - ${makeEm(2 * skew)})`,
|
||||
marginLeft: makeEm(2 * skew),
|
||||
}
|
||||
: undefined,
|
||||
},
|
||||
],
|
||||
}, options);
|
||||
}
|
||||
|
||||
const accentWrap =
|
||||
buildCommon.makeSpan(["mord", "accent"], [accentBody], options);
|
||||
|
||||
if (supSubGroup) {
|
||||
// Here, we replace the "base" child of the supsub with our newly
|
||||
// generated accent.
|
||||
supSubGroup.children[0] = accentWrap;
|
||||
|
||||
// Since we don't rerun the height calculation after replacing the
|
||||
// accent, we manually recalculate height.
|
||||
supSubGroup.height = Math.max(accentWrap.height, supSubGroup.height);
|
||||
|
||||
// Accents should always be ords, even when their innards are not.
|
||||
supSubGroup.classes[0] = "mord";
|
||||
|
||||
return supSubGroup;
|
||||
} else {
|
||||
return accentWrap;
|
||||
}
|
||||
};
|
||||
|
||||
const mathmlBuilder: MathMLBuilder<"accent"> = (group, options) => {
|
||||
const accentNode =
|
||||
group.isStretchy ?
|
||||
stretchy.mathMLnode(group.label) :
|
||||
new mathMLTree.MathNode("mo", [mml.makeText(group.label, group.mode)]);
|
||||
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mover",
|
||||
[mml.buildGroup(group.base, options), accentNode]);
|
||||
|
||||
node.setAttribute("accent", "true");
|
||||
|
||||
return node;
|
||||
};
|
||||
|
||||
const NON_STRETCHY_ACCENT_REGEX = new RegExp([
|
||||
"\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
|
||||
"\\check", "\\hat", "\\vec", "\\dot", "\\mathring",
|
||||
].map(accent => `\\${accent}`).join("|"));
|
||||
|
||||
// Accents
|
||||
defineFunction({
|
||||
type: "accent",
|
||||
names: [
|
||||
"\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
|
||||
"\\check", "\\hat", "\\vec", "\\dot", "\\mathring", "\\widecheck",
|
||||
"\\widehat", "\\widetilde", "\\overrightarrow", "\\overleftarrow",
|
||||
"\\Overrightarrow", "\\overleftrightarrow", "\\overgroup",
|
||||
"\\overlinesegment", "\\overleftharpoon", "\\overrightharpoon",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
},
|
||||
handler: (context, args) => {
|
||||
const base = normalizeArgument(args[0]);
|
||||
|
||||
const isStretchy = !NON_STRETCHY_ACCENT_REGEX.test(context.funcName);
|
||||
const isShifty = !isStretchy ||
|
||||
context.funcName === "\\widehat" ||
|
||||
context.funcName === "\\widetilde" ||
|
||||
context.funcName === "\\widecheck";
|
||||
|
||||
return {
|
||||
type: "accent",
|
||||
mode: context.parser.mode,
|
||||
label: context.funcName,
|
||||
isStretchy: isStretchy,
|
||||
isShifty: isShifty,
|
||||
base: base,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
// Text-mode accents
|
||||
defineFunction({
|
||||
type: "accent",
|
||||
names: [
|
||||
"\\'", "\\`", "\\^", "\\~", "\\=", "\\u", "\\.", '\\"',
|
||||
"\\c", "\\r", "\\H", "\\v", "\\textcircled",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
allowedInText: true,
|
||||
allowedInMath: true, // unless in strict mode
|
||||
argTypes: ["primitive"],
|
||||
},
|
||||
handler: (context, args) => {
|
||||
const base = args[0];
|
||||
let mode = context.parser.mode;
|
||||
|
||||
if (mode === "math") {
|
||||
context.parser.settings.reportNonstrict("mathVsTextAccents",
|
||||
`LaTeX's accent ${context.funcName} works only in text mode`);
|
||||
mode = "text";
|
||||
}
|
||||
|
||||
return {
|
||||
type: "accent",
|
||||
mode: mode,
|
||||
label: context.funcName,
|
||||
isStretchy: false,
|
||||
isShifty: true,
|
||||
base: base,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
Reference in New Issue
Block a user