1 |
|
2 | import defineFunction from "../defineFunction";
|
3 | import buildCommon from "../buildCommon";
|
4 | import mathMLTree from "../mathMLTree";
|
5 | import stretchy from "../stretchy";
|
6 | import Style from "../Style";
|
7 | import {assertNodeType, checkNodeType} from "../parseNode";
|
8 |
|
9 | import * as html from "../buildHTML";
|
10 | import * as mml from "../buildMathML";
|
11 |
|
12 | import type {HtmlBuilderSupSub, MathMLBuilder} from "../defineFunction";
|
13 | import type {ParseNode} from "../parseNode";
|
14 |
|
15 |
|
16 |
|
17 | export const htmlBuilder: HtmlBuilderSupSub<"horizBrace"> = (grp, options) => {
|
18 | const style = options.style;
|
19 |
|
20 |
|
21 | let supSubGroup;
|
22 | let group: ParseNode<"horizBrace">;
|
23 | const supSub = checkNodeType(grp, "supsub");
|
24 | if (supSub) {
|
25 |
|
26 |
|
27 |
|
28 | supSubGroup = supSub.sup ?
|
29 | html.buildGroup(supSub.sup, options.havingStyle(style.sup()), options) :
|
30 | html.buildGroup(supSub.sub, options.havingStyle(style.sub()), options);
|
31 | group = assertNodeType(supSub.base, "horizBrace");
|
32 | } else {
|
33 | group = assertNodeType(grp, "horizBrace");
|
34 | }
|
35 |
|
36 |
|
37 | const body = html.buildGroup(
|
38 | group.base, options.havingBaseStyle(Style.DISPLAY));
|
39 |
|
40 |
|
41 | const braceBody = stretchy.svgSpan(group, options);
|
42 |
|
43 |
|
44 |
|
45 | let vlist;
|
46 | if (group.isOver) {
|
47 | vlist = buildCommon.makeVList({
|
48 | positionType: "firstBaseline",
|
49 | children: [
|
50 | {type: "elem", elem: body},
|
51 | {type: "kern", size: 0.1},
|
52 | {type: "elem", elem: braceBody},
|
53 | ],
|
54 | }, options);
|
55 |
|
56 | vlist.children[0].children[0].children[1].classes.push("svg-align");
|
57 | } else {
|
58 | vlist = buildCommon.makeVList({
|
59 | positionType: "bottom",
|
60 | positionData: body.depth + 0.1 + braceBody.height,
|
61 | children: [
|
62 | {type: "elem", elem: braceBody},
|
63 | {type: "kern", size: 0.1},
|
64 | {type: "elem", elem: body},
|
65 | ],
|
66 | }, options);
|
67 |
|
68 | vlist.children[0].children[0].children[0].classes.push("svg-align");
|
69 | }
|
70 |
|
71 | if (supSubGroup) {
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 |
|
81 | const vSpan = buildCommon.makeSpan(
|
82 | ["mord", (group.isOver ? "mover" : "munder")],
|
83 | [vlist], options);
|
84 |
|
85 | if (group.isOver) {
|
86 | vlist = buildCommon.makeVList({
|
87 | positionType: "firstBaseline",
|
88 | children: [
|
89 | {type: "elem", elem: vSpan},
|
90 | {type: "kern", size: 0.2},
|
91 | {type: "elem", elem: supSubGroup},
|
92 | ],
|
93 | }, options);
|
94 | } else {
|
95 | vlist = buildCommon.makeVList({
|
96 | positionType: "bottom",
|
97 | positionData: vSpan.depth + 0.2 + supSubGroup.height +
|
98 | supSubGroup.depth,
|
99 | children: [
|
100 | {type: "elem", elem: supSubGroup},
|
101 | {type: "kern", size: 0.2},
|
102 | {type: "elem", elem: vSpan},
|
103 | ],
|
104 | }, options);
|
105 | }
|
106 | }
|
107 |
|
108 | return buildCommon.makeSpan(
|
109 | ["mord", (group.isOver ? "mover" : "munder")], [vlist], options);
|
110 | };
|
111 |
|
112 | const mathmlBuilder: MathMLBuilder<"horizBrace"> = (group, options) => {
|
113 | const accentNode = stretchy.mathMLnode(group.label);
|
114 | return new mathMLTree.MathNode(
|
115 | (group.isOver ? "mover" : "munder"),
|
116 | [mml.buildGroup(group.base, options), accentNode]
|
117 | );
|
118 | };
|
119 |
|
120 |
|
121 | defineFunction({
|
122 | type: "horizBrace",
|
123 | names: ["\\overbrace", "\\underbrace"],
|
124 | props: {
|
125 | numArgs: 1,
|
126 | },
|
127 | handler({parser, funcName}, args) {
|
128 | return {
|
129 | type: "horizBrace",
|
130 | mode: parser.mode,
|
131 | label: funcName,
|
132 | isOver: /^\\over/.test(funcName),
|
133 | base: args[0],
|
134 | };
|
135 | },
|
136 | htmlBuilder,
|
137 | mathmlBuilder,
|
138 | });
|