katex 0.16.44 → 0.16.46

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 (61) hide show
  1. package/README.md +3 -3
  2. package/contrib/copy-tex/README.md +2 -2
  3. package/contrib/mathtex-script-type/README.md +5 -5
  4. package/contrib/mathtex-script-type/mathtex-script-type.js +2 -1
  5. package/contrib/mhchem/README.md +1 -1
  6. package/contrib/render-a11y-string/render-a11y-string.ts +7 -5
  7. package/contrib/render-a11y-string/test/render-a11y-string-spec.ts +0 -1
  8. package/dist/README.md +3 -3
  9. package/dist/contrib/mathtex-script-type.js +2 -1
  10. package/dist/contrib/mathtex-script-type.min.js +1 -1
  11. package/dist/contrib/mathtex-script-type.mjs +2 -1
  12. package/dist/contrib/render-a11y-string.js +47 -8
  13. package/dist/contrib/render-a11y-string.min.js +1 -1
  14. package/dist/contrib/render-a11y-string.mjs +27 -2
  15. package/dist/katex-swap.css +5 -2
  16. package/dist/katex-swap.min.css +1 -1
  17. package/dist/katex.css +5 -2
  18. package/dist/katex.js +551 -345
  19. package/dist/katex.min.css +1 -1
  20. package/dist/katex.min.js +1 -1
  21. package/dist/katex.mjs +522 -348
  22. package/package.json +15 -15
  23. package/src/Options.ts +29 -28
  24. package/src/Parser.ts +12 -15
  25. package/src/Settings.ts +177 -60
  26. package/src/atoms.ts +33 -0
  27. package/src/buildCommon.ts +54 -46
  28. package/src/buildHTML.ts +4 -3
  29. package/src/buildMathML.ts +54 -47
  30. package/src/defineEnvironment.ts +1 -1
  31. package/src/defineFunction.ts +10 -3
  32. package/src/delimiter.ts +17 -13
  33. package/src/domTree.ts +28 -23
  34. package/src/environments/array.ts +12 -6
  35. package/src/environments/cd.ts +9 -2
  36. package/src/fontMetrics.ts +10 -23
  37. package/src/fontMetricsData.d.ts +6 -1
  38. package/src/functions/arrow.ts +4 -5
  39. package/src/functions/delimsizing.ts +22 -16
  40. package/src/functions/enclose.ts +6 -6
  41. package/src/functions/environment.ts +7 -2
  42. package/src/functions/font.ts +13 -8
  43. package/src/functions/hbox.ts +2 -2
  44. package/src/functions/horizBrace.ts +4 -6
  45. package/src/functions/math.ts +1 -0
  46. package/src/functions/op.ts +10 -5
  47. package/src/functions/smash.ts +1 -1
  48. package/src/functions/styling.ts +17 -5
  49. package/src/functions/supsub.ts +6 -3
  50. package/src/functions/text.ts +7 -3
  51. package/src/functions/vcenter.ts +3 -1
  52. package/src/parseNode.ts +7 -5
  53. package/src/stretchy.ts +14 -26
  54. package/src/styles/katex.scss +3 -1
  55. package/src/svgGeometry.ts +32 -27
  56. package/src/symbols.ts +11 -26
  57. package/src/tree.ts +11 -5
  58. package/src/types/fonts.ts +73 -0
  59. package/src/{types.ts → types/index.ts} +4 -10
  60. package/src/utils.ts +0 -1
  61. package/src/wide-character.ts +101 -55
