@drghaliasri/butex 5.3.2 → 5.4.0

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.
package/dist/index.mjs CHANGED
@@ -109,17 +109,15 @@ mjx-container[jax="SVG"] svg text[data-butex-svg-text] {
109
109
  unicode-bidi: isolate;
110
110
  }
111
111
 
112
- .butex-preview-mirror {
112
+ /* CHTML only: CSS flip is safe here because layout is unaffected.
113
+ * SVG mirrors are baked into the transform attribute by patchBuTeXSvgMath
114
+ * (CSS transform would override MathJax's translate presentation attribute). */
115
+ mjx-container[jax="CHTML"] .butex-preview-mirror {
113
116
  transform: scaleX(-1);
114
117
  transform-origin: center;
115
118
  display: inline-block;
116
119
  }
117
120
 
118
- mjx-container[jax="SVG"] svg .butex-preview-mirror {
119
- transform-box: fill-box;
120
- transform-origin: center center;
121
- }
122
-
123
121
  /* Keeps Arabic text shaping sane after double flip; tweak fonts in page preamble */
124
122
  .mjx-rtl-unmirror .mjx-text,
125
123
  .mjx-rtl-unmirror .mjx-char {
@@ -747,11 +745,20 @@ function passthroughArgument(parser, name) {
747
745
  const inner = new TexParserClass(arg, parser.stack.env, parser.configuration).mml();
748
746
  parser.Push(inner);
749
747
  }
748
+ function arabvecArgument(parser, name) {
749
+ const arg = parser.GetArgument(name);
750
+ const TexParserClass = parser.constructor;
751
+ const tex = `\\butexmirror{\\vec{\\butexmirror{${arg}}}}`;
752
+ const inner = new TexParserClass(tex, parser.stack.env, parser.configuration).mml();
753
+ parser.Push(inner);
754
+ }
750
755
  var passthroughArgumentTyped = passthroughArgument;
756
+ var arabvecArgumentTyped = arabvecArgument;
751
757
  function registerPassthroughCommandMacros(CommandMap) {
752
758
  new CommandMap(COMMAND_MAP6, {
753
759
  unit: passthroughArgumentTyped,
754
- idx: passthroughArgumentTyped
760
+ idx: passthroughArgumentTyped,
761
+ arabvec: arabvecArgumentTyped
755
762
  });
756
763
  return COMMAND_MAP6;
757
764
  }
@@ -1077,6 +1084,320 @@ function buildSqrtNodeBody(node, buildChain, side) {
1077
1084
  return wrap;
1078
1085
  }
1079
1086
 
1087
+ // src/editor/display/overset.ts
1088
+ var OVERSET_CSS = `
1089
+ .overset {
1090
+ display: inline-flex;
1091
+ flex-direction: column;
1092
+ align-items: center;
1093
+ justify-content: center;
1094
+ vertical-align: middle;
1095
+ margin: 0 2px;
1096
+ min-width: 1.2em;
1097
+ }
1098
+
1099
+ .overset-over {
1100
+ display: inline-flex;
1101
+ justify-content: center;
1102
+ align-items: center;
1103
+ min-height: 0.85em;
1104
+ padding: 0 2px;
1105
+ font-size: 0.72em;
1106
+ line-height: 1.1;
1107
+ }
1108
+
1109
+ .overset-base {
1110
+ display: inline-flex;
1111
+ justify-content: center;
1112
+ align-items: center;
1113
+ min-height: 1.05em;
1114
+ padding: 0 2px;
1115
+ }
1116
+ `.trim();
1117
+ function buildOversetNodeBody(node, buildChain) {
1118
+ const wrap = document.createElement("span");
1119
+ wrap.className = "overset";
1120
+ const over = document.createElement("span");
1121
+ over.className = "overset-over";
1122
+ if (node.overExpr) {
1123
+ over.appendChild(buildChain(node.overExpr));
1124
+ }
1125
+ const base = document.createElement("span");
1126
+ base.className = "overset-base";
1127
+ if (node.baseExpr) {
1128
+ base.appendChild(buildChain(node.baseExpr));
1129
+ }
1130
+ wrap.appendChild(over);
1131
+ wrap.appendChild(base);
1132
+ return wrap;
1133
+ }
1134
+
1135
+ // src/editor/display/underset.ts
1136
+ var UNDERSET_CSS = `
1137
+ .underset {
1138
+ display: inline-flex;
1139
+ flex-direction: column;
1140
+ align-items: center;
1141
+ justify-content: center;
1142
+ vertical-align: middle;
1143
+ margin: 0 2px;
1144
+ min-width: 1.2em;
1145
+ }
1146
+
1147
+ .underset-base {
1148
+ display: inline-flex;
1149
+ justify-content: center;
1150
+ align-items: center;
1151
+ min-height: 1.05em;
1152
+ padding: 0 2px;
1153
+ }
1154
+
1155
+ .underset-under {
1156
+ display: inline-flex;
1157
+ justify-content: center;
1158
+ align-items: center;
1159
+ min-height: 0.85em;
1160
+ padding: 0 2px;
1161
+ font-size: 0.72em;
1162
+ line-height: 1.1;
1163
+ }
1164
+ `.trim();
1165
+ function buildUndersetNodeBody(node, buildChain) {
1166
+ const wrap = document.createElement("span");
1167
+ wrap.className = "underset";
1168
+ const base = document.createElement("span");
1169
+ base.className = "underset-base";
1170
+ if (node.baseExpr) {
1171
+ base.appendChild(buildChain(node.baseExpr));
1172
+ }
1173
+ const under = document.createElement("span");
1174
+ under.className = "underset-under";
1175
+ if (node.underExpr) {
1176
+ under.appendChild(buildChain(node.underExpr));
1177
+ }
1178
+ wrap.appendChild(base);
1179
+ wrap.appendChild(under);
1180
+ return wrap;
1181
+ }
1182
+
1183
+ // src/editor/accentCommands.ts
1184
+ var ACCENT_COMMANDS = {
1185
+ vec: {
1186
+ id: "vec",
1187
+ englishTex: "\\vec",
1188
+ arabicTex: "\\arabvec",
1189
+ placement: "over",
1190
+ label: "\u20D7",
1191
+ title: "\u0633\u0647\u0645 \u0641\u0648\u0642"
1192
+ },
1193
+ hat: {
1194
+ id: "hat",
1195
+ englishTex: "\\hat",
1196
+ arabicTex: "\\hat",
1197
+ placement: "over",
1198
+ label: "\u02C6",
1199
+ title: "\u0642\u0628\u0639\u0629"
1200
+ },
1201
+ tilde: {
1202
+ id: "tilde",
1203
+ englishTex: "\\tilde",
1204
+ arabicTex: "\\tilde",
1205
+ placement: "over",
1206
+ label: "\u02DC",
1207
+ title: "\u0645\u062F\u0629"
1208
+ },
1209
+ dot: {
1210
+ id: "dot",
1211
+ englishTex: "\\dot",
1212
+ arabicTex: "\\dot",
1213
+ placement: "over",
1214
+ label: "\u02D9",
1215
+ title: "\u0646\u0642\u0637\u0629 \u0641\u0648\u0642"
1216
+ },
1217
+ ddot: {
1218
+ id: "ddot",
1219
+ englishTex: "\\ddot",
1220
+ arabicTex: "\\ddot",
1221
+ placement: "over",
1222
+ label: "\xA8",
1223
+ title: "\u0646\u0642\u0637\u062A\u0627\u0646 \u0641\u0648\u0642"
1224
+ },
1225
+ dddot: {
1226
+ id: "dddot",
1227
+ englishTex: "\\dddot",
1228
+ arabicTex: "\\dddot",
1229
+ placement: "over",
1230
+ label: "\u20DB",
1231
+ title: "\u062B\u0644\u0627\u062B \u0646\u0642\u0627\u0637 \u0641\u0648\u0642"
1232
+ },
1233
+ bar: {
1234
+ id: "bar",
1235
+ englishTex: "\\bar",
1236
+ arabicTex: "\\bar",
1237
+ placement: "over",
1238
+ label: "\xAF",
1239
+ title: "\u062E\u0637 \u0641\u0648\u0642"
1240
+ },
1241
+ check: {
1242
+ id: "check",
1243
+ englishTex: "\\check",
1244
+ arabicTex: "\\check",
1245
+ placement: "over",
1246
+ label: "\u02C7",
1247
+ title: "\u0639\u0644\u0627\u0645\u0629 \u062A\u062D\u0642\u0642"
1248
+ },
1249
+ breve: {
1250
+ id: "breve",
1251
+ englishTex: "\\breve",
1252
+ arabicTex: "\\breve",
1253
+ placement: "over",
1254
+ label: "\u02D8",
1255
+ title: "\u0642\u0648\u0633 \u0642\u0635\u064A\u0631"
1256
+ },
1257
+ acute: {
1258
+ id: "acute",
1259
+ englishTex: "\\acute",
1260
+ arabicTex: "\\grave",
1261
+ placement: "over",
1262
+ label: "\xB4",
1263
+ title: "\u0646\u0628\u0631\u0629 \u062D\u0627\u062F\u0629"
1264
+ },
1265
+ grave: {
1266
+ id: "grave",
1267
+ englishTex: "\\grave",
1268
+ arabicTex: "\\acute",
1269
+ placement: "over",
1270
+ label: "`",
1271
+ title: "\u0646\u0628\u0631\u0629 \u062B\u0642\u064A\u0644\u0629"
1272
+ },
1273
+ overline: {
1274
+ id: "overline",
1275
+ englishTex: "\\overline",
1276
+ arabicTex: "\\overline",
1277
+ placement: "over",
1278
+ label: "\u203E",
1279
+ title: "\u062E\u0637 \u0639\u0644\u0648\u064A \u0645\u0645\u062A\u062F"
1280
+ },
1281
+ underline: {
1282
+ id: "underline",
1283
+ englishTex: "\\underline",
1284
+ arabicTex: "\\underline",
1285
+ placement: "under",
1286
+ label: "_",
1287
+ title: "\u062E\u0637 \u0633\u0641\u0644\u064A"
1288
+ },
1289
+ overleftarrow: {
1290
+ id: "overleftarrow",
1291
+ englishTex: "\\overleftarrow",
1292
+ arabicTex: "\\overrightarrow",
1293
+ placement: "over",
1294
+ label: "\u2190",
1295
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631"
1296
+ },
1297
+ overrightarrow: {
1298
+ id: "overrightarrow",
1299
+ englishTex: "\\overrightarrow",
1300
+ arabicTex: "\\overleftarrow",
1301
+ placement: "over",
1302
+ label: "\u2192",
1303
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646"
1304
+ },
1305
+ overleftrightarrow: {
1306
+ id: "overleftrightarrow",
1307
+ englishTex: "\\overleftrightarrow",
1308
+ arabicTex: "\\overleftrightarrow",
1309
+ placement: "over",
1310
+ label: "\u2194",
1311
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0645\u0632\u062F\u0648\u062C \u0627\u0644\u0627\u062A\u062C\u0627\u0647"
1312
+ }
1313
+ };
1314
+ function accentCommandSpec(id) {
1315
+ return Object.prototype.hasOwnProperty.call(ACCENT_COMMANDS, id) ? ACCENT_COMMANDS[id] : null;
1316
+ }
1317
+ function accentCommandsList() {
1318
+ return Object.values(ACCENT_COMMANDS);
1319
+ }
1320
+ function accentCommandIdFromTex(tex) {
1321
+ const normalized = tex.startsWith("\\") ? tex : `\\${tex}`;
1322
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1323
+ if (spec.englishTex === normalized) {
1324
+ return spec.id;
1325
+ }
1326
+ }
1327
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1328
+ if (spec.arabicTex === normalized) {
1329
+ return spec.id;
1330
+ }
1331
+ }
1332
+ return null;
1333
+ }
1334
+
1335
+ // src/editor/display/accent.ts
1336
+ var ACCENT_CSS = `
1337
+ .math-accent {
1338
+ display: inline-flex;
1339
+ flex-direction: column;
1340
+ align-items: center;
1341
+ justify-content: center;
1342
+ vertical-align: middle;
1343
+ margin: 0 2px;
1344
+ min-width: 1.1em;
1345
+ }
1346
+
1347
+ .math-accent-chrome {
1348
+ display: inline-flex;
1349
+ justify-content: center;
1350
+ align-items: center;
1351
+ min-height: 0.7em;
1352
+ padding: 0 2px;
1353
+ font-size: 0.85em;
1354
+ line-height: 1;
1355
+ color: var(--butex-script-color, #475569);
1356
+ user-select: none;
1357
+ }
1358
+
1359
+ .math-accent-base {
1360
+ display: inline-flex;
1361
+ justify-content: center;
1362
+ align-items: center;
1363
+ min-height: 1.05em;
1364
+ padding: 0 2px;
1365
+ }
1366
+
1367
+ .math-accent--under .math-accent-chrome {
1368
+ min-height: 0.45em;
1369
+ border-top: 1.5px solid currentColor;
1370
+ width: 100%;
1371
+ font-size: 0;
1372
+ color: var(--butex-surface-fg, #0f172a);
1373
+ }
1374
+ `.trim();
1375
+ function buildAccentNodeBody(node, buildChain) {
1376
+ const wrap = document.createElement("span");
1377
+ const spec = accentCommandSpec(node.expr);
1378
+ const placement = spec?.placement ?? "over";
1379
+ wrap.className = placement === "under" ? "math-accent math-accent--under" : "math-accent math-accent--over";
1380
+ const chrome = document.createElement("span");
1381
+ chrome.className = "math-accent-chrome";
1382
+ chrome.setAttribute("aria-hidden", "true");
1383
+ if (placement === "over") {
1384
+ chrome.textContent = spec?.label ?? "\u02C6";
1385
+ }
1386
+ const base = document.createElement("span");
1387
+ base.className = "math-accent-base";
1388
+ if (node.baseExpr) {
1389
+ base.appendChild(buildChain(node.baseExpr));
1390
+ }
1391
+ if (placement === "under") {
1392
+ wrap.appendChild(base);
1393
+ wrap.appendChild(chrome);
1394
+ } else {
1395
+ wrap.appendChild(chrome);
1396
+ wrap.appendChild(base);
1397
+ }
1398
+ return wrap;
1399
+ }
1400
+
1080
1401
  // src/editor/display/env.ts
