1 |
|
2 | import defineFunction from "../defineFunction";
|
3 | import buildCommon from "../buildCommon";
|
4 | import mathMLTree from "../mathMLTree";
|
5 | import stretchy from "../stretchy";
|
6 |
|
7 | import * as html from "../buildHTML";
|
8 | import * as mml from "../buildMathML";
|
9 |
|
10 | import type {ParseNode} from "../parseNode";
|
11 |
|
12 |
|
13 | const paddedNode = group => {
|
14 | const node = new mathMLTree.MathNode("mpadded", group ? [group] : []);
|
15 | node.setAttribute("width", "+0.6em");
|
16 | node.setAttribute("lspace", "0.3em");
|
17 | return node;
|
18 | };
|
19 |
|
20 |
|
21 | defineFunction({
|
22 | type: "xArrow",
|
23 | names: [
|
24 | "\\xleftarrow", "\\xrightarrow", "\\xLeftarrow", "\\xRightarrow",
|
25 | "\\xleftrightarrow", "\\xLeftrightarrow", "\\xhookleftarrow",
|
26 | "\\xhookrightarrow", "\\xmapsto", "\\xrightharpoondown",
|
27 | "\\xrightharpoonup", "\\xleftharpoondown", "\\xleftharpoonup",
|
28 | "\\xrightleftharpoons", "\\xleftrightharpoons", "\\xlongequal",
|
29 | "\\xtwoheadrightarrow", "\\xtwoheadleftarrow", "\\xtofrom",
|
30 |
|
31 |
|
32 | "\\xrightleftarrows", "\\xrightequilibrium", "\\xleftequilibrium",
|
33 | ],
|
34 | props: {
|
35 | numArgs: 1,
|
36 | numOptionalArgs: 1,
|
37 | },
|
38 | handler({parser, funcName}, args, optArgs) {
|
39 | return {
|
40 | type: "xArrow",
|
41 | mode: parser.mode,
|
42 | label: funcName,
|
43 | body: args[0],
|
44 | below: optArgs[0],
|
45 | };
|
46 | },
|
47 |
|
48 |
|
49 | htmlBuilder(group: ParseNode<"xArrow">, options) {
|
50 | const style = options.style;
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | let newOptions = options.havingStyle(style.sup());
|
58 | const upperGroup = buildCommon.wrapFragment(
|
59 | html.buildGroup(group.body, newOptions, options), options);
|
60 | upperGroup.classes.push("x-arrow-pad");
|
61 |
|
62 | let lowerGroup;
|
63 | if (group.below) {
|
64 |
|
65 | newOptions = options.havingStyle(style.sub());
|
66 | lowerGroup = buildCommon.wrapFragment(
|
67 | html.buildGroup(group.below, newOptions, options), options);
|
68 | lowerGroup.classes.push("x-arrow-pad");
|
69 | }
|
70 |
|
71 | const arrowBody = stretchy.svgSpan(group, options);
|
72 |
|
73 |
|
74 |
|
75 | const arrowShift = -options.fontMetrics().axisHeight +
|
76 | 0.5 * arrowBody.height;
|
77 |
|
78 | let upperShift = -options.fontMetrics().axisHeight
|
79 | - 0.5 * arrowBody.height - 0.111;
|
80 | if (upperGroup.depth > 0.25 || group.label === "\\xleftequilibrium") {
|
81 | upperShift -= upperGroup.depth;
|
82 | }
|
83 |
|
84 |
|
85 | let vlist;
|
86 | if (lowerGroup) {
|
87 | const lowerShift = -options.fontMetrics().axisHeight
|
88 | + lowerGroup.height + 0.5 * arrowBody.height
|
89 | + 0.111;
|
90 | vlist = buildCommon.makeVList({
|
91 | positionType: "individualShift",
|
92 | children: [
|
93 | {type: "elem", elem: upperGroup, shift: upperShift},
|
94 | {type: "elem", elem: arrowBody, shift: arrowShift},
|
95 | {type: "elem", elem: lowerGroup, shift: lowerShift},
|
96 | ],
|
97 | }, options);
|
98 | } else {
|
99 | vlist = buildCommon.makeVList({
|
100 | positionType: "individualShift",
|
101 | children: [
|
102 | {type: "elem", elem: upperGroup, shift: upperShift},
|
103 | {type: "elem", elem: arrowBody, shift: arrowShift},
|
104 | ],
|
105 | }, options);
|
106 | }
|
107 |
|
108 |
|
109 | vlist.children[0].children[0].children[1].classes.push("svg-align");
|
110 |
|
111 | return buildCommon.makeSpan(["mrel", "x-arrow"], [vlist], options);
|
112 | },
|
113 | mathmlBuilder(group, options) {
|
114 | const arrowNode = stretchy.mathMLnode(group.label);
|
115 | let node;
|
116 |
|
117 | if (group.body) {
|
118 | const upperNode = paddedNode(mml.buildGroup(group.body, options));
|
119 | if (group.below) {
|
120 | const lowerNode = paddedNode(mml.buildGroup(group.below, options));
|
121 | node = new mathMLTree.MathNode(
|
122 | "munderover", [arrowNode, lowerNode, upperNode]
|
123 | );
|
124 | } else {
|
125 | node = new mathMLTree.MathNode("mover", [arrowNode, upperNode]);
|
126 | }
|
127 | } else if (group.below) {
|
128 | const lowerNode = paddedNode(mml.buildGroup(group.below, options));
|
129 | node = new mathMLTree.MathNode("munder", [arrowNode, lowerNode]);
|
130 | } else {
|
131 |
|
132 |
|
133 | node = paddedNode();
|
134 | node = new mathMLTree.MathNode("mover", [arrowNode, node]);
|
135 | }
|
136 | return node;
|
137 | },
|
138 | });
|