package/src/stretchy.ts CHANGED
@@ -96,18 +96,6 @@ export const stretchyMathML = function(label: string): MathNode {
96
96
  // Some functions, such as \cancel, need to vary their aspect ratio. These
97
97
  // functions do not get the overflow SVG treatment.
98
98
 
99
- // Second Brush Stroke
100
- // Low resolution monitors struggle to display images in fine detail.
101
- // So browsers apply anti-aliasing. A long straight arrow shaft therefore
102
- // will sometimes appear as if it has a blurred edge.
103
-
104
- // To mitigate this, these SVG files contain a second "brush-stroke" on the
105
- // arrow shafts. That is, a second long thin rectangular SVG path has been
106
- // written directly on top of each arrow shaft. This reinforcement causes
107
- // some of the screen pixels to display as black instead of the anti-aliased
108
- // gray pixel that a single path would generate. So we get arrow shafts
109
- // whose edges appear to be sharper.
110
-
111
99
  // In the katexImagesData object just below, the dimensions all
112
100
  // correspond to path geometry inside the relevant SVG.
113
101
  // For example, \overrightarrow uses the same arrowhead as glyph U+2192
@@ -115,9 +103,9 @@ export const stretchyMathML = function(label: string): MathNode {
115
103
  // That is, inside the font, that arrowhead is 522 units tall, which
116
104
  // corresponds to 0.522 em inside the document.
117
105
 
118
- const katexImagesData: {
119
- [key: string]: ([string[], number, number] | [[string], number, number, string])
120
- } = {
106
+ type SvgData = [string[], number, number, string?];
107
+
108
+ const katexImagesData: {[key: string]: SvgData} = {
121
109
  // path(s), minWidth, height, align
122
110
  overrightarrow: [["rightarrow"], 0.888, 522, "xMaxYMin"],
123
111
  overleftarrow: [["leftarrow"], 0.888, 522, "xMinYMin"],
@@ -189,15 +177,11 @@ export const stretchySvg = function(
189
177
  } {
190
178
  let viewBoxWidth = 400000; // default
191
179
  const label = group.label.slice(1);
192
- if (wideAccentLabels.has(label)) {
193
- // Each type in the `if` statement corresponds to one of the ParseNode
194
- // types below. This narrowing is required to access `grp.base`.
195
- // TODO(ts)
196
- const grp = group as ParseNode<"accent"> | ParseNode<"accentUnder">;
180
+ if (wideAccentLabels.has(label) && 'base' in group) {
197
181
  // There are four SVG images available for each function.
198
182
  // Choose a taller image when there are more characters.
199
- const numChars = grp.base.type === "ordgroup" ?
200
- grp.base.body.length : 1;
183
+ const numChars = group.base.type === "ordgroup" ?
184
+ group.base.body.length : 1;
201
185
  let viewBoxHeight;
202
186
  let pathName;
203
187
  let height;
@@ -244,6 +228,9 @@ export const stretchySvg = function(
244
228
  const spans = [];
245
229
 
246
230
  const data = katexImagesData[label];
231
+ if (!data) {
232
+ throw new Error(`No SVG data for "${label}".`);
233
+ }
247
234
  const [paths, minWidth, viewBoxHeight] = data;
248
235
  const height = viewBoxHeight / 1000;
249
236
 
@@ -251,11 +238,12 @@ export const stretchySvg = function(
251
238
  let widthClasses;
252
239
  let aligns;
253
240
  if (numSvgChildren === 1) {
254
- // TODO(ts): All these cases must be of the 4-tuple type.
255
- const align1: string =
256
- (data as [[string], number, number, string])[3];
241
+ if (data.length !== 4) {
242
+ throw new Error(
243
+ `Expected 4-tuple for single-path SVG data "${label}".`);
244
+ }
257
245
  widthClasses = ["hide-tail"];
258
- aligns = [align1];
246
+ aligns = [data[3]];
259
247
  } else if (numSvgChildren === 2) {
260
248
  widthClasses = ["halfarrow-left", "halfarrow-right"];
261
249
  aligns = ["xMinYMin", "xMaxYMin"];
@@ -49,7 +49,7 @@ $display-margin: 1em 0 !default;
49
49
  /* Accessibility hack to only show to screen readers
50
50
  Found at: http://a11yproject.com/posts/how-to-hide-content/ */
51
51
  position: absolute;
52
- clip: rect(1px, 1px, 1px, 1px);
52
+ clip-path: inset(50%);
53
53
  padding: 0;
54
54
  border: 0;
55
55
  height: 1px;
@@ -349,7 +349,9 @@ $display-margin: 1em 0 !default;
349
349
  > .root {
350
350
  /* These values are taken from the definition of `\r@@t`,
351
351
  `\mkern 5mu` and `\mkern -10mu`. */
352
+ /* stylelint-disable-next-line declaration-property-value-no-unknown */
352
353
  margin-left: calc(5*$mu);
354
+ /* stylelint-disable-next-line declaration-property-value-no-unknown */
353
355
  margin-right: calc(-10*$mu);
354
356
  }
355
357
  }
@@ -5,6 +5,19 @@
5
5
 
6
6
  // In all paths below, the viewBox-to-em scale is 1000:1.
7
7
 
8
+ // Second Brush Stroke
9
+ // Low resolution monitors struggle to display images in fine detail.
10
+ // So browsers apply anti-aliasing. A long straight arrow shaft therefore
11
+ // will sometimes appear as if it has a blurred edge.
12
+
13
+ // To mitigate this, these SVG files contain a second "brush-stroke" on the
14
+ // arrow shafts. That is, a second long thin rectangular SVG path has been
15
+ // written directly on top of each arrow shaft. This reinforcement causes
16
+ // some of the screen pixels to display as black instead of the anti-aliased
17
+ // gray pixel that a single path would generate. So we get arrow shafts
18
+ // whose edges appear to be sharper.
19
+ const doubleBrushStroke = (svgPath: string): string => `${svgPath} ${svgPath}`;
20
+
8
21
  const hLinePad = 80; // padding above a sqrt vinculum. Prevents image cropping.
9
22
 
10
23
  // The vinculum of a \sqrt can be made thicker by a KaTeX rendering option.
@@ -154,25 +167,25 @@ export const innerPath = function(name: string, height: number): string {
154
167
  // The inner part of stretchy tall delimiters
155
168
  switch (name) {
156
169
  case "\u239c":
157
- return `M291 0 H417 V${height} H291z M291 0 H417 V${height} H291z`;
170
+ return doubleBrushStroke(`M291 0 H417 V${height} H291z`);
158
171
  case "\u2223":
159
- return `M145 0 H188 V${height} H145z M145 0 H188 V${height} H145z`;
172
+ return doubleBrushStroke(`M145 0 H188 V${height} H145z`);
160
173
  case "\u2225":
161
- return `M145 0 H188 V${height} H145z M145 0 H188 V${height} H145z` +
162
- `M367 0 H410 V${height} H367z M367 0 H410 V${height} H367z`;
174
+ return doubleBrushStroke(`M145 0 H188 V${height} H145z`) +
175
+ doubleBrushStroke(`M367 0 H410 V${height} H367z`);
163
176
  case "\u239f":
164
- return `M457 0 H583 V${height} H457z M457 0 H583 V${height} H457z`;
177
+ return doubleBrushStroke(`M457 0 H583 V${height} H457z`);
165
178
  case "\u23a2":
166
- return `M319 0 H403 V${height} H319z M319 0 H403 V${height} H319z`;
179
+ return doubleBrushStroke(`M319 0 H403 V${height} H319z`);
167
180
  case "\u23a5":
168
- return `M263 0 H347 V${height} H263z M263 0 H347 V${height} H263z`;
181
+ return doubleBrushStroke(`M263 0 H347 V${height} H263z`);
169
182
  case "\u23aa":
170
- return `M384 0 H504 V${height} H384z M384 0 H504 V${height} H384z`;
183
+ return doubleBrushStroke(`M384 0 H504 V${height} H384z`);
171
184
  case "\u23d0":
172
- return `M312 0 H355 V${height} H312z M312 0 H355 V${height} H312z`;
185
+ return doubleBrushStroke(`M312 0 H355 V${height} H312z`);
173
186
  case "\u2016":
174
- return `M257 0 H300 V${height} H257z M257 0 H300 V${height} H257z` +
175
- `M478 0 H521 V${height} H478z M478 0 H521 V${height} H478z`;
187
+ return doubleBrushStroke(`M257 0 H300 V${height} H257z`) +
188
+ doubleBrushStroke(`M478 0 H521 V${height} H478z`);
176
189
  default:
177
190
  return "";
178
191
  }
@@ -256,17 +269,13 @@ v40h399900v-40zM0 241v40h399900v-40zm0 0v40h399900v-40z`,
256
269
  -68.7 15.7-86 37-10 12-15 25.3-15 40 0 22.7 9.8 40.7 29.5 54 19.7 13.3 43.5 21
257
270
  71.5 23h399859zM103 281v-40h399897v40z`,
258
271
 
259
- leftlinesegment: `M40 281 V428 H0 V94 H40 V241 H400000 v40z
260
- M40 281 V428 H0 V94 H40 V241 H400000 v40z`,
272
+ leftlinesegment: doubleBrushStroke(`M40 281 V428 H0 V94 H40 V241 H400000 v40z`),
261
273
 
262
- leftbracketunder: `M0 0 h120 V290 H399995 v120 H0z
263
- M0 0 h120 V290 H399995 v120 H0z`,
274
+ leftbracketunder: doubleBrushStroke(`M0 0 h120 V290 H399995 v120 H0z`),
264
275
 
265
- leftbracketover: `M0 440 h120 V150 H399995 v-120 H0z
266
- M0 440 h120 V150 H399995 v-120 H0z`,
276
+ leftbracketover: doubleBrushStroke(`M0 440 h120 V150 H399995 v-120 H0z`),
267
277
 
268
- leftmapsto: `M40 281 V448H0V74H40V241H400000v40z
269
- M40 281 V448H0V74H40V241H400000v40z`,
278
+ leftmapsto: doubleBrushStroke(`M40 281 V448H0V74H40V241H400000v40z`),
270
279
 
271
280
  // tofrom is from glyph U+21C4 in font KaTeX AMS Regular
272
281
  leftToFrom: `M0 147h400000v40H0zm0 214c68 40 115.7 95.7 143 167h22c15.3 0 23
@@ -274,8 +283,7 @@ M40 281 V448H0V74H40V241H400000v40z`,
274
283
  c28.7-32 52-65.7 70-101 10.7-23.3 16-35.7 16-37 0-.7-7.7-1-23-1h-22C115.7 265.3
275
284
  68 321 0 361zm0-174v-40h399900v40zm100 154v40h399900v-40z`,
276
285
 
277
- longequal: `M0 50 h400000 v40H0z m0 194h40000v40H0z
278
- M0 50 h400000 v40H0z m0 194h40000v40H0z`,
286
+ longequal: doubleBrushStroke(`M0 50 h400000 v40H0z m0 194h40000v40H0z`),
279
287
 
280
288
  midbrace: `M200428 334
281
289
  c-100.7-8.3-195.3-44-280-108-55.3-42-101.7-93-139-153l-9-14c-2.7 4-5.7 8.7-9 14
@@ -358,14 +366,11 @@ m0-194v40h400000v-40zm0 0v40h400000v-40z`,
358
366
  -13.3 8.7-20 26-20 38 0 71 11.2 99 33.5 0 0 7 5.6 21 16.7 14 11.2 21 33.5 21
359
367
  66.8s-14 61.2-42 83.5c-28 22.3-61 33.5-99 33.5L0 241z M0 281v-40h399859v40z`,
360
368
 
361
- rightlinesegment: `M399960 241 V94 h40 V428 h-40 V281 H0 v-40z
362
- M399960 241 V94 h40 V428 h-40 V281 H0 v-40z`,
369
+ rightlinesegment: doubleBrushStroke(`M399960 241 V94 h40 V428 h-40 V281 H0 v-40z`),
363
370
 
364
- rightbracketunder: `M399995 0 h-120 V290 H0 v120 H400000z
365
- M399995 0 h-120 V290 H0 v120 H400000z`,
371
+ rightbracketunder: doubleBrushStroke(`M399995 0 h-120 V290 H0 v120 H400000z`),
366
372
 
367
- rightbracketover: `M399995 440 h-120 V150 H0 v-120 H399995z
368
- M399995 440 h-120 V150 H0 v-120 H399995z`,
373
+ rightbracketover: doubleBrushStroke(`M399995 440 h-120 V150 H0 v-120 H399995z`),
369
374
 
370
375
  rightToFrom: `M400000 167c-70.7-42-118-97.7-142-167h-23c-15.3 0-23 .3-23
371
376
  1 0 1.3 5.3 13.7 16 37 18 35.3 41.3 69 70 101l7 8H0v40h399905l-7 8c-28.7 32
package/src/symbols.ts CHANGED
@@ -16,34 +16,19 @@
16
16
  * accepted in (e.g. "math" or "text").
17
17
  */
18
18
 
19
+ import type {Group} from "./atoms";
19
20
  import type {Mode} from "./types";
21
+ import type {SymbolFont} from "./types/fonts";
20
22
 
21
- type Font = "main" | "ams";
22
23
  // Some of these have a "-token" suffix since these are also used as `ParseNode`
23
24
  // types for raw text tokens, and we want to avoid conflicts with higher-level
24
25
  // `ParseNode` types. These `ParseNode`s are constructed within `Parser` by
25
26
  // looking up the `symbols` map.
26
- export const ATOMS = {
27
- "bin": 1,
28
- "close": 1,
29
- "inner": 1,
30
- "open": 1,
31
- "punct": 1,
32
- "rel": 1,
33
- };
34
- export const NON_ATOMS = {
35
- "accent-token": 1,
36
- "mathord": 1,
37
- "op-token": 1,
38
- "spacing": 1,
39
- "textord": 1,
40
- };
41
-
42
- export type Atom = keyof typeof ATOMS;
43
- export type NonAtom = keyof typeof NON_ATOMS;
44
- export type Group = Atom | NonAtom;
45
27
 
46
- type CharInfoMap = Record<string, {font: Font, group: Group, replace: string | null | undefined}>;
28
+ type CharInfoMap = Record<
29
+ string,
30
+ {font: SymbolFont; group: Group; replace: string | null | undefined}
31
+ >;
47
32
 
48
33
  const symbols: Record<Mode, CharInfoMap> = {
49
34
  "math": {},
@@ -54,9 +39,9 @@ export default symbols;
54
39
  /** `acceptUnicodeChar = true` is only applicable if `replace` is set. */
55
40
  export function defineSymbol(
56
41
  mode: Mode,
57
- font: Font,
42
+ font: SymbolFont,
58
43
  group: Group,
59
- replace: string | null | undefined,
44
+ replace: string,
60
45
  name: string,
61
46
  acceptUnicodeChar?: boolean,
62
47
  ) {
@@ -595,8 +580,8 @@ defineSymbol(text, main, spacing, "\u00a0", "\\ ");
595
580
  defineSymbol(text, main, spacing, "\u00a0", " ");
596
581
  defineSymbol(text, main, spacing, "\u00a0", "\\space");
597
582
  defineSymbol(text, main, spacing, "\u00a0", "\\nobreakspace");
598
- defineSymbol(math, main, spacing, null, "\\nobreak");
599
- defineSymbol(math, main, spacing, null, "\\allowbreak");
583
+ defineSymbol(math, main, spacing, "", "\\nobreak");
584
+ defineSymbol(math, main, spacing, "", "\\allowbreak");
600
585
  defineSymbol(math, main, punct, ",", ",");
601
586
  defineSymbol(math, main, punct, ";", ";");
602
587
  defineSymbol(math, ams, bin, "\u22bc", "\\barwedge", true);
@@ -799,7 +784,7 @@ defineSymbol(text, main, mathord, "h", "\u210E");
799
784
  // Mathematical Alphanumeric Symbols.
800
785
  // Some editors do not deal well with wide characters. So don't write the
801
786
  // string into this file. Instead, create the string from the surrogate pair.
802
- let wideChar = "";
787
+ let wideChar;
803
788
  for (let i = 0; i < letters.length; i++) {
804
789
  const ch = letters.charAt(i);
805
790
 
package/src/tree.ts CHANGED
@@ -8,6 +8,10 @@ export interface VirtualNode {
8
8
  toMarkup(): string;
9
9
  }
10
10
 
11
+ function isMathDomNode(node: VirtualNode): node is MathDomNode {
12
+ return 'toText' in node;
13
+ }
14
+
11
15
 
12
16
  /**
13
17
  * This node represents a document fragment, which contains elements, but when
@@ -64,10 +68,12 @@ export class DocumentFragment<ChildType extends VirtualNode>
64
68
  * MathDomNode's only.
65
69
  */
66
70
  toText(): string {
67
- // To avoid this, we would subclass documentFragment separately for
68
- // MathML, but polyfills for subclassing is expensive per PR 1469.
69
- // TODO(ts): Only works for ChildType = MathDomNode.
70
- const toText = (child: ChildType): string => (child as unknown as MathDomNode).toText();
71
- return this.children.map(toText).join("");
71
+ return this.children.map((child: ChildType): string => {
72
+ if (isMathDomNode(child)) {
73
+ return child.toText();
74
+ }
75
+ throw new Error(
76
+ `Expected MathDomNode with toText, got ${child.constructor.name}`);
77
+ }).join("");
72
78
  }
73
79
  }
@@ -0,0 +1,73 @@
1
+ // Math font variants.
2
+ export type FontVariant =
3
+ | "bold"
4
+ | "bold-italic"
5
+ | "bold-sans-serif"
6
+ | "double-struck"
7
+ | "fraktur"
8
+ | "italic"
9
+ | "monospace"
10
+ | "normal"
11
+ | "sans-serif"
12
+ | "sans-serif-bold-italic"
13
+ | "sans-serif-italic"
14
+ | "script";
15
+
16
+ export type FontName =
17
+ | "AMS-Regular"
18
+ | "Caligraphic-Regular"
19
+ | "Fraktur-Regular"
20
+ | "Main-Bold"
21
+ | "Main-BoldItalic"
22
+ | "Main-Italic"
23
+ | "Main-Regular"
24
+ | "Math-BoldItalic"
25
+ | "Math-Italic"
26
+ | "SansSerif-Regular"
27
+ | "SansSerif-Bold"
28
+ | "SansSerif-Italic"
29
+ | "Script-Regular"
30
+ | "Size1-Regular"
31
+ | "Size2-Regular"
32
+ | "Size3-Regular"
33
+ | "Size4-Regular"
34
+ | "Typewriter-Regular";
35
+
36
+ //[depth, height, italic, skew, width]
37
+ export type CharacterMetricsTuple = [depth: number, height: number, italic: number, skew: number, width: number];
38
+
39
+ export type CharacterMetrics = {
40
+ depth: number;
41
+ height: number;
42
+ italic: number;
43
+ skew: number;
44
+ width: number;
45
+ };
46
+
47
+ export type FontMetrics = {
48
+ cssEmPerMu: number;
49
+ [key: string]: number;
50
+ };
51
+
52
+ export type SymbolFont = "main" | "ams";
53
+
54
+ export type MathFont =
55
+ | ""
56
+ | "mathrm"
57
+ | "mathit"
58
+ | "mathbf"
59
+ | "mathnormal"
60
+ | "mathsfit"
61
+ | "mathbb"
62
+ | "mathcal"
63
+ | "mathfrak"
64
+ | "mathscr"
65
+ | "mathsf"
66
+ | "mathtt"
67
+ | "boldsymbol";
68
+
69
+ export type TextFont = "textrm" | "textsf" | "texttt" | "amsrm" | "";
70
+
71
+ // In these types, "" (empty string) means "no change".
72
+ export type FontWeight = "textbf" | "textmd" | "";
73
+ export type FontShape = "textit" | "textup" | "";
@@ -1,9 +1,3 @@
1
-
2
- /**
3
- * This file consists only of basic types used in multiple places.
4
- * For types with javascript, create separate files by themselves.
5
- */
6
-
7
1
  export type Mode = "math" | "text";
8
2
 
9
3
  // LaTeX argument type.
@@ -29,7 +23,7 @@ export type StyleStr = "text" | "display" | "script" | "scriptscript";
29
23
  export type BreakToken = "]" | "}" | "\\endgroup" | "$" | "\\)" | "\\\\" | "\\end" |
30
24
  "EOF";
31
25
 
32
- // Math font variants.
33
- export type FontVariant = "bold" | "bold-italic" | "bold-sans-serif" |
34
- "double-struck" | "fraktur" | "italic" | "monospace" | "normal" | "sans-serif" |
35
- "sans-serif-bold-italic" | "sans-serif-italic" | "script";
26
+ export type DelimiterSize = 1 | 2 | 3 | 4;
27
+
28
+ export type Slice1<S extends string> =
29
+ S extends `${string}${infer Rest}` ? Rest : "";
package/src/utils.ts CHANGED
@@ -70,7 +70,6 @@ export const protocolFromUrl = (url: string): string | null => {
70
70
  // Check for possible leading protocol.
71
71
  // https://url.spec.whatwg.org/#url-parsing strips leading whitespace
72
72
  // (U+20) or C0 control (U+00-U+1F) characters.
73
- // eslint-disable-next-line no-control-regex
74
73
  const protocol = /^[\x00-\x20]*([^\\/#?]*?)(:|&#0*58|&#x0*3a|&colon)/i
75
74
  .exec(url);
76
75
  if (!protocol) {
@@ -6,101 +6,147 @@
6
6
  * the font information necessary to render it properly.
7
7
  */
8
8
 
9
- import type {Mode} from "./types";
10
9
  import ParseError from "./ParseError";
10
+ import type {FontName} from "./types/fonts";
11
+
12
+ type WideChar = {
13
+ readonly mathClass: string;
14
+ readonly textClass: string;
15
+ readonly font: Extract<FontName,
16
+ | "Main-Bold"
17
+ | "Math-Italic"
18
+ | "Main-BoldItalic"
19
+ | "Script-Regular"
20
+ | "Fraktur-Regular"
21
+ | "AMS-Regular"
22
+ | "SansSerif-Regular"
23
+ | "SansSerif-Bold"
24
+ | "SansSerif-Italic"
25
+ | "Typewriter-Regular"
26
+ > | "";
27
+ };
28
+
29
+ const boldUpright: WideChar = {
30
+ mathClass: "mathbf",
31
+ textClass: "textbf",
32
+ font: "Main-Bold",
33
+ };
34
+ const italic: WideChar = {
35
+ mathClass: "mathnormal",
36
+ textClass: "textit",
37
+ font: "Math-Italic",
38
+ };
39
+ const boldItalic: WideChar = {
40
+ mathClass: "boldsymbol",
41
+ textClass: "boldsymbol",
42
+ font: "Main-BoldItalic",
43
+ };
44
+ const script: WideChar = {
45
+ mathClass: "mathscr",
46
+ textClass: "textscr",
47
+ font: "Script-Regular",
48
+ };
49
+ const noFont: WideChar = {mathClass: "", textClass: "", font: ""};
50
+ const fraktur: WideChar = {
51
+ mathClass: "mathfrak",
52
+ textClass: "textfrak",
53
+ font: "Fraktur-Regular",
54
+ };
55
+ const doubleStruck: WideChar = {
56
+ mathClass: "mathbb",
57
+ textClass: "textbb",
58
+ font: "AMS-Regular",
59
+ };
60
+ const boldFraktur: WideChar = {
61
+ mathClass: "mathboldfrak",
62
+ textClass: "textboldfrak",
63
+ font: "Fraktur-Regular",
64
+ };
65
+ const sansSerif: WideChar = {
66
+ mathClass: "mathsf",
67
+ textClass: "textsf",
68
+ font: "SansSerif-Regular",
69
+ };
70
+ const boldSansSerif: WideChar = {
71
+ mathClass: "mathboldsf",
72
+ textClass: "textboldsf",
73
+ font: "SansSerif-Bold",
74
+ };
75
+ const italicSansSerif: WideChar = {
76
+ mathClass: "mathitsf",
77
+ textClass: "textitsf",
78
+ font: "SansSerif-Italic",
79
+ };
80
+ const monospace: WideChar = {
81
+ mathClass: "mathtt",
82
+ textClass: "texttt",
83
+ font: "Typewriter-Regular",
84
+ };
11
85
 
12
86
  /**
13
87
  * Data below is from https://www.unicode.org/charts/PDF/U1D400.pdf
14
88
  * That document sorts characters into groups by font type, say bold or italic.
15
89
  *
16
- * In the arrays below, each subarray consists three elements:
90
+ * In the arrays below, each object consists of three properties:
17
91
  * * The CSS class of that group when in math mode.
18
92
  * * The CSS class of that group when in text mode.
19
93
  * * The font name, so that KaTeX can get font metrics.
20
94
  */
21
95
 
22
96
  const wideLatinLetterData = [
23
- ["mathbf", "textbf", "Main-Bold"], // A-Z bold upright
24
- ["mathbf", "textbf", "Main-Bold"], // a-z bold upright
25
-
26
- ["mathnormal", "textit", "Math-Italic"], // A-Z italic
27
- ["mathnormal", "textit", "Math-Italic"], // a-z italic
28
-
29
- ["boldsymbol", "boldsymbol", "Main-BoldItalic"], // A-Z bold italic
30
- ["boldsymbol", "boldsymbol", "Main-BoldItalic"], // a-z bold italic
31
-
97
+ boldUpright, boldUpright, // A-Z, a-z
98
+ italic, italic, // A-Z, a-z
99
+ boldItalic, boldItalic, // A-Z, a-z
32
100
  // Map fancy A-Z letters to script, not calligraphic.
33
101
  // This aligns with unicode-math and math fonts (except Cambria Math).
34
- ["mathscr", "textscr", "Script-Regular"], // A-Z script
35
- ["", "", ""], // a-z script. No font
36
-
37
- ["", "", ""], // A-Z bold script. No font
38
- ["", "", ""], // a-z bold script. No font
39
-
40
- ["mathfrak", "textfrak", "Fraktur-Regular"], // A-Z Fraktur
41
- ["mathfrak", "textfrak", "Fraktur-Regular"], // a-z Fraktur
42
-
43
- ["mathbb", "textbb", "AMS-Regular"], // A-Z double-struck
44
- ["mathbb", "textbb", "AMS-Regular"], // k double-struck
45
-
102
+ script, noFont, // A-Z script, a-z — no font
103
+ noFont, noFont, // A-Z bold script, a-z bold script — no font
104
+ fraktur, fraktur, // A-Z, a-z
105
+ doubleStruck, doubleStruck, // A-Z double-struck, k double-struck
46
106
  // Note that we are using a bold font, but font metrics for regular Fraktur.
47
- ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // A-Z bold Fraktur
48
- ["mathboldfrak", "textboldfrak", "Fraktur-Regular"], // a-z bold Fraktur
49
-
50
- ["mathsf", "textsf", "SansSerif-Regular"], // A-Z sans-serif
51
- ["mathsf", "textsf", "SansSerif-Regular"], // a-z sans-serif
52
-
53
- ["mathboldsf", "textboldsf", "SansSerif-Bold"], // A-Z bold sans-serif
54
- ["mathboldsf", "textboldsf", "SansSerif-Bold"], // a-z bold sans-serif
55
-
56
- ["mathitsf", "textitsf", "SansSerif-Italic"], // A-Z italic sans-serif
57
- ["mathitsf", "textitsf", "SansSerif-Italic"], // a-z italic sans-serif
58
-
59
- ["", "", ""], // A-Z bold italic sans. No font
60
- ["", "", ""], // a-z bold italic sans. No font
61
-
62
- ["mathtt", "texttt", "Typewriter-Regular"], // A-Z monospace
63
- ["mathtt", "texttt", "Typewriter-Regular"], // a-z monospace
64
- ] as const satisfies readonly (readonly [string, string, string])[];
107
+ boldFraktur, boldFraktur, // A-Z, a-z
108
+ sansSerif, sansSerif, // A-Z, a-z
109
+ boldSansSerif, boldSansSerif, // A-Z, a-z
110
+ italicSansSerif, italicSansSerif, // A-Z, a-z
111
+ noFont, noFont, // A-Z bold italic sans, a-z bold italic sans - no font
112
+ monospace, monospace, // A-Z, a-z
113
+ ] as const;
65
114
 
66
115
  const wideNumeralData = [
67
- ["mathbf", "textbf", "Main-Bold"], // 0-9 bold
68
- ["", "", ""], // 0-9 double-struck. No KaTeX font.
69
- ["mathsf", "textsf", "SansSerif-Regular"], // 0-9 sans-serif
70
- ["mathboldsf", "textboldsf", "SansSerif-Bold"], // 0-9 bold sans-serif
71
- ["mathtt", "texttt", "Typewriter-Regular"], // 0-9 monospace
72
- ] as const satisfies readonly (readonly [string, string, string])[];
116
+ boldUpright, // 0-9
117
+ noFont, // 0-9 double-struck. No KaTeX font.
118
+ sansSerif, // 0-9
119
+ boldSansSerif, // 0-9
120
+ monospace, // 0-9
121
+ ] as const;
73
122
 
74
123
  export const wideCharacterFont = (
75
124
  wideChar: string,
76
- mode: Mode,
77
- ): [string, string] => {
125
+ ): WideChar => {
78
126
 
79
127
  // IE doesn't support codePointAt(). So work with the surrogate pair.
80
128
  const H = wideChar.charCodeAt(0); // high surrogate
81
129
  const L = wideChar.charCodeAt(1); // low surrogate
82
130
  const codePoint = ((H - 0xD800) * 0x400) + (L - 0xDC00) + 0x10000;
83
131
 
84
- const j = mode === "math" ? 0 : 1; // column index for CSS class.
85
-
86
132
  if (0x1D400 <= codePoint && codePoint < 0x1D6A4) {
87
133
  // wideLatinLetterData contains exactly 26 chars on each row.
88
134
  // So we can calculate the relevant row. No traverse necessary.
89
135
  const i = Math.floor((codePoint - 0x1D400) / 26);
90
- return [wideLatinLetterData[i]![2], wideLatinLetterData[i]![j]];
136
+ return wideLatinLetterData[i];
91
137
 
92
138
  } else if (0x1D7CE <= codePoint && codePoint <= 0x1D7FF) {
93
139
  // Numerals, ten per row.
94
140
  const i = Math.floor((codePoint - 0x1D7CE) / 10);
95
- return [wideNumeralData[i]![2], wideNumeralData[i]![j]];
141
+ return wideNumeralData[i];
96
142
 
97
143
  } else if (codePoint === 0x1D6A5 || codePoint === 0x1D6A6) {
98
144
  // dotless i or j
99
- return [wideLatinLetterData[0][2], wideLatinLetterData[0][j]];
145
+ return wideLatinLetterData[0];
100
146
 
101
147
  } else if (0x1D6A6 < codePoint && codePoint < 0x1D7CE) {
102
148
  // Greek letters. Not supported, yet.
103
- return ["", ""];
149
+ return noFont;
104
150
 
105
151
  } else {
106
152
  // We don't support any wide characters outside 1D400–1D7FF.