1081
1402
  var WRAPPERS = {
1082
1403
  matrix: { left: "", right: "" },
@@ -1302,6 +1623,10 @@ var EQUATION_EDITOR_MESSAGES = {
1302
1623
  insertBraces: "\u0625\u062F\u0631\u0627\u062C \u062D\u0627\u0635\u0631\u062A\u064A\u0646",
1303
1624
  insertFraction: "\u0625\u062F\u0631\u0627\u062C \u0643\u0633\u0631",
1304
1625
  insertRoot: "\u0625\u062F\u0631\u0627\u062C \u062C\u0630\u0631",
1626
+ insertOverset: "\u0625\u062F\u0631\u0627\u062C \u0641\u0648\u0642",
1627
+ insertUnderset: "\u0625\u062F\u0631\u0627\u062C \u062A\u062D\u062A",
1628
+ insertAccentPair: "\u0625\u062F\u0631\u0627\u062C \u0641\u0648\u0642 \u0648\u062A\u062D\u062A",
1629
+ insertAccents: "\u0625\u062F\u0631\u0627\u062C \u0644\u0643\u0646\u0629",
1305
1630
  environments: "\u0627\u0644\u0628\u064A\u0626\u0627\u062A",
1306
1631
  insertEnvironment: "\u0625\u062F\u0631\u0627\u062C \u0628\u064A\u0626\u0629 \u0634\u0628\u0643\u064A\u0629",
1307
1632
  environmentType: "\u0646\u0648\u0639 \u0627\u0644\u0628\u064A\u0626\u0629",
@@ -1409,6 +1734,10 @@ var EQUATION_EDITOR_MESSAGES = {
1409
1734
  insertBraces: "Insert braces",
1410
1735
  insertFraction: "Insert fraction",
1411
1736
  insertRoot: "Insert root",
1737
+ insertOverset: "Insert overset",
1738
+ insertUnderset: "Insert underset",
1739
+ insertAccentPair: "Insert overset and underset",
1740
+ insertAccents: "Insert accent",
1412
1741
  environments: "Environments",
1413
1742
  insertEnvironment: "Insert grid environment",
1414
1743
  environmentType: "Environment type",
@@ -1676,7 +2005,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1676
2005
  id: "neq",
1677
2006
  category: "operators1",
1678
2007
  Tex: "\\neq",
1679
- mirror: false,
2008
+ mirror: true,
1680
2009
  Label: "\u2260",
1681
2010
  title: "\u0644\u0627 \u064A\u0633\u0627\u0648\u064A",
1682
2011
  svg_path: null
@@ -1686,6 +2015,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1686
2015
  category: "operators1",
1687
2016
  Tex: "\\approx",
1688
2017
  mirror: false,
2018
+ displayMirror: true,
1689
2019
  Label: "\u2248",
1690
2020
  title: "\u062A\u0642\u0631\u064A\u0628\u0627 \u064A\u0633\u0627\u0648\u064A",
1691
2021
  svg_path: null
@@ -1695,6 +2025,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1695
2025
  category: "operators1",
1696
2026
  Tex: "\\sim",
1697
2027
  mirror: false,
2028
+ displayMirror: true,
1698
2029
  Label: "\u223C",
1699
2030
  title: "\u0645\u0634\u0627\u0628\u0647",
1700
2031
  svg_path: null
@@ -1713,6 +2044,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1713
2044
  category: "operators1",
1714
2045
  Tex: "\\leq",
1715
2046
  mirror: true,
2047
+ displayMirror: false,
1716
2048
  Label: "\u2264",
1717
2049
  title: "\u0623\u0635\u063A\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
1718
2050
  svg_path: null
@@ -1722,6 +2054,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1722
2054
  category: "operators1",
1723
2055
  Tex: "\\geq",
1724
2056
  mirror: true,
2057
+ displayMirror: false,
1725
2058
  Label: "\u2265",
1726
2059
  title: "\u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
1727
2060
  svg_path: null
@@ -1731,6 +2064,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1731
2064
  category: "operators1",
1732
2065
  Tex: "\\coloneqq",
1733
2066
  mirror: true,
2067
+ displayMirror: false,
1734
2068
  Label: "\u2254",
1735
2069
  title: "\u064A\u0639\u0631\u0641 \u0628\u0623\u0646\u0647 \u064A\u0633\u0627\u0648\u064A",
1736
2070
  svg_path: null
@@ -1740,6 +2074,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1740
2074
  category: "operators1",
1741
2075
  Tex: "\\eqqcolon",
1742
2076
  mirror: true,
2077
+ displayMirror: false,
1743
2078
  Label: "\u2255",
1744
2079
  title: "\u064A\u0633\u0627\u0648\u064A \u0628\u0627\u0644\u062A\u0639\u0631\u064A\u0641",
1745
2080
  svg_path: null
@@ -1750,6 +2085,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1750
2085
  category: "operators2",
1751
2086
  Tex: "\\propto",
1752
2087
  mirror: true,
2088
+ displayMirror: false,
1753
2089
  Label: "\u221D",
1754
2090
  title: "\u064A\u062A\u0646\u0627\u0633\u0628 \u0645\u0639",
1755
2091
  svg_path: null
@@ -1759,6 +2095,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1759
2095
  category: "operators2",
1760
2096
  Tex: "\\in",
1761
2097
  mirror: true,
2098
+ displayMirror: false,
1762
2099
  Label: "\u2208",
1763
2100
  title: "\u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
1764
2101
  svg_path: null
@@ -1768,6 +2105,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1768
2105
  category: "operators2",
1769
2106
  Tex: "\\notin",
1770
2107
  mirror: false,
2108
+ displayMirror: true,
1771
2109
  Label: "\u2209",
1772
2110
  title: "\u0644\u0627 \u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
1773
2111
  svg_path: null
@@ -1777,6 +2115,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1777
2115
  category: "operators2",
1778
2116
  Tex: "\\subset",
1779
2117
  mirror: true,
2118
+ displayMirror: false,
1780
2119
  Label: "\u2282",
1781
2120
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0645\u0646",
1782
2121
  svg_path: null
@@ -1786,6 +2125,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1786
2125
  category: "operators2",
1787
2126
  Tex: "\\supset",
1788
2127
  mirror: true,
2128
+ displayMirror: false,
1789
2129
  Label: "\u2283",
1790
2130
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0644\u0640",
1791
2131
  svg_path: null
@@ -1795,6 +2135,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1795
2135
  category: "operators2",
1796
2136
  Tex: "\\subseteq",
1797
2137
  mirror: true,
2138
+ displayMirror: false,
1798
2139
  Label: "\u2286",
1799
2140
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1800
2141
  svg_path: null
@@ -1804,6 +2145,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1804
2145
  category: "operators2",
1805
2146
  Tex: "\\supseteq",
1806
2147
  mirror: true,
2148
+ displayMirror: false,
1807
2149
  Label: "\u2287",
1808
2150
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1809
2151
  svg_path: null
@@ -1813,6 +2155,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1813
2155
  category: "operators2",
1814
2156
  Tex: "\\cap",
1815
2157
  mirror: false,
2158
+ displayMirror: true,
1816
2159
  Label: "\u2229",
1817
2160
  title: "\u062A\u0642\u0627\u0637\u0639",
1818
2161
  svg_path: null
@@ -1822,6 +2165,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1822
2165
  category: "operators2",
1823
2166
  Tex: "\\cup",
1824
2167
  mirror: false,
2168
+ displayMirror: true,
1825
2169
  Label: "\u222A",
1826
2170
  title: "\u0627\u062A\u062D\u0627\u062F",
1827
2171
  svg_path: null
@@ -1831,6 +2175,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1831
2175
  category: "operators2",
1832
2176
  Tex: "\\emptyset",
1833
2177
  mirror: false,
2178
+ displayMirror: true,
1834
2179
  Label: "\u2205",
1835
2180
  title: "\u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0629 \u0627\u0644\u062E\u0627\u0644\u064A\u0629",
1836
2181
  svg_path: null
@@ -1840,6 +2185,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1840
2185
  category: "operators2",
1841
2186
  Tex: "\\nsubseteq",
1842
2187
  mirror: true,
2188
+ displayMirror: false,
1843
2189
  Label: "\u2288",
1844
2190
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1845
2191
  svg_path: null
@@ -1849,6 +2195,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
1849
2195
  category: "operators2",
1850
2196
  Tex: "\\nsupseteq",
1851
2197
  mirror: true,
2198
+ displayMirror: false,
1852
2199
  Label: "\u2289",
1853
2200
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1854
2201
  svg_path: null
@@ -2060,6 +2407,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2060
2407
  category: "integrals",
2061
2408
  Tex: "\\iint",
2062
2409
  mirror: true,
2410
+ displayMirror: false,
2063
2411
  Label: "\u222C",
2064
2412
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u0632\u062F\u0648\u062C",
2065
2413
  svg_path: null
@@ -2069,6 +2417,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2069
2417
  category: "integrals",
2070
2418
  Tex: "\\iiint",
2071
2419
  mirror: true,
2420
+ displayMirror: false,
2072
2421
  Label: "\u222D",
2073
2422
  title: "\u062A\u0643\u0627\u0645\u0644 \u062B\u0644\u0627\u062B\u064A",
2074
2423
  svg_path: null
@@ -2078,6 +2427,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2078
2427
  category: "integrals",
2079
2428
  Tex: "\\iiiint",
2080
2429
  mirror: true,
2430
+ displayMirror: false,
2081
2431
  Label: "\u2A0C",
2082
2432
  title: "\u062A\u0643\u0627\u0645\u0644 \u0631\u0628\u0627\u0639\u064A",
2083
2433
  svg_path: null
@@ -2087,6 +2437,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2087
2437
  category: "integrals",
2088
2438
  Tex: "\\oint",
2089
2439
  mirror: true,
2440
+ displayMirror: false,
2090
2441
  Label: "\u222E",
2091
2442
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u063A\u0644\u0642",
2092
2443
  svg_path: null
@@ -2096,6 +2447,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2096
2447
  category: "integrals",
2097
2448
  Tex: "\\oiint",
2098
2449
  mirror: true,
2450
+ displayMirror: false,
2099
2451
  Label: "\u222F",
2100
2452
  title: "\u062A\u0643\u0627\u0645\u0644 \u0633\u0637\u062D\u064A \u0645\u063A\u0644\u0642",
2101
2453
  svg_path: null
@@ -2105,6 +2457,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2105
2457
  category: "integrals",
2106
2458
  Tex: "\\oiiint",
2107
2459
  mirror: true,
2460
+ displayMirror: false,
2108
2461
  Label: "\u2230",
2109
2462
  title: "\u062A\u0643\u0627\u0645\u0644 \u062D\u062C\u0645\u064A \u0645\u063A\u0644\u0642",
2110
2463
  svg_path: null
@@ -2421,6 +2774,12 @@ ${FRAC_CSS}
2421
2774
 
2422
2775
  ${SQRT_CSS}
2423
2776
 
2777
+ ${OVERSET_CSS}
2778
+
2779
+ ${UNDERSET_CSS}
2780
+
2781
+ ${ACCENT_CSS}
2782
+
2424
2783
  ${MATRIX_ENV_CSS}
2425
2784
 
2426
2785
  ${ATOMIC_COMMAND_CSS}
@@ -2447,6 +2806,8 @@ function injectBuTeXEditorStyles(doc) {
2447
2806
  // src/editor/index.ts
2448
2807
  var editor_exports = {};
2449
2808
  __export(editor_exports, {
2809
+ ACCENT_COMMANDS: () => ACCENT_COMMANDS,
2810
+ ACCENT_CSS: () => ACCENT_CSS,
2450
2811
  ATOMIC_COMMANDS: () => ATOMIC_COMMANDS,
2451
2812
  ATOMIC_COMMAND_CSS: () => ATOMIC_COMMAND_CSS,
2452
2813
  ATOMIC_OPERATOR_COMMANDS: () => ATOMIC_OPERATOR_COMMANDS,
@@ -2457,7 +2818,12 @@ __export(editor_exports, {
2457
2818
  DELIMITER_CSS: () => DELIMITER_CSS,
2458
2819
  FRAC_CSS: () => FRAC_CSS,
2459
2820
  MATRIX_ENV_CSS: () => MATRIX_ENV_CSS,
2821
+ OVERSET_CSS: () => OVERSET_CSS,
2460
2822
  SQRT_CSS: () => SQRT_CSS,
2823
+ UNDERSET_CSS: () => UNDERSET_CSS,
2824
+ accentCommandIdFromTex: () => accentCommandIdFromTex,
2825
+ accentCommandSpec: () => accentCommandSpec,
2826
+ accentCommandsList: () => accentCommandsList,
2461
2827
  activeSideLabel: () => activeSideLabel,
2462
2828
  activeTreeKey: () => activeTreeKey,
2463
2829
  addMatrixColumn: () => addMatrixColumn,
@@ -2478,6 +2844,7 @@ __export(editor_exports, {
2478
2844
  collectCaretPositions: () => collectCaretPositions,
2479
2845
  copySelection: () => copySelection,
2480
2846
  coveredNodeIds: () => coveredNodeIds,
2847
+ createAccentNode: () => createAccentNode,
2481
2848
  createAtomicCommandNode: () => createAtomicCommandNode,
2482
2849
  createAtomicOperatorCommandNode: () => createAtomicOperatorCommandNode,
2483
2850
  createDelimiterNode: () => createDelimiterNode,
@@ -2488,8 +2855,10 @@ __export(editor_exports, {
2488
2855
  createFracNode: () => createFracNode,
2489
2856
  createGridEnvNode: () => createGridEnvNode,
2490
2857
  createMatrixEnvNode: () => createMatrixEnvNode,
2858
+ createOversetNode: () => createOversetNode,
2491
2859
  createSqrtNode: () => createSqrtNode,
2492
2860
  createStarterSession: () => createStarterSession,
2861
+ createUndersetNode: () => createUndersetNode,
2493
2862
  createUndoRedoStacks: () => createUndoRedoStacks,
2494
2863
  cutSelection: () => cutSelection,
2495
2864
  deleteBackward: () => deleteBackward,
@@ -2503,6 +2872,8 @@ __export(editor_exports, {
2503
2872
  fragmentToPlainText: () => fragmentToPlainText,
2504
2873
  horizontalCaretDelta: () => horizontalCaretDelta,
2505
2874
  injectBuTeXEditorStyles: () => injectBuTeXEditorStyles,
2875
+ insertAccent: () => insertAccent,
2876
+ insertAccentPair: () => insertAccentPair,
2506
2877
  insertAlignedEnv: () => insertAlignedEnv,
2507
2878
  insertArrayEnv: () => insertArrayEnv,
2508
2879
  insertAtomicCommand: () => insertAtomicCommand,
@@ -2512,11 +2883,14 @@ __export(editor_exports, {
2512
2883
  insertDivideOperator: () => insertDivideOperator,
2513
2884
  insertFirstDerivative: () => insertFirstDerivative,
2514
2885
  insertFraction: () => insertFraction,
2886
+ insertLimitsSeriesTemplate: () => insertLimitsSeriesTemplate,
2515
2887
  insertMatrixEnv: () => insertMatrixEnv,
2516
2888
  insertNumber: () => insertNumber,
2517
2889
  insertOperator: () => insertOperator,
2890
+ insertOverset: () => insertOverset,
2518
2891
  insertSecondDerivative: () => insertSecondDerivative,
2519
2892
  insertSqrt: () => insertSqrt,
2893
+ insertUnderset: () => insertUnderset,
2520
2894
  isSelectionActive: () => isSelectionActive,
2521
2895
  isSpacingCommandSpec: () => isSpacingCommandSpec,
2522
2896
  mirrorBuTeXOperatorsInTex: () => mirrorBuTeXOperatorsInTex,
@@ -2590,6 +2964,9 @@ function createEditorNode(kind, expr) {
2590
2964
  denominator: null,
2591
2965
  radicand: null,
2592
2966
  rootIndex: null,
2967
+ overExpr: null,
2968
+ underExpr: null,
2969
+ baseExpr: null,
2593
2970
  envName: null,
2594
2971
  matrixStyle: null,
2595
2972
  matrixRows: null,
@@ -2618,6 +2995,26 @@ function createSqrtNode() {
2618
2995
  rootIndex: createEditorChain()
2619
2996
  };
2620
2997
  }
2998
+ function createOversetNode() {
2999
+ return {
3000
+ ...createEditorNode("overset", ""),
3001
+ overExpr: createEditorChain(),
3002
+ baseExpr: createEditorChain()
3003
+ };
3004
+ }
3005
+ function createUndersetNode() {
3006
+ return {
3007
+ ...createEditorNode("underset", ""),
3008
+ underExpr: createEditorChain(),
3009
+ baseExpr: createEditorChain()
3010
+ };
3011
+ }
3012
+ function createAccentNode(accentId) {
3013
+ return {
3014
+ ...createEditorNode("accent", accentId),
3015
+ baseExpr: createEditorChain()
3016
+ };
3017
+ }
2621
3018
  function createMatrixEnvNode(style, rows, columns) {
2622
3019
  return createGridEnvNode(style, rows, columns);
2623
3020
  }
@@ -2685,6 +3082,15 @@ function collectNodeIds(chain, ids) {
2685
3082
  if (node.radicand) {
2686
3083
  collectNodeIds(node.radicand, ids);
2687
3084
  }
3085
+ if (node.overExpr) {
3086
+ collectNodeIds(node.overExpr, ids);
3087
+ }
3088
+ if (node.underExpr) {
3089
+ collectNodeIds(node.underExpr, ids);
3090
+ }
3091
+ if (node.baseExpr) {
3092
+ collectNodeIds(node.baseExpr, ids);
3093
+ }
2688
3094
  if (node.matrixRows) {
2689
3095
  for (const row of node.matrixRows) {
2690
3096
  for (const cell of row) {
@@ -2849,6 +3255,22 @@ function renderMatrixRowsArabic(node, options) {
2849
3255
  }
2850
3256
  return `\\begin{${envName}}${rows.join(" \\\\\n")}\\end{${envName}}`;
2851
3257
  }
3258
+ function renderAccentEnglish(command, accent, base, options) {
3259
+ const baseTex = base ? renderChainEnglish(base, options) : "";
3260
+ const accentTex = accent ? renderChainEnglish(accent, options) : "";
3261
+ if (accentTex === "") {
3262
+ return baseTex;
3263
+ }
3264
+ return `\\${command}{${accentTex}}{${baseTex}}`;
3265
+ }
3266
+ function renderAccentArabic(command, accent, base, options) {
3267
+ const baseTex = base ? renderChainArabic(base, options) : "";
3268
+ const accentTex = accent ? renderChainArabic(accent, options) : "";
3269
+ if (accentTex === "") {
3270
+ return baseTex;
3271
+ }
3272
+ return `\\${command}{${accentTex}}{${baseTex}}`;
3273
+ }
2852
3274
  function escapeText(s) {
2853
3275
  return s.replace(/\\/g, "\\textbackslash{}").replace(/[{}]/g, "\\$&");
2854
3276
  }
@@ -2878,6 +3300,19 @@ function renderNodeEnglish(node, options) {
2878
3300
  const body = `\\sqrt${optionalRootIndexEnglish(node, options)}{${renderChainEnglish(node.radicand, options)}}`;
2879
3301
  return `${body}${latinScripts(node, options)}`;
2880
3302
  }
3303
+ if (node.kind === "overset" && node.baseExpr) {
3304
+ const body = renderAccentEnglish("overset", node.overExpr, node.baseExpr, options);
3305
+ return `${body}${latinScripts(node, options)}`;
3306
+ }
3307
+ if (node.kind === "underset" && node.baseExpr) {
3308
+ const body = renderAccentEnglish("underset", node.underExpr, node.baseExpr, options);
3309
+ return `${body}${latinScripts(node, options)}`;
3310
+ }
3311
+ if (node.kind === "accent" && node.baseExpr) {
3312
+ const cmd = accentCommandSpec(node.expr)?.englishTex ?? `\\${node.expr}`;
3313
+ const body = `${cmd}{${renderChainEnglish(node.baseExpr, options)}}`;
3314
+ return `${body}${latinScripts(node, options)}`;
3315
+ }
2881
3316
  if (node.kind === "env") {
2882
3317
  return `${renderMatrixRowsEnglish(node, options)}${latinScripts(node, options)}`;
2883
3318
  }
@@ -2910,6 +3345,19 @@ function renderNodeArabic(node, options) {
2910
3345
  const content = `\\arabsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
2911
3346
  return arabicScripts(node, content, options);
2912
3347
  }
3348
+ if (node.kind === "overset" && node.baseExpr) {
3349
+ const content = renderAccentArabic("overset", node.overExpr, node.baseExpr, options);
3350
+ return arabicScripts(node, content, options);
3351
+ }
3352
+ if (node.kind === "underset" && node.baseExpr) {
3353
+ const content = renderAccentArabic("underset", node.underExpr, node.baseExpr, options);
3354
+ return arabicScripts(node, content, options);
3355
+ }
3356
+ if (node.kind === "accent" && node.baseExpr) {
3357
+ const cmd = accentCommandSpec(node.expr)?.arabicTex ?? `\\${node.expr}`;
3358
+ const content = `${cmd}{${renderChainArabic(node.baseExpr, options)}}`;
3359
+ return arabicScripts(node, content, options);
3360
+ }
2913
3361
  if (node.kind === "env") {
2914
3362
  return arabicScripts(node, renderMatrixRowsArabic(node, options), options);
2915
3363
  }
@@ -2966,6 +3414,35 @@ function collectCaretPositions(chain) {
2966
3414
  if (node.radicand) {
2967
3415
  walkChain(node.radicand);
2968
3416
  }
3417
+ if (node.kind === "overset") {
3418
+ if (node.overExpr) {
3419
+ walkChain(node.overExpr);
3420
+ }
3421
+ if (node.baseExpr) {
3422
+ walkChain(node.baseExpr);
3423
+ }
3424
+ } else if (node.kind === "underset") {
3425
+ if (node.baseExpr) {
3426
+ walkChain(node.baseExpr);
3427
+ }
3428
+ if (node.underExpr) {
3429
+ walkChain(node.underExpr);
3430
+ }
3431
+ } else if (node.kind === "accent") {
3432
+ if (node.baseExpr) {
3433
+ walkChain(node.baseExpr);
3434
+ }
3435
+ } else {
3436
+ if (node.overExpr) {
3437
+ walkChain(node.overExpr);
3438
+ }
3439
+ if (node.underExpr) {
3440
+ walkChain(node.underExpr);
3441
+ }
3442
+ if (node.baseExpr) {
3443
+ walkChain(node.baseExpr);
3444
+ }
3445
+ }
2969
3446
  if (node.matrixRows) {
2970
3447
  for (const row of node.matrixRows) {
2971
3448
  for (const cell of row) {
@@ -3099,6 +3576,42 @@ function findChainById(root, chainId) {
3099
3576
  return nested;
3100
3577
  }
3101
3578
  }
3579
+ if (node.overExpr) {
3580
+ if (node.overExpr.id === chainId) {
3581
+ return {
3582
+ chain: node.overExpr,
3583
+ relation: { kind: "overExpr", ownerNodeId: node.id, ownerChainId: root.id }
3584
+ };
3585
+ }
3586
+ const nested = findChainById(node.overExpr, chainId);
3587
+ if (nested) {
3588
+ return nested;
3589
+ }
3590
+ }
3591
+ if (node.underExpr) {
3592
+ if (node.underExpr.id === chainId) {
3593
+ return {
3594
+ chain: node.underExpr,
3595
+ relation: { kind: "underExpr", ownerNodeId: node.id, ownerChainId: root.id }
3596
+ };
3597
+ }
3598
+ const nested = findChainById(node.underExpr, chainId);
3599
+ if (nested) {
3600
+ return nested;
3601
+ }
3602
+ }
3603
+ if (node.baseExpr) {
3604
+ if (node.baseExpr.id === chainId) {
3605
+ return {
3606
+ chain: node.baseExpr,
3607
+ relation: { kind: "baseExpr", ownerNodeId: node.id, ownerChainId: root.id }
3608
+ };
3609
+ }
3610
+ const nested = findChainById(node.baseExpr, chainId);
3611
+ if (nested) {
3612
+ return nested;
3613
+ }
3614
+ }
3102
3615
  if (node.matrixRows) {
3103
3616
  for (let rowIndex = 0; rowIndex < node.matrixRows.length; rowIndex += 1) {
3104
3617
  const row = node.matrixRows[rowIndex];
@@ -3172,6 +3685,24 @@ function findNodeById(root, nodeId) {
3172
3685
  return nested;
3173
3686
  }
3174
3687
  }
3688
+ if (node.overExpr) {
3689
+ const nested = findNodeById(node.overExpr, nodeId);
3690
+ if (nested) {
3691
+ return nested;
3692
+ }
3693
+ }
3694
+ if (node.underExpr) {
3695
+ const nested = findNodeById(node.underExpr, nodeId);
3696
+ if (nested) {
3697
+ return nested;
3698
+ }
3699
+ }
3700
+ if (node.baseExpr) {
3701
+ const nested = findNodeById(node.baseExpr, nodeId);
3702
+ if (nested) {
3703
+ return nested;
3704
+ }
3705
+ }
3175
3706
  if (node.matrixRows) {
3176
3707
  for (const row of node.matrixRows) {
3177
3708
  for (const cell of row) {
@@ -3210,6 +3741,15 @@ function nodeChildChains(node) {
3210
3741
  if (node.radicand) {
3211
3742
  chains.push(node.radicand);
3212
3743
  }
3744
+ if (node.overExpr) {
3745
+ chains.push(node.overExpr);
3746
+ }
3747
+ if (node.underExpr) {
3748
+ chains.push(node.underExpr);
3749
+ }
3750
+ if (node.baseExpr) {
3751
+ chains.push(node.baseExpr);
3752
+ }
3213
3753
  if (node.matrixRows) {
3214
3754
  for (const row of node.matrixRows) {
3215
3755
  chains.push(...row);
@@ -3580,6 +4120,91 @@ function derivativeTemplateInitialCaret(englishFrac) {
3580
4120
  };
3581
4121
  }
3582
4122
 
4123
+ // src/editor/limitsTemplates.ts
4124
+ var LIMITS_SERIES_TEMPLATE_IDS = /* @__PURE__ */ new Set([
4125
+ "sum",
4126
+ "prod",
4127
+ "lim",
4128
+ "max",
4129
+ "min",
4130
+ "sup",
4131
+ "inf"
4132
+ ]);
4133
+ function isLimitsSeriesTemplateId(commandId) {
4134
+ return LIMITS_SERIES_TEMPLATE_IDS.has(commandId);
4135
+ }
4136
+ function syncChainIds2(english, arabic) {
4137
+ arabic.id = english.id;
4138
+ const limit = Math.min(english.nodes.length, arabic.nodes.length);
4139
+ for (let index = 0; index < limit; index += 1) {
4140
+ arabic.nodes[index].id = english.nodes[index].id;
4141
+ }
4142
+ }
4143
+ function syncOversetIds(english, arabic) {
4144
+ arabic.id = english.id;
4145
+ if (english.overExpr && arabic.overExpr) {
4146
+ syncChainIds2(english.overExpr, arabic.overExpr);
4147
+ }
4148
+ if (english.baseExpr && arabic.baseExpr) {
4149
+ syncChainIds2(english.baseExpr, arabic.baseExpr);
4150
+ }
4151
+ }
4152
+ function syncUndersetIds(english, arabic) {
4153
+ arabic.id = english.id;
4154
+ if (english.underExpr && arabic.underExpr) {
4155
+ syncChainIds2(english.underExpr, arabic.underExpr);
4156
+ }
4157
+ if (english.baseExpr && arabic.baseExpr) {
4158
+ syncChainIds2(english.baseExpr, arabic.baseExpr);
4159
+ }
4160
+ }
4161
+ function buildLimitsSeriesTemplate(commandId) {
4162
+ if (!isLimitsSeriesTemplateId(commandId)) {
4163
+ throw new Error(`BuTeX: unsupported limits-series template id: ${commandId}`);
4164
+ }
4165
+ const englishOp = createAtomicCommandNode(commandId);
4166
+ const arabicOp = createAtomicCommandNode(commandId);
4167
+ arabicOp.id = englishOp.id;
4168
+ const englishOverset = createOversetNode();
4169
+ const arabicOverset = createOversetNode();
4170
+ syncOversetIds(englishOverset, arabicOverset);
4171
+ englishOverset.baseExpr = createEditorChain([englishOp]);
4172
+ arabicOverset.baseExpr = createEditorChain([arabicOp]);
4173
+ syncChainIds2(englishOverset.baseExpr, arabicOverset.baseExpr);
4174
+ const englishUnderset = createUndersetNode();
4175
+ const arabicUnderset = createUndersetNode();
4176
+ syncUndersetIds(englishUnderset, arabicUnderset);
4177
+ englishUnderset.baseExpr = createEditorChain([englishOverset]);
4178
+ arabicUnderset.baseExpr = createEditorChain([arabicOverset]);
4179
+ syncChainIds2(englishUnderset.baseExpr, arabicUnderset.baseExpr);
4180
+ return { english: englishUnderset, arabic: arabicUnderset };
4181
+ }
4182
+ function buildAccentPairTemplate() {
4183
+ const englishOverset = createOversetNode();
4184
+ const arabicOverset = createOversetNode();
4185
+ syncOversetIds(englishOverset, arabicOverset);
4186
+ const englishUnderset = createUndersetNode();
4187
+ const arabicUnderset = createUndersetNode();
4188
+ syncUndersetIds(englishUnderset, arabicUnderset);
4189
+ englishUnderset.baseExpr = createEditorChain([englishOverset]);
4190
+ arabicUnderset.baseExpr = createEditorChain([arabicOverset]);
4191
+ syncChainIds2(englishUnderset.baseExpr, arabicUnderset.baseExpr);
4192
+ return { english: englishUnderset, arabic: arabicUnderset };
4193
+ }
4194
+ function accentPairTemplateInitialCaret(englishUnderset) {
4195
+ const overset = englishUnderset.baseExpr?.nodes[0];
4196
+ return {
4197
+ chainId: overset?.baseExpr?.id ?? englishUnderset.underExpr?.id ?? "",
4198
+ index: 0
4199
+ };
4200
+ }
4201
+ function limitsSeriesTemplateInitialCaret(englishUnderset) {
4202
+ return {
4203
+ chainId: englishUnderset.underExpr?.id ?? englishUnderset.baseExpr?.id ?? "",
4204
+ index: 0
4205
+ };
4206
+ }
4207
+
3583
4208
  // src/editor/state.ts
3584
4209
  function ensureSyncEntry(session, nodeId) {
3585
4210
  if (!session.sync[nodeId]) {
@@ -3613,7 +4238,7 @@ function syncSelectionToCaret(session) {
3613
4238
  session.selectedNodeId = located.relation.ownerNodeId;
3614
4239
  return;
3615
4240
  }
3616
- if (located.relation.kind === "inner" || located.relation.kind === "numerator" || located.relation.kind === "denominator" || located.relation.kind === "radicand" || located.relation.kind === "rootIndex" || located.relation.kind === "matrixCell") {
4241
+ if (located.relation.kind === "inner" || located.relation.kind === "numerator" || located.relation.kind === "denominator" || located.relation.kind === "radicand" || located.relation.kind === "rootIndex" || located.relation.kind === "overExpr" || located.relation.kind === "underExpr" || located.relation.kind === "baseExpr" || located.relation.kind === "matrixCell") {
3617
4242
  session.selectedNodeId = located.relation.ownerNodeId;
3618
4243
  return;
3619
4244
  }
@@ -3970,6 +4595,106 @@ function moveCaretVertical(session, direction) {
3970
4595
  appendDebug(next, "moveCaretVertical", "sqrt-radicand-down-exit");
3971
4596
  return next;
3972
4597
  }
4598
+ if (located.relation.kind === "overExpr" && ownerLocated && ownerNode && ownerNode.baseExpr) {
4599
+ if (direction === "down") {
4600
+ next.caret = {
4601
+ chainId: ownerNode.baseExpr.id,
4602
+ index: ownerNode.baseExpr.nodes.length
4603
+ };
4604
+ next.selectedStructureNodeId = null;
4605
+ syncSelectionToCaret(next);
4606
+ appendDebug(next, "moveCaretVertical", "overset-over->base");
4607
+ return next;
4608
+ }
4609
+ next.caret = {
4610
+ chainId: ownerLocated.chain.id,
4611
+ index: ownerLocated.index
4612
+ };
4613
+ next.selectedStructureNodeId = null;
4614
+ syncSelectionToCaret(next);
4615
+ appendDebug(next, "moveCaretVertical", "overset-over-up-exit");
4616
+ return next;
4617
+ }
4618
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "overset" && ownerNode.overExpr) {
4619
+ if (direction === "up") {
4620
+ next.caret = {
4621
+ chainId: ownerNode.overExpr.id,
4622
+ index: ownerNode.overExpr.nodes.length
4623
+ };
4624
+ next.selectedStructureNodeId = null;
4625
+ syncSelectionToCaret(next);
4626
+ appendDebug(next, "moveCaretVertical", "overset-base->over");
4627
+ return next;
4628
+ }
4629
+ next.caret = {
4630
+ chainId: ownerLocated.chain.id,
4631
+ index: ownerLocated.index + 1
4632
+ };
4633
+ next.selectedStructureNodeId = null;
4634
+ syncSelectionToCaret(next);
4635
+ appendDebug(next, "moveCaretVertical", "overset-base-down-exit");
4636
+ return next;
4637
+ }
4638
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "underset" && ownerNode.underExpr) {
4639
+ if (direction === "down") {
4640
+ next.caret = {
4641
+ chainId: ownerNode.underExpr.id,
4642
+ index: ownerNode.underExpr.nodes.length
4643
+ };
4644
+ next.selectedStructureNodeId = null;
4645
+ syncSelectionToCaret(next);
4646
+ appendDebug(next, "moveCaretVertical", "underset-base->under");
4647
+ return next;
4648
+ }
4649
+ next.caret = {
4650
+ chainId: ownerLocated.chain.id,
4651
+ index: ownerLocated.index
4652
+ };
4653
+ next.selectedStructureNodeId = null;
4654
+ syncSelectionToCaret(next);
4655
+ appendDebug(next, "moveCaretVertical", "underset-base-up-exit");
4656
+ return next;
4657
+ }
4658
+ if (located.relation.kind === "underExpr" && ownerLocated && ownerNode && ownerNode.baseExpr) {
4659
+ if (direction === "up") {
4660
+ next.caret = {
4661
+ chainId: ownerNode.baseExpr.id,
4662
+ index: ownerNode.baseExpr.nodes.length
4663
+ };
4664
+ next.selectedStructureNodeId = null;
4665
+ syncSelectionToCaret(next);
4666
+ appendDebug(next, "moveCaretVertical", "underset-under->base");
4667
+ return next;
4668
+ }
4669
+ next.caret = {
4670
+ chainId: ownerLocated.chain.id,
4671
+ index: ownerLocated.index + 1
4672
+ };
4673
+ next.selectedStructureNodeId = null;
4674
+ syncSelectionToCaret(next);
4675
+ appendDebug(next, "moveCaretVertical", "underset-under-down-exit");
4676
+ return next;
4677
+ }
4678
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "accent") {
4679
+ if (direction === "up") {
4680
+ next.caret = {
4681
+ chainId: ownerLocated.chain.id,
4682
+ index: ownerLocated.index
4683
+ };
4684
+ next.selectedStructureNodeId = null;
4685
+ syncSelectionToCaret(next);
4686
+ appendDebug(next, "moveCaretVertical", "accent-base-up-exit");
4687
+ return next;
4688
+ }
4689
+ next.caret = {
4690
+ chainId: ownerLocated.chain.id,
4691
+ index: ownerLocated.index + 1
4692
+ };
4693
+ next.selectedStructureNodeId = null;
4694
+ syncSelectionToCaret(next);
4695
+ appendDebug(next, "moveCaretVertical", "accent-base-down-exit");
4696
+ return next;
4697
+ }
3973
4698
  if (located.relation.kind === "matrixCell" && ownerLocated && ownerNode?.matrixRows) {
3974
4699
  const rowIndex = located.relation.rowIndex ?? 0;
3975
4700
  const columnIndex = located.relation.columnIndex ?? 0;
@@ -4347,6 +5072,119 @@ function insertSqrt(session) {
4347
5072
  appendDebug(next, "insertSqrt", "");
4348
5073
  return next;
4349
5074
  }
5075
+ function insertOverset(session) {
5076
+ const base = replaceSelectionFirst(session);
5077
+ const next = cloneEditorSession(base);
5078
+ const englishNode = createOversetNode();
5079
+ const arabicNode = createOversetNode();
5080
+ arabicNode.id = englishNode.id;
5081
+ if (arabicNode.overExpr && englishNode.overExpr) {
5082
+ arabicNode.overExpr.id = englishNode.overExpr.id;
5083
+ }
5084
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5085
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5086
+ }
5087
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5088
+ next.caret = {
5089
+ chainId: englishNode.overExpr ? englishNode.overExpr.id : next.caret.chainId,
5090
+ index: 0
5091
+ };
5092
+ next.selectedStructureNodeId = null;
5093
+ syncSelectionToCaret(next);
5094
+ appendDebug(next, "insertOverset", "");
5095
+ return next;
5096
+ }
5097
+ function insertUnderset(session) {
5098
+ const base = replaceSelectionFirst(session);
5099
+ const next = cloneEditorSession(base);
5100
+ const englishNode = createUndersetNode();
5101
+ const arabicNode = createUndersetNode();
5102
+ arabicNode.id = englishNode.id;
5103
+ if (arabicNode.underExpr && englishNode.underExpr) {
5104
+ arabicNode.underExpr.id = englishNode.underExpr.id;
5105
+ }
5106
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5107
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5108
+ }
5109
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5110
+ next.caret = {
5111
+ chainId: englishNode.underExpr ? englishNode.underExpr.id : next.caret.chainId,
5112
+ index: 0
5113
+ };
5114
+ next.selectedStructureNodeId = null;
5115
+ syncSelectionToCaret(next);
5116
+ appendDebug(next, "insertUnderset", "");
5117
+ return next;
5118
+ }
5119
+ function insertLimitsSeriesTemplate(session, commandId) {
5120
+ const base = replaceSelectionFirst(session);
5121
+ const next = cloneEditorSession(base);
5122
+ const { english, arabic } = buildLimitsSeriesTemplate(commandId);
5123
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
5124
+ syncSubtreeRecursive(next, english, arabic);
5125
+ next.caret = limitsSeriesTemplateInitialCaret(english);
5126
+ next.selectedStructureNodeId = null;
5127
+ syncSelectionToCaret(next);
5128
+ appendDebug(next, "insertLimitsSeriesTemplate", commandId);
5129
+ return next;
5130
+ }
5131
+ function insertAccentPair(session) {
5132
+ const base = replaceSelectionFirst(session);
5133
+ const next = cloneEditorSession(base);
5134
+ const { english, arabic } = buildAccentPairTemplate();
5135
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
5136
+ syncSubtreeRecursive(next, english, arabic);
5137
+ next.caret = accentPairTemplateInitialCaret(english);
5138
+ next.selectedStructureNodeId = null;
5139
+ syncSelectionToCaret(next);
5140
+ appendDebug(next, "insertAccentPair", "");
5141
+ return next;
5142
+ }
5143
+ function insertAccent(session, accentId) {
5144
+ const next = cloneEditorSession(session);
5145
+ const englishNode = createAccentNode(accentId);
5146
+ const arabicNode = createAccentNode(accentId);
5147
+ arabicNode.id = englishNode.id;
5148
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5149
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5150
+ }
5151
+ if (isSelectionActive(next.selection) && next.selection) {
5152
+ const sel = next.selection;
5153
+ const { start, end } = normalizeSelection(sel);
5154
+ const englishLocated = findChainById(next.englishTree, sel.chainId);
5155
+ const arabicLocated = findChainById(next.arabicTree, sel.chainId);
5156
+ if (englishLocated && arabicLocated && end > start) {
5157
+ const count = end - start;
5158
+ const englishWrapped = englishLocated.chain.nodes.splice(start, count);
5159
+ const arabicWrapped = arabicLocated.chain.nodes.splice(start, count);
5160
+ englishNode.baseExpr.nodes = englishWrapped;
5161
+ arabicNode.baseExpr.nodes = arabicWrapped;
5162
+ englishLocated.chain.nodes.splice(start, 0, englishNode);
5163
+ arabicLocated.chain.nodes.splice(start, 0, arabicNode);
5164
+ syncSubtreeRecursive(next, englishNode, arabicNode);
5165
+ next.caret = {
5166
+ chainId: englishNode.baseExpr.id,
5167
+ index: englishWrapped.length
5168
+ };
5169
+ next.selection = null;
5170
+ next.selectedStructureNodeId = null;
5171
+ syncSelectionToCaret(next);
5172
+ appendDebug(next, "insertAccent", `${accentId}:wrap`);
5173
+ return next;
5174
+ }
5175
+ }
5176
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5177
+ syncSubtreeRecursive(next, englishNode, arabicNode);
5178
+ next.caret = {
5179
+ chainId: englishNode.baseExpr ? englishNode.baseExpr.id : next.caret.chainId,
5180
+ index: 0
5181
+ };
5182
+ next.selection = null;
5183
+ next.selectedStructureNodeId = null;
5184
+ syncSelectionToCaret(next);
5185
+ appendDebug(next, "insertAccent", `${accentId}:empty`);
5186
+ return next;
5187
+ }
4350
5188
  function insertMatrixEnv(session, style, rows, columns) {
4351
5189
  return insertGridEnv(session, style, rows, columns);
4352
5190
  }
@@ -4594,7 +5432,7 @@ function deleteBackward(session) {
4594
5432
  if (!previousNode) {
4595
5433
  return session;
4596
5434
  }
4597
- if ((previousNode.kind === "delimiter" || previousNode.kind === "frac" || previousNode.kind === "sqrt" || previousNode.kind === "env") && next.selectedStructureNodeId !== previousNode.id) {
5435
+ if ((previousNode.kind === "delimiter" || previousNode.kind === "frac" || previousNode.kind === "sqrt" || previousNode.kind === "overset" || previousNode.kind === "underset" || previousNode.kind === "accent" || previousNode.kind === "env") && next.selectedStructureNodeId !== previousNode.id) {
4598
5436
  next.selectedStructureNodeId = previousNode.id;
4599
5437
  next.selectedNodeId = previousNode.id;
4600
5438
  appendDebug(next, "deleteBackward", "selected structure");
@@ -4889,6 +5727,15 @@ function buildNodeBody(node, buildChain, side, digitForm = "western", uiLocale =
4889
5727
  if (node.kind === "sqrt") {
4890
5728
  return buildSqrtNodeBody(node, buildChain, side);
4891
5729
  }
5730
+ if (node.kind === "overset") {
5731
+ return buildOversetNodeBody(node, buildChain);
5732
+ }
5733
+ if (node.kind === "underset") {
5734
+ return buildUndersetNodeBody(node, buildChain);
5735
+ }
5736
+ if (node.kind === "accent") {
5737
+ return buildAccentNodeBody(node, buildChain);
5738
+ }
4892
5739
  if (node.kind === "env") {
4893
5740
  return buildMatrixEnvNodeBody(node, buildChain, side);
4894
5741
  }
@@ -5597,6 +6444,26 @@ function createEditorRuntime(options) {
5597
6444
  applyStructural((prev) => insertSqrt(prev));
5598
6445
  surfaceEl.focus();
5599
6446
  },
6447
+ insertOverset: () => {
6448
+ applyStructural((prev) => insertOverset(prev));
6449
+ surfaceEl.focus();
6450
+ },
6451
+ insertUnderset: () => {
6452
+ applyStructural((prev) => insertUnderset(prev));
6453
+ surfaceEl.focus();
6454
+ },
6455
+ insertLimitsSeriesTemplate: (commandId) => {
6456
+ applyStructural((prev) => insertLimitsSeriesTemplate(prev, commandId));
6457
+ surfaceEl.focus();
6458
+ },
6459
+ insertAccentPair: () => {
6460
+ applyStructural((prev) => insertAccentPair(prev));
6461
+ surfaceEl.focus();
6462
+ },
6463
+ insertAccent: (accentId) => {
6464
+ applyStructural((prev) => insertAccent(prev, accentId));
6465
+ surfaceEl.focus();
6466
+ },
5600
6467
  insertAtomicCommand: (commandId) => {
5601
6468
  applyStructural((prev) => insertAtomicCommand(prev, commandId));
5602
6469
  surfaceEl.focus();
@@ -5826,7 +6693,10 @@ function parseBuTeX(input) {
5826
6693
  // src/mathjax/svgPatcher.ts
5827
6694
  var SVG_ARABSQRT_SELECTOR = 'mjx-container[jax="SVG"] svg .mjx-rtl-mirror[data-mjx-rtl-root="true"]';
5828
6695
  var ARABSQRT_SELECTOR = '.mjx-rtl-mirror[data-mjx-rtl-root="true"]';
6696
+ var SVG_PREVIEW_MIRROR_SELECTOR = 'mjx-container[jax="SVG"] svg .butex-preview-mirror';
6697
+ var PREVIEW_MIRROR_SELECTOR = ".butex-preview-mirror";
5829
6698
  var PATCHED_ATTR = "data-butex-svg-arabsqrt";
6699
+ var MIRROR_PATCHED_ATTR = "data-butex-svg-mirror";
5830
6700
  var ROOT_INDEX_SCALE = 0.72;
5831
6701
  var ROOT_INDEX_GAP_FACTOR = 0.08;
5832
6702
  var ROOT_INDEX_MIN_GAP = 2;
@@ -5851,11 +6721,12 @@ function directSvgElementChildren(element) {
5851
6721
  return Array.from(element.children).filter((child) => child instanceof SVGElement);
5852
6722
  }
5853
6723
  function boxFor(element) {
5854
- if (!(element instanceof SVGGraphicsElement) || typeof element.getBBox !== "function") {
6724
+ const candidate = element;
6725
+ if (typeof candidate.getBBox !== "function") {
5855
6726
  return null;
5856
6727
  }
5857
6728
  try {
5858
- const box = element.getBBox();
6729
+ const box = candidate.getBBox();
5859
6730
  return {
5860
6731
  x: box.x,
5861
6732
  y: box.y,
@@ -6099,6 +6970,31 @@ function patchArabSqrtRoot(root) {
6099
6970
  root.setAttribute(PATCHED_ATTR, "patched");
6100
6971
  rootNode.setAttribute(PATCHED_ATTR, "patched");
6101
6972
  }
6973
+ function patchPreviewMirror(element) {
6974
+ if (element.getAttribute(MIRROR_PATCHED_ATTR) === "patched") {
6975
+ return;
6976
+ }
6977
+ const box = boxFor(element);
6978
+ if (!box || box.width <= 0) {
6979
+ return;
6980
+ }
6981
+ const [tx, ty] = readTranslate(element);
6982
+ const mirrorX = tx + 2 * box.x + box.width;
6983
+ element.setAttribute(
6984
+ "transform",
6985
+ `translate(${roundSvg(mirrorX)},${roundSvg(ty)}) scale(-1,1)`
6986
+ );
6987
+ element.setAttribute(MIRROR_PATCHED_ATTR, "patched");
6988
+ }
6989
+ function collectPreviewMirrors(root) {
6990
+ let mirrors = Array.from(root.querySelectorAll(SVG_PREVIEW_MIRROR_SELECTOR));
6991
+ if (!mirrors.length) {
6992
+ mirrors = Array.from(root.querySelectorAll(PREVIEW_MIRROR_SELECTOR)).filter((candidate) => {
6993
+ return candidate.closest('mjx-container[jax="SVG"]') != null;
6994
+ });
6995
+ }
6996
+ return mirrors;
6997
+ }
6102
6998
  function patchBuTeXSvgMath(root) {
6103
6999
  if (typeof root.querySelectorAll !== "function") {
6104
7000
  return;
@@ -6110,6 +7006,7 @@ function patchBuTeXSvgMath(root) {
6110
7006
  });
6111
7007
  }
6112
7008
  roots.sort((a, b) => rootDepth(b) - rootDepth(a)).forEach((arabSqrtRoot) => patchArabSqrtRoot(arabSqrtRoot));
7009
+ collectPreviewMirrors(root).forEach((mirror) => patchPreviewMirror(mirror));
6113
7010
  }
6114
7011
 
6115
7012
  // src/mathjax/renderIsland.ts