Update katex to v0.16.21

This commit is contained in:
Will Faught
2025-01-19 11:08:41 -08:00
parent d663b8aa90
commit 3ac8d7b9b8
36 changed files with 1044 additions and 409 deletions

View File

@@ -700,7 +700,10 @@ const fontMap: {[string]: {| variant: FontVariant, fontName: string |}} = {
variant: "italic",
fontName: "Math-Italic",
},
"mathsfit": {
variant: "sans-serif-italic",
fontName: "SansSerif-Italic",
},
// "boldsymbol" is missing because they require the use of multiple fonts:
// Math-BoldItalic and Main-Bold. This is handled by a special case in
// makeOrd which ends up calling boldsymbol.

View File

@@ -98,6 +98,8 @@ export const getVariant = function(
return "bold";
} else if (font === "mathbb") {
return "double-struck";
} else if (font === "mathsfit") {
return "sans-serif-italic";
} else if (font === "mathfrak") {
return "fraktur";
} else if (font === "mathscr" || font === "mathcal") {
@@ -126,6 +128,30 @@ export const getVariant = function(
return null;
};
/**
* Check for <mi>.</mi> which is how a dot renders in MathML,
* or <mo separator="true" lspace="0em" rspace="0em">,</mo>
* which is how a braced comma {,} renders in MathML
*/
function isNumberPunctuation(group: ?MathNode): boolean {
if (!group) {
return false;
}
if (group.type === 'mi' && group.children.length === 1) {
const child = group.children[0];
return child instanceof TextNode && child.text === '.';
} else if (group.type === 'mo' && group.children.length === 1 &&
group.getAttribute('separator') === 'true' &&
group.getAttribute('lspace') === '0em' &&
group.getAttribute('rspace') === '0em'
) {
const child = group.children[0];
return child instanceof TextNode && child.text === ',';
} else {
return false;
}
}
/**
* Takes a list of nodes, builds them, and returns a list of the generated
* MathML nodes. Also combine consecutive <mtext> outputs into a single
@@ -163,13 +189,25 @@ export const buildExpression = function(
lastGroup.children.push(...group.children);
continue;
// Concatenate <mn>...</mn> followed by <mi>.</mi>
} else if (group.type === 'mi' && group.children.length === 1 &&
lastGroup.type === 'mn') {
const child = group.children[0];
if (child instanceof TextNode && child.text === '.') {
lastGroup.children.push(...group.children);
continue;
} else if (isNumberPunctuation(group) && lastGroup.type === 'mn') {
lastGroup.children.push(...group.children);
continue;
// Concatenate <mi>.</mi> followed by <mn>...</mn>
} else if (group.type === 'mn' && isNumberPunctuation(lastGroup)) {
group.children = [...lastGroup.children, ...group.children];
groups.pop();
// Put preceding <mn>...</mn> or <mi>.</mi> inside base of
// <msup><mn>...base...</mn>...exponent...</msup> (or <msub>)
} else if ((group.type === 'msup' || group.type === 'msub') &&
group.children.length >= 1 &&
(lastGroup.type === 'mn' || isNumberPunctuation(lastGroup))
) {
const base = group.children[0];
if (base instanceof MathNode && base.type === 'mn') {
base.children = [...lastGroup.children, ...base.children];
groups.pop();
}
// \not
} else if (lastGroup.type === 'mi' && lastGroup.children.length === 1) {
const lastChild = lastGroup.children[0];
if (lastChild instanceof TextNode && lastChild.text === '\u0338' &&

View File

@@ -17,6 +17,7 @@ import {path} from "./svgGeometry";
import type Options from "./Options";
import {DocumentFragment} from "./tree";
import {makeEm} from "./units";
import ParseError from "./ParseError";
import type {VirtualNode} from "./tree";
@@ -83,6 +84,16 @@ const toNode = function(tagName: string): HTMLElement {
return node;
};
/**
* https://w3c.github.io/html-reference/syntax.html#syntax-attributes
*
* > Attribute Names must consist of one or more characters
* other than the space characters, U+0000 NULL,
* '"', "'", ">", "/", "=", the control characters,
* and any characters that are not defined by Unicode.
*/
const invalidAttributeNameRegex = /[\s"'>/=\x00-\x1f]/;
/**
* Convert into an HTML markup string
*/
@@ -110,6 +121,9 @@ const toMarkup = function(tagName: string): string {
// Add the attributes
for (const attr in this.attributes) {
if (this.attributes.hasOwnProperty(attr)) {
if (invalidAttributeNameRegex.test(attr)) {
throw new ParseError(`Invalid attribute name '${attr}'`);
}
markup += ` ${attr}="${utils.escape(this.attributes[attr])}"`;
}
}

View File

@@ -75,7 +75,7 @@ const sigmasAndXis = {
// This value determines how large a pt is, for metrics which are defined
// in terms of pts.
// This value is also used in katex.less; if you change it make sure the
// This value is also used in katex.scss; if you change it make sure the
// values match.
ptPerEm: [10.0, 10.0, 10.0],

View File

@@ -1,64 +0,0 @@
@font-folder: "../fonts";
@use-ttf: true;
@use-woff: true;
@use-woff2: true;
.use-woff2(@family, @family-suffix) when (@use-woff2 = true) {
src+: url('@{font-folder}/KaTeX_@{family}-@{family-suffix}.woff2') format('woff2')
}
.use-woff(@family, @family-suffix) when (@use-woff = true) {
src+: url('@{font-folder}/KaTeX_@{family}-@{family-suffix}.woff') format('woff')
}
.use-ttf(@family, @family-suffix) when (@use-ttf = true) {
src+: url('@{font-folder}/KaTeX_@{family}-@{family-suffix}.ttf') format('truetype')
}
.generate-suffix(@weight, @style) when (@weight = normal) and (@style = normal) {
@suffix: 'Regular';
}
.generate-suffix(@weight, @style) when (@weight = normal) and (@style = italic) {
@suffix: 'Italic';
}
.generate-suffix(@weight, @style) when (@weight = bold) and (@style = normal) {
@suffix: 'Bold';
}
.generate-suffix(@weight, @style) when (@weight = bold) and (@style = italic) {
@suffix: 'BoldItalic';
}
.font-face(@family, @weight, @style) {
.generate-suffix(@weight, @style);
@font-face {
font-family: 'KaTeX_@{family}';
.use-woff2(@family, @suffix);
.use-woff(@family, @suffix);
.use-ttf(@family, @suffix);
font-weight: @weight;
font-style: @style;
}
}
.font-face('AMS', normal, normal);
.font-face('Caligraphic', bold, normal);
.font-face('Caligraphic', normal, normal);
.font-face('Fraktur', bold, normal);
.font-face('Fraktur', normal, normal);
.font-face('Main', bold, normal);
.font-face('Main', bold, italic);
.font-face('Main', normal, italic);
.font-face('Main', normal, normal);
//.font-face('Math', bold, normal);
.font-face('Math', bold, italic);
.font-face('Math', normal, italic);
//.font-face('Math', normal, normal);
.font-face('SansSerif', bold, normal);
.font-face('SansSerif', normal, italic);
.font-face('SansSerif', normal, normal);
.font-face('Script', normal, normal);
.font-face('Size1', normal, normal);
.font-face('Size2', normal, normal);
.font-face('Size3', normal, normal);
.font-face('Size4', normal, normal);
.font-face('Typewriter', normal, normal);

View File

@@ -33,7 +33,7 @@ defineFunction({
type: "font",
names: [
// styles, except \boldsymbol defined below
"\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal",
"\\mathrm", "\\mathit", "\\mathbf", "\\mathnormal", "\\mathsfit",
// families
"\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",

View File

@@ -11,6 +11,8 @@ defineFunction({
props: {
numArgs: 2,
numOptionalArgs: 1,
allowedInText: true,
allowedInMath: true,
argTypes: ["size", "size", "size"],
},
handler({parser}, args, optArgs) {

View File

@@ -30,9 +30,13 @@ const optionsWithFont = (group, options) => {
return options.withTextFontFamily(textFontFamilies[font]);
} else if (textFontWeights[font]) {
return options.withTextFontWeight(textFontWeights[font]);
} else {
return options.withTextFontShape(textFontShapes[font]);
} else if (font === "\\emph") {
return options.fontShape === "textit" ?
options.withTextFontShape("textup") :
options.withTextFontShape("textit");
}
return options.withTextFontShape(textFontShapes[font]);
};
defineFunction({
@@ -43,7 +47,7 @@ defineFunction({
// Font weights
"\\textbf", "\\textmd",
// Font Shapes
"\\textit", "\\textup",
"\\textit", "\\textup", "\\emph",
],
props: {
numArgs: 1,

View File

@@ -146,7 +146,9 @@ defineMacro("\\char", function(context) {
// \newcommand{\macro}[args]{definition}
// \renewcommand{\macro}[args]{definition}
// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition}
const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
const newcommand = (
context, existsOK: boolean, nonexistsOK: boolean, skipIfExists: boolean
) => {
let arg = context.consumeArg().tokens;
if (arg.length !== 1) {
throw new ParseError(
@@ -181,16 +183,21 @@ const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
arg = context.consumeArg().tokens;
}
// Final arg is the expansion of the macro
context.macros.set(name, {
tokens: arg,
numArgs,
});
if (!(exists && skipIfExists)) {
// Final arg is the expansion of the macro
context.macros.set(name, {
tokens: arg,
numArgs,
});
}
return '';
};
defineMacro("\\newcommand", (context) => newcommand(context, false, true));
defineMacro("\\renewcommand", (context) => newcommand(context, true, false));
defineMacro("\\providecommand", (context) => newcommand(context, true, true));
defineMacro("\\newcommand",
(context) => newcommand(context, false, true, false));
defineMacro("\\renewcommand",
(context) => newcommand(context, true, false, false));
defineMacro("\\providecommand",
(context) => newcommand(context, true, true, true));
// terminal (console) tools
defineMacro("\\message", (context) => {
@@ -341,7 +348,7 @@ defineMacro("\\lrcorner", "\\html@mathml{\\@lrcorner}{\\mathop{\\char\"231f}}");
// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
// We'll call \varvdots, which gets a glyph from symbols.js.
// The zero-width rule gets us an equivalent to the vertical 6pt kern.
defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}");
defineMacro("\\vdots", "{\\varvdots\\rule{0pt}{15pt}}");
defineMacro("\u22ee", "\\vdots");
//////////////////////////////////////////////////////////////////////
@@ -380,6 +387,12 @@ defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;");
defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;");
defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;");
// \def\dddot#1{{\mathop{#1}\limits^{\vbox to-1.4\ex@{\kern-\tw@\ex@
// \hbox{\normalfont ...}\vss}}}}
// We use \overset which avoids the vertical shift of \mathop.
defineMacro("\\dddot", "{\\overset{\\raisebox{-0.1ex}{\\normalsize ...}}{#1}}");
defineMacro("\\ddddot", "{\\overset{\\raisebox{-0.1ex}{\\normalsize ....}}{#1}}");
// AMSMath's automatic \dots, based on \mdots@@ macro.
const dotsByToken = {
',': '\\dotsc',

View File

@@ -95,7 +95,18 @@ export class MathNode implements MathDomNode {
}
for (let i = 0; i < this.children.length; i++) {
node.appendChild(this.children[i].toNode());
// Combine multiple TextNodes into one TextNode, to prevent
// screen readers from reading each as a separate word [#3995]
if (this.children[i] instanceof TextNode &&
this.children[i + 1] instanceof TextNode) {
let text = this.children[i].toText() + this.children[++i].toText();
while (this.children[i + 1] instanceof TextNode) {
text += this.children[++i].toText();
}
node.appendChild(new TextNode(text).toNode());
} else {
node.appendChild(this.children[i].toNode());
}
}
return node;

71
paige/node_modules/katex/src/styles/fonts.scss generated vendored Normal file
View File

@@ -0,0 +1,71 @@
$font-folder: "../../fonts" !default;
$use-woff2: true !default;
$use-woff: true !default;
$use-ttf: true !default;
@function generate-src($family, $family-suffix) {
$src: null;
@if $use-woff2 {
$src: append($src, url('#{$font-folder}/KaTeX_#{$family}-#{$family-suffix}.woff2') format('woff2'), comma);
}
@if $use-woff {
$src: append($src, url('#{$font-folder}/KaTeX_#{$family}-#{$family-suffix}.woff') format('woff'), comma);
}
@if $use-ttf {
$src: append($src, url('#{$font-folder}/KaTeX_#{$family}-#{$family-suffix}.ttf') format('truetype'), comma);
}
@return $src;
}
@function generate-suffix($weight, $style) {
$suffix: null;
@if $weight == normal and $style == normal {
$suffix: 'Regular';
}
@if $weight == normal and $style == italic {
$suffix: 'Italic';
}
@if $weight == bold and $style == normal {
$suffix: 'Bold';
}
@if $weight == bold and $style == italic {
$suffix: 'BoldItalic';
}
@return $suffix;
}
@mixin font-face($family, $weight, $style) {
$suffix: generate-suffix($weight, $style);
$src: generate-src($family, $suffix);
@font-face {
font-family: 'KaTeX_#{$family}';
src: $src;
font-weight: $weight;
font-style: $style;
}
}
@include font-face('AMS', normal, normal);
@include font-face('Caligraphic', bold, normal);
@include font-face('Caligraphic', normal, normal);
@include font-face('Fraktur', bold, normal);
@include font-face('Fraktur', normal, normal);
@include font-face('Main', bold, normal);
@include font-face('Main', bold, italic);
@include font-face('Main', normal, italic);
@include font-face('Main', normal, normal);
@include font-face('Math', bold, italic);
@include font-face('Math', normal, italic);
@include font-face('SansSerif', bold, normal);
@include font-face('SansSerif', normal, italic);
@include font-face('SansSerif', normal, normal);
@include font-face('Script', normal, normal);
@include font-face('Size1', normal, normal);
@include font-face('Size2', normal, normal);
@include font-face('Size3', normal, normal);
@include font-face('Size4', normal, normal);
@include font-face('Typewriter', normal, normal);

View File

@@ -1,11 +1,14 @@
/* stylelint-disable font-family-no-missing-generic-family-keyword */
@import "fonts.less";
@import "./fonts.scss";
// The mu unit is defined as 1/18 em
@mu: (1em / 18);
$mu: calc(1em / 18);
// The version is dynamically set from package.json via webpack.common.js
@version: "";
$version: "" !default;
// CSS margin property for math in display mode
$display-margin: 1em 0 !default;
.katex {
font: normal 1.21em KaTeX_Main, Times New Roman, serif;
@@ -27,7 +30,7 @@
}
.katex-version::after {
content: @version;
content: $version;
}
.katex-mathml {
@@ -155,6 +158,7 @@
font-weight: bold;
}
.mathsfit,
.mathitsf,
.textitsf {
font-family: KaTeX_SansSerif;
@@ -168,13 +172,13 @@
// This value is also used in fontMetrics.js, if you change it make sure the
// values match.
@ptperem: 10;
@nulldelimiterspace: (1.2em / @ptperem);
$ptperem: 10;
$nulldelimiterspace: calc(1.2em / $ptperem);
@muspace: 0.055556em; // 1mu
@thinspace: 0.16667em; // 3mu
@mediumspace: 0.22222em; // 4mu
@thickspace: 0.27778em; // 5mu
$muspace: 0.055556em; // 1mu
$thinspace: 0.16667em; // 3mu
$mediumspace: 0.22222em; // 4mu
$thickspace: 0.27778em; // 5mu
.vlist-t {
display: inline-table;
@@ -328,47 +332,23 @@
> .root {
/* These values are taken from the definition of `\r@@t`,
`\mkern 5mu` and `\mkern -10mu`. */
margin-left: 5*@mu;
margin-right: -10*@mu;
margin-left: calc(5*$mu);
margin-right: calc(-10*$mu);
}
}
.sizing,
.fontsize-ensurer {
@size1: 0.5;
@size2: 0.6;
@size3: 0.7;
@size4: 0.8;
@size5: 0.9;
@size6: 1;
@size7: 1.2;
@size8: 1.44;
@size9: 1.728;
@size10: 2.074;
@size11: 2.488;
$sizes: 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.2, 1.44, 1.728, 2.074, 2.488;
.generate-size-change(@from, @to) {
&.reset-size@{from}.size@{to} {
@sizeFromVariable: ~"size@{from}";
@sizeToVariable: ~"size@{to}";
font-size: (@@sizeToVariable / @@sizeFromVariable) * 1em;
@for $from from 1 through length($sizes) {
@for $to from 1 through length($sizes) {
&.reset-size#{$from}.size#{$to} {
/* stylelint-disable-next-line */
font-size: calc((nth($sizes, $to) / nth($sizes, $from)) * 1em);
}
}
}
.generate-to-size-change(@from, @currTo) when (@currTo =< 11) {
.generate-size-change(@from, @currTo);
.generate-to-size-change(@from, (@currTo + 1));
}
.generate-from-size-change(@currFrom) when (@currFrom =< 11) {
.generate-to-size-change(@currFrom, 1);
.generate-from-size-change((@currFrom + 1));
}
.generate-from-size-change(1);
}
.delimsizing {
@@ -390,7 +370,7 @@
.nulldelimiter {
display: inline-block;
width: @nulldelimiterspace;
width: $nulldelimiterspace;
}
.delimcenter {
@@ -645,7 +625,7 @@
.katex-display {
display: block;
margin: 1em 0;
margin: $display-margin;
text-align: center;
> .katex {

View File

@@ -673,7 +673,9 @@ defineSymbol(text, main, inner, "\u2026", "\\ldots", true);
defineSymbol(math, main, inner, "\u2026", "\\ldots", true);
defineSymbol(math, main, inner, "\u22ef", "\\@cdots", true);
defineSymbol(math, main, inner, "\u22f1", "\\ddots", true);
defineSymbol(math, main, textord, "\u22ee", "\\varvdots"); // \vdots is a macro
// \vdots is a macro that uses one of these two symbols (with made-up names):
defineSymbol(math, main, textord, "\u22ee", "\\varvdots");
defineSymbol(text, main, textord, "\u22ee", "\\varvdots");
defineSymbol(math, main, accent, "\u02ca", "\\acute");
defineSymbol(math, main, accent, "\u02cb", "\\grave");
defineSymbol(math, main, accent, "\u00a8", "\\ddot");
@@ -812,11 +814,11 @@ for (let i = 0; i < letters.length; i++) {
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);
wideChar = String.fromCharCode(0xD835, 0xDD04 + i); // A-Z a-z Fractur
wideChar = String.fromCharCode(0xD835, 0xDD04 + i); // A-Z a-z Fraktur
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);
wideChar = String.fromCharCode(0xD835, 0xDD6C + i); // A-Z a-z bold Fractur
wideChar = String.fromCharCode(0xD835, 0xDD6C + i); // A-Z a-z bold Fraktur
defineSymbol(math, main, mathord, ch, wideChar);
defineSymbol(text, main, textord, ch, wideChar);