@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.
@@ -151,17 +151,15 @@ mjx-container[jax="SVG"] svg text[data-butex-svg-text] {
151
151
  unicode-bidi: isolate;
152
152
  }
153
153
 
154
- .butex-preview-mirror {
154
+ /* CHTML only: CSS flip is safe here because layout is unaffected.
155
+ * SVG mirrors are baked into the transform attribute by patchBuTeXSvgMath
156
+ * (CSS transform would override MathJax's translate presentation attribute). */
157
+ mjx-container[jax="CHTML"] .butex-preview-mirror {
155
158
  transform: scaleX(-1);
156
159
  transform-origin: center;
157
160
  display: inline-block;
158
161
  }
159
162
 
160
- mjx-container[jax="SVG"] svg .butex-preview-mirror {
161
- transform-box: fill-box;
162
- transform-origin: center center;
163
- }
164
-
165
163
  /* Keeps Arabic text shaping sane after double flip; tweak fonts in page preamble */
166
164
  .mjx-rtl-unmirror .mjx-text,
167
165
  .mjx-rtl-unmirror .mjx-char {
@@ -789,11 +787,20 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
789
787
  const inner = new TexParserClass(arg, parser.stack.env, parser.configuration).mml();
790
788
  parser.Push(inner);
791
789
  }
790
+ function arabvecArgument(parser, name) {
791
+ const arg = parser.GetArgument(name);
792
+ const TexParserClass = parser.constructor;
793
+ const tex = `\\butexmirror{\\vec{\\butexmirror{${arg}}}}`;
794
+ const inner = new TexParserClass(tex, parser.stack.env, parser.configuration).mml();
795
+ parser.Push(inner);
796
+ }
792
797
  var passthroughArgumentTyped = passthroughArgument;
798
+ var arabvecArgumentTyped = arabvecArgument;
793
799
  function registerPassthroughCommandMacros(CommandMap) {
794
800
  new CommandMap(COMMAND_MAP6, {
795
801
  unit: passthroughArgumentTyped,
796
- idx: passthroughArgumentTyped
802
+ idx: passthroughArgumentTyped,
803
+ arabvec: arabvecArgumentTyped
797
804
  });
798
805
  return COMMAND_MAP6;
799
806
  }
@@ -1119,6 +1126,320 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1119
1126
  return wrap;
1120
1127
  }
1121
1128
 
1129
+ // src/editor/display/overset.ts
1130
+ var OVERSET_CSS = `
1131
+ .overset {
1132
+ display: inline-flex;
1133
+ flex-direction: column;
1134
+ align-items: center;
1135
+ justify-content: center;
1136
+ vertical-align: middle;
1137
+ margin: 0 2px;
1138
+ min-width: 1.2em;
1139
+ }
1140
+
1141
+ .overset-over {
1142
+ display: inline-flex;
1143
+ justify-content: center;
1144
+ align-items: center;
1145
+ min-height: 0.85em;
1146
+ padding: 0 2px;
1147
+ font-size: 0.72em;
1148
+ line-height: 1.1;
1149
+ }
1150
+
1151
+ .overset-base {
1152
+ display: inline-flex;
1153
+ justify-content: center;
1154
+ align-items: center;
1155
+ min-height: 1.05em;
1156
+ padding: 0 2px;
1157
+ }
1158
+ `.trim();
1159
+ function buildOversetNodeBody(node, buildChain) {
1160
+ const wrap = document.createElement("span");
1161
+ wrap.className = "overset";
1162
+ const over = document.createElement("span");
1163
+ over.className = "overset-over";
1164
+ if (node.overExpr) {
1165
+ over.appendChild(buildChain(node.overExpr));
1166
+ }
1167
+ const base = document.createElement("span");
1168
+ base.className = "overset-base";
1169
+ if (node.baseExpr) {
1170
+ base.appendChild(buildChain(node.baseExpr));
1171
+ }
1172
+ wrap.appendChild(over);
1173
+ wrap.appendChild(base);
1174
+ return wrap;
1175
+ }
1176
+
1177
+ // src/editor/display/underset.ts
1178
+ var UNDERSET_CSS = `
1179
+ .underset {
1180
+ display: inline-flex;
1181
+ flex-direction: column;
1182
+ align-items: center;
1183
+ justify-content: center;
1184
+ vertical-align: middle;
1185
+ margin: 0 2px;
1186
+ min-width: 1.2em;
1187
+ }
1188
+
1189
+ .underset-base {
1190
+ display: inline-flex;
1191
+ justify-content: center;
1192
+ align-items: center;
1193
+ min-height: 1.05em;
1194
+ padding: 0 2px;
1195
+ }
1196
+
1197
+ .underset-under {
1198
+ display: inline-flex;
1199
+ justify-content: center;
1200
+ align-items: center;
1201
+ min-height: 0.85em;
1202
+ padding: 0 2px;
1203
+ font-size: 0.72em;
1204
+ line-height: 1.1;
1205
+ }
1206
+ `.trim();
1207
+ function buildUndersetNodeBody(node, buildChain) {
1208
+ const wrap = document.createElement("span");
1209
+ wrap.className = "underset";
1210
+ const base = document.createElement("span");
1211
+ base.className = "underset-base";
1212
+ if (node.baseExpr) {
1213
+ base.appendChild(buildChain(node.baseExpr));
1214
+ }
1215
+ const under = document.createElement("span");
1216
+ under.className = "underset-under";
1217
+ if (node.underExpr) {
1218
+ under.appendChild(buildChain(node.underExpr));
1219
+ }
1220
+ wrap.appendChild(base);
1221
+ wrap.appendChild(under);
1222
+ return wrap;
1223
+ }
1224
+
1225
+ // src/editor/accentCommands.ts
1226
+ var ACCENT_COMMANDS = {
1227
+ vec: {
1228
+ id: "vec",
1229
+ englishTex: "\\vec",
1230
+ arabicTex: "\\arabvec",
1231
+ placement: "over",
1232
+ label: "\u20D7",
1233
+ title: "\u0633\u0647\u0645 \u0641\u0648\u0642"
1234
+ },
1235
+ hat: {
1236
+ id: "hat",
1237
+ englishTex: "\\hat",
1238
+ arabicTex: "\\hat",
1239
+ placement: "over",
1240
+ label: "\u02C6",
1241
+ title: "\u0642\u0628\u0639\u0629"
1242
+ },
1243
+ tilde: {
1244
+ id: "tilde",
1245
+ englishTex: "\\tilde",
1246
+ arabicTex: "\\tilde",
1247
+ placement: "over",
1248
+ label: "\u02DC",
1249
+ title: "\u0645\u062F\u0629"
1250
+ },
1251
+ dot: {
1252
+ id: "dot",
1253
+ englishTex: "\\dot",
1254
+ arabicTex: "\\dot",
1255
+ placement: "over",
1256
+ label: "\u02D9",
1257
+ title: "\u0646\u0642\u0637\u0629 \u0641\u0648\u0642"
1258
+ },
1259
+ ddot: {
1260
+ id: "ddot",
1261
+ englishTex: "\\ddot",
1262
+ arabicTex: "\\ddot",
1263
+ placement: "over",
1264
+ label: "\xA8",
1265
+ title: "\u0646\u0642\u0637\u062A\u0627\u0646 \u0641\u0648\u0642"
1266
+ },
1267
+ dddot: {
1268
+ id: "dddot",
1269
+ englishTex: "\\dddot",
1270
+ arabicTex: "\\dddot",
1271
+ placement: "over",
1272
+ label: "\u20DB",
1273
+ title: "\u062B\u0644\u0627\u062B \u0646\u0642\u0627\u0637 \u0641\u0648\u0642"
1274
+ },
1275
+ bar: {
1276
+ id: "bar",
1277
+ englishTex: "\\bar",
1278
+ arabicTex: "\\bar",
1279
+ placement: "over",
1280
+ label: "\xAF",
1281
+ title: "\u062E\u0637 \u0641\u0648\u0642"
1282
+ },
1283
+ check: {
1284
+ id: "check",
1285
+ englishTex: "\\check",
1286
+ arabicTex: "\\check",
1287
+ placement: "over",
1288
+ label: "\u02C7",
1289
+ title: "\u0639\u0644\u0627\u0645\u0629 \u062A\u062D\u0642\u0642"
1290
+ },
1291
+ breve: {
1292
+ id: "breve",
1293
+ englishTex: "\\breve",
1294
+ arabicTex: "\\breve",
1295
+ placement: "over",
1296
+ label: "\u02D8",
1297
+ title: "\u0642\u0648\u0633 \u0642\u0635\u064A\u0631"
1298
+ },
1299
+ acute: {
1300
+ id: "acute",
1301
+ englishTex: "\\acute",
1302
+ arabicTex: "\\grave",
1303
+ placement: "over",
1304
+ label: "\xB4",
1305
+ title: "\u0646\u0628\u0631\u0629 \u062D\u0627\u062F\u0629"
1306
+ },
1307
+ grave: {
1308
+ id: "grave",
1309
+ englishTex: "\\grave",
1310
+ arabicTex: "\\acute",
1311
+ placement: "over",
1312
+ label: "`",
1313
+ title: "\u0646\u0628\u0631\u0629 \u062B\u0642\u064A\u0644\u0629"
1314
+ },
1315
+ overline: {
1316
+ id: "overline",
1317
+ englishTex: "\\overline",
1318
+ arabicTex: "\\overline",
1319
+ placement: "over",
1320
+ label: "\u203E",
1321
+ title: "\u062E\u0637 \u0639\u0644\u0648\u064A \u0645\u0645\u062A\u062F"
1322
+ },
1323
+ underline: {
1324
+ id: "underline",
1325
+ englishTex: "\\underline",
1326
+ arabicTex: "\\underline",
1327
+ placement: "under",
1328
+ label: "_",
1329
+ title: "\u062E\u0637 \u0633\u0641\u0644\u064A"
1330
+ },
1331
+ overleftarrow: {
1332
+ id: "overleftarrow",
1333
+ englishTex: "\\overleftarrow",
1334
+ arabicTex: "\\overrightarrow",
1335
+ placement: "over",
1336
+ label: "\u2190",
1337
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631"
1338
+ },
1339
+ overrightarrow: {
1340
+ id: "overrightarrow",
1341
+ englishTex: "\\overrightarrow",
1342
+ arabicTex: "\\overleftarrow",
1343
+ placement: "over",
1344
+ label: "\u2192",
1345
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646"
1346
+ },
1347
+ overleftrightarrow: {
1348
+ id: "overleftrightarrow",
1349
+ englishTex: "\\overleftrightarrow",
1350
+ arabicTex: "\\overleftrightarrow",
1351
+ placement: "over",
1352
+ label: "\u2194",
1353
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0645\u0632\u062F\u0648\u062C \u0627\u0644\u0627\u062A\u062C\u0627\u0647"
1354
+ }
1355
+ };
1356
+ function accentCommandSpec(id) {
1357
+ return Object.prototype.hasOwnProperty.call(ACCENT_COMMANDS, id) ? ACCENT_COMMANDS[id] : null;
1358
+ }
1359
+ function accentCommandsList() {
1360
+ return Object.values(ACCENT_COMMANDS);
1361
+ }
1362
+ function accentCommandIdFromTex(tex) {
1363
+ const normalized = tex.startsWith("\\") ? tex : `\\${tex}`;
1364
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1365
+ if (spec.englishTex === normalized) {
1366
+ return spec.id;
1367
+ }
1368
+ }
1369
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1370
+ if (spec.arabicTex === normalized) {
1371
+ return spec.id;
1372
+ }
1373
+ }
1374
+ return null;
1375
+ }
1376
+
1377
+ // src/editor/display/accent.ts
1378
+ var ACCENT_CSS = `
1379
+ .math-accent {
1380
+ display: inline-flex;
1381
+ flex-direction: column;
1382
+ align-items: center;
1383
+ justify-content: center;
1384
+ vertical-align: middle;
1385
+ margin: 0 2px;
1386
+ min-width: 1.1em;
1387
+ }
1388
+
1389
+ .math-accent-chrome {
1390
+ display: inline-flex;
1391
+ justify-content: center;
1392
+ align-items: center;
1393
+ min-height: 0.7em;
1394
+ padding: 0 2px;
1395
+ font-size: 0.85em;
1396
+ line-height: 1;
1397
+ color: var(--butex-script-color, #475569);
1398
+ user-select: none;
1399
+ }
1400
+
1401
+ .math-accent-base {
1402
+ display: inline-flex;
1403
+ justify-content: center;
1404
+ align-items: center;
1405
+ min-height: 1.05em;
1406
+ padding: 0 2px;
1407
+ }
1408
+
1409
+ .math-accent--under .math-accent-chrome {
1410
+ min-height: 0.45em;
1411
+ border-top: 1.5px solid currentColor;
1412
+ width: 100%;
1413
+ font-size: 0;
1414
+ color: var(--butex-surface-fg, #0f172a);
1415
+ }
1416
+ `.trim();
1417
+ function buildAccentNodeBody(node, buildChain) {
1418
+ const wrap = document.createElement("span");
1419
+ const spec = accentCommandSpec(node.expr);
1420
+ const placement = spec?.placement ?? "over";
1421
+ wrap.className = placement === "under" ? "math-accent math-accent--under" : "math-accent math-accent--over";
1422
+ const chrome = document.createElement("span");
1423
+ chrome.className = "math-accent-chrome";
1424
+ chrome.setAttribute("aria-hidden", "true");
1425
+ if (placement === "over") {
1426
+ chrome.textContent = spec?.label ?? "\u02C6";
1427
+ }
1428
+ const base = document.createElement("span");
1429
+ base.className = "math-accent-base";
1430
+ if (node.baseExpr) {
1431
+ base.appendChild(buildChain(node.baseExpr));
1432
+ }
1433
+ if (placement === "under") {
1434
+ wrap.appendChild(base);
1435
+ wrap.appendChild(chrome);
1436
+ } else {
1437
+ wrap.appendChild(chrome);
1438
+ wrap.appendChild(base);
1439
+ }
1440
+ return wrap;
1441
+ }
1442
+
1122
1443
  // src/editor/display/env.ts
1123
1444
  var WRAPPERS = {
1124
1445
  matrix: { left: "", right: "" },
@@ -1344,6 +1665,10 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1344
1665
  insertBraces: "\u0625\u062F\u0631\u0627\u062C \u062D\u0627\u0635\u0631\u062A\u064A\u0646",
1345
1666
  insertFraction: "\u0625\u062F\u0631\u0627\u062C \u0643\u0633\u0631",
1346
1667
  insertRoot: "\u0625\u062F\u0631\u0627\u062C \u062C\u0630\u0631",
1668
+ insertOverset: "\u0625\u062F\u0631\u0627\u062C \u0641\u0648\u0642",
1669
+ insertUnderset: "\u0625\u062F\u0631\u0627\u062C \u062A\u062D\u062A",
1670
+ insertAccentPair: "\u0625\u062F\u0631\u0627\u062C \u0641\u0648\u0642 \u0648\u062A\u062D\u062A",
1671
+ insertAccents: "\u0625\u062F\u0631\u0627\u062C \u0644\u0643\u0646\u0629",
1347
1672
  environments: "\u0627\u0644\u0628\u064A\u0626\u0627\u062A",
1348
1673
  insertEnvironment: "\u0625\u062F\u0631\u0627\u062C \u0628\u064A\u0626\u0629 \u0634\u0628\u0643\u064A\u0629",
1349
1674
  environmentType: "\u0646\u0648\u0639 \u0627\u0644\u0628\u064A\u0626\u0629",
@@ -1451,6 +1776,10 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1451
1776
  insertBraces: "Insert braces",
1452
1777
  insertFraction: "Insert fraction",
1453
1778
  insertRoot: "Insert root",
1779
+ insertOverset: "Insert overset",
1780
+ insertUnderset: "Insert underset",
1781
+ insertAccentPair: "Insert overset and underset",
1782
+ insertAccents: "Insert accent",
1454
1783
  environments: "Environments",
1455
1784
  insertEnvironment: "Insert grid environment",
1456
1785
  environmentType: "Environment type",
@@ -1718,7 +2047,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1718
2047
  id: "neq",
1719
2048
  category: "operators1",
1720
2049
  Tex: "\\neq",
1721
- mirror: false,
2050
+ mirror: true,
1722
2051
  Label: "\u2260",
1723
2052
  title: "\u0644\u0627 \u064A\u0633\u0627\u0648\u064A",
1724
2053
  svg_path: null
@@ -1728,6 +2057,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1728
2057
  category: "operators1",
1729
2058
  Tex: "\\approx",
1730
2059
  mirror: false,
2060
+ displayMirror: true,
1731
2061
  Label: "\u2248",
1732
2062
  title: "\u062A\u0642\u0631\u064A\u0628\u0627 \u064A\u0633\u0627\u0648\u064A",
1733
2063
  svg_path: null
@@ -1737,6 +2067,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1737
2067
  category: "operators1",
1738
2068
  Tex: "\\sim",
1739
2069
  mirror: false,
2070
+ displayMirror: true,
1740
2071
  Label: "\u223C",
1741
2072
  title: "\u0645\u0634\u0627\u0628\u0647",
1742
2073
  svg_path: null
@@ -1755,6 +2086,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1755
2086
  category: "operators1",
1756
2087
  Tex: "\\leq",
1757
2088
  mirror: true,
2089
+ displayMirror: false,
1758
2090
  Label: "\u2264",
1759
2091
  title: "\u0623\u0635\u063A\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
1760
2092
  svg_path: null
@@ -1764,6 +2096,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1764
2096
  category: "operators1",
1765
2097
  Tex: "\\geq",
1766
2098
  mirror: true,
2099
+ displayMirror: false,
1767
2100
  Label: "\u2265",
1768
2101
  title: "\u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
1769
2102
  svg_path: null
@@ -1773,6 +2106,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1773
2106
  category: "operators1",
1774
2107
  Tex: "\\coloneqq",
1775
2108
  mirror: true,
2109
+ displayMirror: false,
1776
2110
  Label: "\u2254",
1777
2111
  title: "\u064A\u0639\u0631\u0641 \u0628\u0623\u0646\u0647 \u064A\u0633\u0627\u0648\u064A",
1778
2112
  svg_path: null
@@ -1782,6 +2116,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1782
2116
  category: "operators1",
1783
2117
  Tex: "\\eqqcolon",
1784
2118
  mirror: true,
2119
+ displayMirror: false,
1785
2120
  Label: "\u2255",
1786
2121
  title: "\u064A\u0633\u0627\u0648\u064A \u0628\u0627\u0644\u062A\u0639\u0631\u064A\u0641",
1787
2122
  svg_path: null
@@ -1792,6 +2127,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1792
2127
  category: "operators2",
1793
2128
  Tex: "\\propto",
1794
2129
  mirror: true,
2130
+ displayMirror: false,
1795
2131
  Label: "\u221D",
1796
2132
  title: "\u064A\u062A\u0646\u0627\u0633\u0628 \u0645\u0639",
1797
2133
  svg_path: null
@@ -1801,6 +2137,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1801
2137
  category: "operators2",
1802
2138
  Tex: "\\in",
1803
2139
  mirror: true,
2140
+ displayMirror: false,
1804
2141
  Label: "\u2208",
1805
2142
  title: "\u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
1806
2143
  svg_path: null
@@ -1810,6 +2147,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1810
2147
  category: "operators2",
1811
2148
  Tex: "\\notin",
1812
2149
  mirror: false,
2150
+ displayMirror: true,
1813
2151
  Label: "\u2209",
1814
2152
  title: "\u0644\u0627 \u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
1815
2153
  svg_path: null
@@ -1819,6 +2157,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1819
2157
  category: "operators2",
1820
2158
  Tex: "\\subset",
1821
2159
  mirror: true,
2160
+ displayMirror: false,
1822
2161
  Label: "\u2282",
1823
2162
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0645\u0646",
1824
2163
  svg_path: null
@@ -1828,6 +2167,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1828
2167
  category: "operators2",
1829
2168
  Tex: "\\supset",
1830
2169
  mirror: true,
2170
+ displayMirror: false,
1831
2171
  Label: "\u2283",
1832
2172
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0644\u0640",
1833
2173
  svg_path: null
@@ -1837,6 +2177,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1837
2177
  category: "operators2",
1838
2178
  Tex: "\\subseteq",
1839
2179
  mirror: true,
2180
+ displayMirror: false,
1840
2181
  Label: "\u2286",
1841
2182
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1842
2183
  svg_path: null
@@ -1846,6 +2187,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1846
2187
  category: "operators2",
1847
2188
  Tex: "\\supseteq",
1848
2189
  mirror: true,
2190
+ displayMirror: false,
1849
2191
  Label: "\u2287",
1850
2192
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1851
2193
  svg_path: null
@@ -1855,6 +2197,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1855
2197
  category: "operators2",
1856
2198
  Tex: "\\cap",
1857
2199
  mirror: false,
2200
+ displayMirror: true,
1858
2201
  Label: "\u2229",
1859
2202
  title: "\u062A\u0642\u0627\u0637\u0639",
1860
2203
  svg_path: null
@@ -1864,6 +2207,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1864
2207
  category: "operators2",
1865
2208
  Tex: "\\cup",
1866
2209
  mirror: false,
2210
+ displayMirror: true,
1867
2211
  Label: "\u222A",
1868
2212
  title: "\u0627\u062A\u062D\u0627\u062F",
1869
2213
  svg_path: null
@@ -1873,6 +2217,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1873
2217
  category: "operators2",
1874
2218
  Tex: "\\emptyset",
1875
2219
  mirror: false,
2220
+ displayMirror: true,
1876
2221
  Label: "\u2205",
1877
2222
  title: "\u0627\u0644\u0645\u062C\u0645\u0648\u0639\u0629 \u0627\u0644\u062E\u0627\u0644\u064A\u0629",
1878
2223
  svg_path: null
@@ -1882,6 +2227,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1882
2227
  category: "operators2",
1883
2228
  Tex: "\\nsubseteq",
1884
2229
  mirror: true,
2230
+ displayMirror: false,
1885
2231
  Label: "\u2288",
1886
2232
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1887
2233
  svg_path: null
@@ -1891,6 +2237,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
1891
2237
  category: "operators2",
1892
2238
  Tex: "\\nsupseteq",
1893
2239
  mirror: true,
2240
+ displayMirror: false,
1894
2241
  Label: "\u2289",
1895
2242
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
1896
2243
  svg_path: null
@@ -2102,6 +2449,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2102
2449
  category: "integrals",
2103
2450
  Tex: "\\iint",
2104
2451
  mirror: true,
2452
+ displayMirror: false,
2105
2453
  Label: "\u222C",
2106
2454
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u0632\u062F\u0648\u062C",
2107
2455
  svg_path: null
@@ -2111,6 +2459,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2111
2459
  category: "integrals",
2112
2460
  Tex: "\\iiint",
2113
2461
  mirror: true,
2462
+ displayMirror: false,
2114
2463
  Label: "\u222D",
2115
2464
  title: "\u062A\u0643\u0627\u0645\u0644 \u062B\u0644\u0627\u062B\u064A",
2116
2465
  svg_path: null
@@ -2120,6 +2469,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2120
2469
  category: "integrals",
2121
2470
  Tex: "\\iiiint",
2122
2471
  mirror: true,
2472
+ displayMirror: false,
2123
2473
  Label: "\u2A0C",
2124
2474
  title: "\u062A\u0643\u0627\u0645\u0644 \u0631\u0628\u0627\u0639\u064A",
2125
2475
  svg_path: null
@@ -2129,6 +2479,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2129
2479
  category: "integrals",
2130
2480
  Tex: "\\oint",
2131
2481
  mirror: true,
2482
+ displayMirror: false,
2132
2483
  Label: "\u222E",
2133
2484
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u063A\u0644\u0642",
2134
2485
  svg_path: null
@@ -2138,6 +2489,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2138
2489
  category: "integrals",
2139
2490
  Tex: "\\oiint",
2140
2491
  mirror: true,
2492
+ displayMirror: false,
2141
2493
  Label: "\u222F",
2142
2494
  title: "\u062A\u0643\u0627\u0645\u0644 \u0633\u0637\u062D\u064A \u0645\u063A\u0644\u0642",
2143
2495
  svg_path: null
@@ -2147,6 +2499,7 @@ mjx-container[jax="SVG"] svg .butex-preview-mirror {
2147
2499
  category: "integrals",
2148
2500
  Tex: "\\oiiint",
2149
2501
  mirror: true,
2502
+ displayMirror: false,
2150
2503
  Label: "\u2230",
2151
2504
  title: "\u062A\u0643\u0627\u0645\u0644 \u062D\u062C\u0645\u064A \u0645\u063A\u0644\u0642",
2152
2505
  svg_path: null
@@ -2463,6 +2816,12 @@ ${FRAC_CSS}
2463
2816
 
2464
2817
  ${SQRT_CSS}
2465
2818
 
2819
+ ${OVERSET_CSS}
2820
+
2821
+ ${UNDERSET_CSS}
2822
+
2823
+ ${ACCENT_CSS}
2824
+
2466
2825
  ${MATRIX_ENV_CSS}
2467
2826
 
2468
2827
  ${ATOMIC_COMMAND_CSS}
@@ -2489,6 +2848,8 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2489
2848
  // src/editor/index.ts
2490
2849
  var editor_exports = {};
2491
2850
  __export(editor_exports, {
2851
+ ACCENT_COMMANDS: () => ACCENT_COMMANDS,
2852
+ ACCENT_CSS: () => ACCENT_CSS,
2492
2853
  ATOMIC_COMMANDS: () => ATOMIC_COMMANDS,
2493
2854
  ATOMIC_COMMAND_CSS: () => ATOMIC_COMMAND_CSS,
2494
2855
  ATOMIC_OPERATOR_COMMANDS: () => ATOMIC_OPERATOR_COMMANDS,
@@ -2499,7 +2860,12 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2499
2860
  DELIMITER_CSS: () => DELIMITER_CSS,
2500
2861
  FRAC_CSS: () => FRAC_CSS,
2501
2862
  MATRIX_ENV_CSS: () => MATRIX_ENV_CSS,
2863
+ OVERSET_CSS: () => OVERSET_CSS,
2502
2864
  SQRT_CSS: () => SQRT_CSS,
2865
+ UNDERSET_CSS: () => UNDERSET_CSS,
2866
+ accentCommandIdFromTex: () => accentCommandIdFromTex,
2867
+ accentCommandSpec: () => accentCommandSpec,
2868
+ accentCommandsList: () => accentCommandsList,
2503
2869
  activeSideLabel: () => activeSideLabel,
2504
2870
  activeTreeKey: () => activeTreeKey,
2505
2871
  addMatrixColumn: () => addMatrixColumn,
@@ -2520,6 +2886,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2520
2886
  collectCaretPositions: () => collectCaretPositions,
2521
2887
  copySelection: () => copySelection,
2522
2888
  coveredNodeIds: () => coveredNodeIds,
2889
+ createAccentNode: () => createAccentNode,
2523
2890
  createAtomicCommandNode: () => createAtomicCommandNode,
2524
2891
  createAtomicOperatorCommandNode: () => createAtomicOperatorCommandNode,
2525
2892
  createDelimiterNode: () => createDelimiterNode,
@@ -2530,8 +2897,10 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2530
2897
  createFracNode: () => createFracNode,
2531
2898
  createGridEnvNode: () => createGridEnvNode,
2532
2899
  createMatrixEnvNode: () => createMatrixEnvNode,
2900
+ createOversetNode: () => createOversetNode,
2533
2901
  createSqrtNode: () => createSqrtNode,
2534
2902
  createStarterSession: () => createStarterSession,
2903
+ createUndersetNode: () => createUndersetNode,
2535
2904
  createUndoRedoStacks: () => createUndoRedoStacks,
2536
2905
  cutSelection: () => cutSelection,
2537
2906
  deleteBackward: () => deleteBackward,
@@ -2545,6 +2914,8 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2545
2914
  fragmentToPlainText: () => fragmentToPlainText,
2546
2915
  horizontalCaretDelta: () => horizontalCaretDelta,
2547
2916
  injectBuTeXEditorStyles: () => injectBuTeXEditorStyles,
2917
+ insertAccent: () => insertAccent,
2918
+ insertAccentPair: () => insertAccentPair,
2548
2919
  insertAlignedEnv: () => insertAlignedEnv,
2549
2920
  insertArrayEnv: () => insertArrayEnv,
2550
2921
  insertAtomicCommand: () => insertAtomicCommand,
@@ -2554,11 +2925,14 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2554
2925
  insertDivideOperator: () => insertDivideOperator,
2555
2926
  insertFirstDerivative: () => insertFirstDerivative,
2556
2927
  insertFraction: () => insertFraction,
2928
+ insertLimitsSeriesTemplate: () => insertLimitsSeriesTemplate,
2557
2929
  insertMatrixEnv: () => insertMatrixEnv,
2558
2930
  insertNumber: () => insertNumber,
2559
2931
  insertOperator: () => insertOperator,
2932
+ insertOverset: () => insertOverset,
2560
2933
  insertSecondDerivative: () => insertSecondDerivative,
2561
2934
  insertSqrt: () => insertSqrt,
2935
+ insertUnderset: () => insertUnderset,
2562
2936
  isSelectionActive: () => isSelectionActive,
2563
2937
  isSpacingCommandSpec: () => isSpacingCommandSpec,
2564
2938
  mirrorBuTeXOperatorsInTex: () => mirrorBuTeXOperatorsInTex,
@@ -2632,6 +3006,9 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2632
3006
  denominator: null,
2633
3007
  radicand: null,
2634
3008
  rootIndex: null,
3009
+ overExpr: null,
3010
+ underExpr: null,
3011
+ baseExpr: null,
2635
3012
  envName: null,
2636
3013
  matrixStyle: null,
2637
3014
  matrixRows: null,
@@ -2660,6 +3037,26 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2660
3037
  rootIndex: createEditorChain()
2661
3038
  };
2662
3039
  }
3040
+ function createOversetNode() {
3041
+ return {
3042
+ ...createEditorNode("overset", ""),
3043
+ overExpr: createEditorChain(),
3044
+ baseExpr: createEditorChain()
3045
+ };
3046
+ }
3047
+ function createUndersetNode() {
3048
+ return {
3049
+ ...createEditorNode("underset", ""),
3050
+ underExpr: createEditorChain(),
3051
+ baseExpr: createEditorChain()
3052
+ };
3053
+ }
3054
+ function createAccentNode(accentId) {
3055
+ return {
3056
+ ...createEditorNode("accent", accentId),
3057
+ baseExpr: createEditorChain()
3058
+ };
3059
+ }
2663
3060
  function createMatrixEnvNode(style, rows, columns) {
2664
3061
  return createGridEnvNode(style, rows, columns);
2665
3062
  }
@@ -2727,6 +3124,15 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2727
3124
  if (node.radicand) {
2728
3125
  collectNodeIds(node.radicand, ids);
2729
3126
  }
3127
+ if (node.overExpr) {
3128
+ collectNodeIds(node.overExpr, ids);
3129
+ }
3130
+ if (node.underExpr) {
3131
+ collectNodeIds(node.underExpr, ids);
3132
+ }
3133
+ if (node.baseExpr) {
3134
+ collectNodeIds(node.baseExpr, ids);
3135
+ }
2730
3136
  if (node.matrixRows) {
2731
3137
  for (const row of node.matrixRows) {
2732
3138
  for (const cell of row) {
@@ -2891,6 +3297,22 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2891
3297
  }
2892
3298
  return `\\begin{${envName}}${rows.join(" \\\\\n")}\\end{${envName}}`;
2893
3299
  }
3300
+ function renderAccentEnglish(command, accent, base, options) {
3301
+ const baseTex = base ? renderChainEnglish(base, options) : "";
3302
+ const accentTex = accent ? renderChainEnglish(accent, options) : "";
3303
+ if (accentTex === "") {
3304
+ return baseTex;
3305
+ }
3306
+ return `\\${command}{${accentTex}}{${baseTex}}`;
3307
+ }
3308
+ function renderAccentArabic(command, accent, base, options) {
3309
+ const baseTex = base ? renderChainArabic(base, options) : "";
3310
+ const accentTex = accent ? renderChainArabic(accent, options) : "";
3311
+ if (accentTex === "") {
3312
+ return baseTex;
3313
+ }
3314
+ return `\\${command}{${accentTex}}{${baseTex}}`;
3315
+ }
2894
3316
  function escapeText(s) {
2895
3317
  return s.replace(/\\/g, "\\textbackslash{}").replace(/[{}]/g, "\\$&");
2896
3318
  }
@@ -2920,6 +3342,19 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2920
3342
  const body = `\\sqrt${optionalRootIndexEnglish(node, options)}{${renderChainEnglish(node.radicand, options)}}`;
2921
3343
  return `${body}${latinScripts(node, options)}`;
2922
3344
  }
3345
+ if (node.kind === "overset" && node.baseExpr) {
3346
+ const body = renderAccentEnglish("overset", node.overExpr, node.baseExpr, options);
3347
+ return `${body}${latinScripts(node, options)}`;
3348
+ }
3349
+ if (node.kind === "underset" && node.baseExpr) {
3350
+ const body = renderAccentEnglish("underset", node.underExpr, node.baseExpr, options);
3351
+ return `${body}${latinScripts(node, options)}`;
3352
+ }
3353
+ if (node.kind === "accent" && node.baseExpr) {
3354
+ const cmd = accentCommandSpec(node.expr)?.englishTex ?? `\\${node.expr}`;
3355
+ const body = `${cmd}{${renderChainEnglish(node.baseExpr, options)}}`;
3356
+ return `${body}${latinScripts(node, options)}`;
3357
+ }
2923
3358
  if (node.kind === "env") {
2924
3359
  return `${renderMatrixRowsEnglish(node, options)}${latinScripts(node, options)}`;
2925
3360
  }
@@ -2952,6 +3387,19 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2952
3387
  const content = `\\arabsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
2953
3388
  return arabicScripts(node, content, options);
2954
3389
  }
3390
+ if (node.kind === "overset" && node.baseExpr) {
3391
+ const content = renderAccentArabic("overset", node.overExpr, node.baseExpr, options);
3392
+ return arabicScripts(node, content, options);
3393
+ }
3394
+ if (node.kind === "underset" && node.baseExpr) {
3395
+ const content = renderAccentArabic("underset", node.underExpr, node.baseExpr, options);
3396
+ return arabicScripts(node, content, options);
3397
+ }
3398
+ if (node.kind === "accent" && node.baseExpr) {
3399
+ const cmd = accentCommandSpec(node.expr)?.arabicTex ?? `\\${node.expr}`;
3400
+ const content = `${cmd}{${renderChainArabic(node.baseExpr, options)}}`;
3401
+ return arabicScripts(node, content, options);
3402
+ }
2955
3403
  if (node.kind === "env") {
2956
3404
  return arabicScripts(node, renderMatrixRowsArabic(node, options), options);
2957
3405
  }
@@ -3008,6 +3456,35 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3008
3456
  if (node.radicand) {
3009
3457
  walkChain(node.radicand);
3010
3458
  }
3459
+ if (node.kind === "overset") {
3460
+ if (node.overExpr) {
3461
+ walkChain(node.overExpr);
3462
+ }
3463
+ if (node.baseExpr) {
3464
+ walkChain(node.baseExpr);
3465
+ }
3466
+ } else if (node.kind === "underset") {
3467
+ if (node.baseExpr) {
3468
+ walkChain(node.baseExpr);
3469
+ }
3470
+ if (node.underExpr) {
3471
+ walkChain(node.underExpr);
3472
+ }
3473
+ } else if (node.kind === "accent") {
3474
+ if (node.baseExpr) {
3475
+ walkChain(node.baseExpr);
3476
+ }
3477
+ } else {
3478
+ if (node.overExpr) {
3479
+ walkChain(node.overExpr);
3480
+ }
3481
+ if (node.underExpr) {
3482
+ walkChain(node.underExpr);
3483
+ }
3484
+ if (node.baseExpr) {
3485
+ walkChain(node.baseExpr);
3486
+ }
3487
+ }
3011
3488
  if (node.matrixRows) {
3012
3489
  for (const row of node.matrixRows) {
3013
3490
  for (const cell of row) {
@@ -3141,6 +3618,42 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3141
3618
  return nested;
3142
3619
  }
3143
3620
  }
3621
+ if (node.overExpr) {
3622
+ if (node.overExpr.id === chainId) {
3623
+ return {
3624
+ chain: node.overExpr,
3625
+ relation: { kind: "overExpr", ownerNodeId: node.id, ownerChainId: root.id }
3626
+ };
3627
+ }
3628
+ const nested = findChainById(node.overExpr, chainId);
3629
+ if (nested) {
3630
+ return nested;
3631
+ }
3632
+ }
3633
+ if (node.underExpr) {
3634
+ if (node.underExpr.id === chainId) {
3635
+ return {
3636
+ chain: node.underExpr,
3637
+ relation: { kind: "underExpr", ownerNodeId: node.id, ownerChainId: root.id }
3638
+ };
3639
+ }
3640
+ const nested = findChainById(node.underExpr, chainId);
3641
+ if (nested) {
3642
+ return nested;
3643
+ }
3644
+ }
3645
+ if (node.baseExpr) {
3646
+ if (node.baseExpr.id === chainId) {
3647
+ return {
3648
+ chain: node.baseExpr,
3649
+ relation: { kind: "baseExpr", ownerNodeId: node.id, ownerChainId: root.id }
3650
+ };
3651
+ }
3652
+ const nested = findChainById(node.baseExpr, chainId);
3653
+ if (nested) {
3654
+ return nested;
3655
+ }
3656
+ }
3144
3657
  if (node.matrixRows) {
3145
3658
  for (let rowIndex = 0; rowIndex < node.matrixRows.length; rowIndex += 1) {
3146
3659
  const row = node.matrixRows[rowIndex];
@@ -3214,6 +3727,24 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3214
3727
  return nested;
3215
3728
  }
3216
3729
  }
3730
+ if (node.overExpr) {
3731
+ const nested = findNodeById(node.overExpr, nodeId);
3732
+ if (nested) {
3733
+ return nested;
3734
+ }
3735
+ }
3736
+ if (node.underExpr) {
3737
+ const nested = findNodeById(node.underExpr, nodeId);
3738
+ if (nested) {
3739
+ return nested;
3740
+ }
3741
+ }
3742
+ if (node.baseExpr) {
3743
+ const nested = findNodeById(node.baseExpr, nodeId);
3744
+ if (nested) {
3745
+ return nested;
3746
+ }
3747
+ }
3217
3748
  if (node.matrixRows) {
3218
3749
  for (const row of node.matrixRows) {
3219
3750
  for (const cell of row) {
@@ -3252,6 +3783,15 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3252
3783
  if (node.radicand) {
3253
3784
  chains.push(node.radicand);
3254
3785
  }
3786
+ if (node.overExpr) {
3787
+ chains.push(node.overExpr);
3788
+ }
3789
+ if (node.underExpr) {
3790
+ chains.push(node.underExpr);
3791
+ }
3792
+ if (node.baseExpr) {
3793
+ chains.push(node.baseExpr);
3794
+ }
3255
3795
  if (node.matrixRows) {
3256
3796
  for (const row of node.matrixRows) {
3257
3797
  chains.push(...row);
@@ -3622,6 +4162,91 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3622
4162
  };
3623
4163
  }
3624
4164
 
4165
+ // src/editor/limitsTemplates.ts
4166
+ var LIMITS_SERIES_TEMPLATE_IDS = /* @__PURE__ */ new Set([
4167
+ "sum",
4168
+ "prod",
4169
+ "lim",
4170
+ "max",
4171
+ "min",
4172
+ "sup",
4173
+ "inf"
4174
+ ]);
4175
+ function isLimitsSeriesTemplateId(commandId) {
4176
+ return LIMITS_SERIES_TEMPLATE_IDS.has(commandId);
4177
+ }
4178
+ function syncChainIds2(english, arabic) {
4179
+ arabic.id = english.id;
4180
+ const limit = Math.min(english.nodes.length, arabic.nodes.length);
4181
+ for (let index = 0; index < limit; index += 1) {
4182
+ arabic.nodes[index].id = english.nodes[index].id;
4183
+ }
4184
+ }
4185
+ function syncOversetIds(english, arabic) {
4186
+ arabic.id = english.id;
4187
+ if (english.overExpr && arabic.overExpr) {
4188
+ syncChainIds2(english.overExpr, arabic.overExpr);
4189
+ }
4190
+ if (english.baseExpr && arabic.baseExpr) {
4191
+ syncChainIds2(english.baseExpr, arabic.baseExpr);
4192
+ }
4193
+ }
4194
+ function syncUndersetIds(english, arabic) {
4195
+ arabic.id = english.id;
4196
+ if (english.underExpr && arabic.underExpr) {
4197
+ syncChainIds2(english.underExpr, arabic.underExpr);
4198
+ }
4199
+ if (english.baseExpr && arabic.baseExpr) {
4200
+ syncChainIds2(english.baseExpr, arabic.baseExpr);
4201
+ }
4202
+ }
4203
+ function buildLimitsSeriesTemplate(commandId) {
4204
+ if (!isLimitsSeriesTemplateId(commandId)) {
4205
+ throw new Error(`BuTeX: unsupported limits-series template id: ${commandId}`);
4206
+ }
4207
+ const englishOp = createAtomicCommandNode(commandId);
4208
+ const arabicOp = createAtomicCommandNode(commandId);
4209
+ arabicOp.id = englishOp.id;
4210
+ const englishOverset = createOversetNode();
4211
+ const arabicOverset = createOversetNode();
4212
+ syncOversetIds(englishOverset, arabicOverset);
4213
+ englishOverset.baseExpr = createEditorChain([englishOp]);
4214
+ arabicOverset.baseExpr = createEditorChain([arabicOp]);
4215
+ syncChainIds2(englishOverset.baseExpr, arabicOverset.baseExpr);
4216
+ const englishUnderset = createUndersetNode();
4217
+ const arabicUnderset = createUndersetNode();
4218
+ syncUndersetIds(englishUnderset, arabicUnderset);
4219
+ englishUnderset.baseExpr = createEditorChain([englishOverset]);
4220
+ arabicUnderset.baseExpr = createEditorChain([arabicOverset]);
4221
+ syncChainIds2(englishUnderset.baseExpr, arabicUnderset.baseExpr);
4222
+ return { english: englishUnderset, arabic: arabicUnderset };
4223
+ }
4224
+ function buildAccentPairTemplate() {
4225
+ const englishOverset = createOversetNode();
4226
+ const arabicOverset = createOversetNode();
4227
+ syncOversetIds(englishOverset, arabicOverset);
4228
+ const englishUnderset = createUndersetNode();
4229
+ const arabicUnderset = createUndersetNode();
4230
+ syncUndersetIds(englishUnderset, arabicUnderset);
4231
+ englishUnderset.baseExpr = createEditorChain([englishOverset]);
4232
+ arabicUnderset.baseExpr = createEditorChain([arabicOverset]);
4233
+ syncChainIds2(englishUnderset.baseExpr, arabicUnderset.baseExpr);
4234
+ return { english: englishUnderset, arabic: arabicUnderset };
4235
+ }
4236
+ function accentPairTemplateInitialCaret(englishUnderset) {
4237
+ const overset = englishUnderset.baseExpr?.nodes[0];
4238
+ return {
4239
+ chainId: overset?.baseExpr?.id ?? englishUnderset.underExpr?.id ?? "",
4240
+ index: 0
4241
+ };
4242
+ }
4243
+ function limitsSeriesTemplateInitialCaret(englishUnderset) {
4244
+ return {
4245
+ chainId: englishUnderset.underExpr?.id ?? englishUnderset.baseExpr?.id ?? "",
4246
+ index: 0
4247
+ };
4248
+ }
4249
+
3625
4250
  // src/editor/state.ts
3626
4251
  function ensureSyncEntry(session, nodeId) {
3627
4252
  if (!session.sync[nodeId]) {
@@ -3655,7 +4280,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
3655
4280
  session.selectedNodeId = located.relation.ownerNodeId;
3656
4281
  return;
3657
4282
  }
3658
- 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") {
4283
+ 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") {
3659
4284
  session.selectedNodeId = located.relation.ownerNodeId;
3660
4285
  return;
3661
4286
  }
@@ -4012,6 +4637,106 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
4012
4637
  appendDebug(next, "moveCaretVertical", "sqrt-radicand-down-exit");
4013
4638
  return next;
4014
4639
  }
4640
+ if (located.relation.kind === "overExpr" && ownerLocated && ownerNode && ownerNode.baseExpr) {
4641
+ if (direction === "down") {
4642
+ next.caret = {
4643
+ chainId: ownerNode.baseExpr.id,
4644
+ index: ownerNode.baseExpr.nodes.length
4645
+ };
4646
+ next.selectedStructureNodeId = null;
4647
+ syncSelectionToCaret(next);
4648
+ appendDebug(next, "moveCaretVertical", "overset-over->base");
4649
+ return next;
4650
+ }
4651
+ next.caret = {
4652
+ chainId: ownerLocated.chain.id,
4653
+ index: ownerLocated.index
4654
+ };
4655
+ next.selectedStructureNodeId = null;
4656
+ syncSelectionToCaret(next);
4657
+ appendDebug(next, "moveCaretVertical", "overset-over-up-exit");
4658
+ return next;
4659
+ }
4660
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "overset" && ownerNode.overExpr) {
4661
+ if (direction === "up") {
4662
+ next.caret = {
4663
+ chainId: ownerNode.overExpr.id,
4664
+ index: ownerNode.overExpr.nodes.length
4665
+ };
4666
+ next.selectedStructureNodeId = null;
4667
+ syncSelectionToCaret(next);
4668
+ appendDebug(next, "moveCaretVertical", "overset-base->over");
4669
+ return next;
4670
+ }
4671
+ next.caret = {
4672
+ chainId: ownerLocated.chain.id,
4673
+ index: ownerLocated.index + 1
4674
+ };
4675
+ next.selectedStructureNodeId = null;
4676
+ syncSelectionToCaret(next);
4677
+ appendDebug(next, "moveCaretVertical", "overset-base-down-exit");
4678
+ return next;
4679
+ }
4680
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "underset" && ownerNode.underExpr) {
4681
+ if (direction === "down") {
4682
+ next.caret = {
4683
+ chainId: ownerNode.underExpr.id,
4684
+ index: ownerNode.underExpr.nodes.length
4685
+ };
4686
+ next.selectedStructureNodeId = null;
4687
+ syncSelectionToCaret(next);
4688
+ appendDebug(next, "moveCaretVertical", "underset-base->under");
4689
+ return next;
4690
+ }
4691
+ next.caret = {
4692
+ chainId: ownerLocated.chain.id,
4693
+ index: ownerLocated.index
4694
+ };
4695
+ next.selectedStructureNodeId = null;
4696
+ syncSelectionToCaret(next);
4697
+ appendDebug(next, "moveCaretVertical", "underset-base-up-exit");
4698
+ return next;
4699
+ }
4700
+ if (located.relation.kind === "underExpr" && ownerLocated && ownerNode && ownerNode.baseExpr) {
4701
+ if (direction === "up") {
4702
+ next.caret = {
4703
+ chainId: ownerNode.baseExpr.id,
4704
+ index: ownerNode.baseExpr.nodes.length
4705
+ };
4706
+ next.selectedStructureNodeId = null;
4707
+ syncSelectionToCaret(next);
4708
+ appendDebug(next, "moveCaretVertical", "underset-under->base");
4709
+ return next;
4710
+ }
4711
+ next.caret = {
4712
+ chainId: ownerLocated.chain.id,
4713
+ index: ownerLocated.index + 1
4714
+ };
4715
+ next.selectedStructureNodeId = null;
4716
+ syncSelectionToCaret(next);
4717
+ appendDebug(next, "moveCaretVertical", "underset-under-down-exit");
4718
+ return next;
4719
+ }
4720
+ if (located.relation.kind === "baseExpr" && ownerLocated && ownerNode && ownerNode.kind === "accent") {
4721
+ if (direction === "up") {
4722
+ next.caret = {
4723
+ chainId: ownerLocated.chain.id,
4724
+ index: ownerLocated.index
4725
+ };
4726
+ next.selectedStructureNodeId = null;
4727
+ syncSelectionToCaret(next);
4728
+ appendDebug(next, "moveCaretVertical", "accent-base-up-exit");
4729
+ return next;
4730
+ }
4731
+ next.caret = {
4732
+ chainId: ownerLocated.chain.id,
4733
+ index: ownerLocated.index + 1
4734
+ };
4735
+ next.selectedStructureNodeId = null;
4736
+ syncSelectionToCaret(next);
4737
+ appendDebug(next, "moveCaretVertical", "accent-base-down-exit");
4738
+ return next;
4739
+ }
4015
4740
  if (located.relation.kind === "matrixCell" && ownerLocated && ownerNode?.matrixRows) {
4016
4741
  const rowIndex = located.relation.rowIndex ?? 0;
4017
4742
  const columnIndex = located.relation.columnIndex ?? 0;
@@ -4389,6 +5114,119 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
4389
5114
  appendDebug(next, "insertSqrt", "");
4390
5115
  return next;
4391
5116
  }
5117
+ function insertOverset(session) {
5118
+ const base = replaceSelectionFirst(session);
5119
+ const next = cloneEditorSession(base);
5120
+ const englishNode = createOversetNode();
5121
+ const arabicNode = createOversetNode();
5122
+ arabicNode.id = englishNode.id;
5123
+ if (arabicNode.overExpr && englishNode.overExpr) {
5124
+ arabicNode.overExpr.id = englishNode.overExpr.id;
5125
+ }
5126
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5127
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5128
+ }
5129
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5130
+ next.caret = {
5131
+ chainId: englishNode.overExpr ? englishNode.overExpr.id : next.caret.chainId,
5132
+ index: 0
5133
+ };
5134
+ next.selectedStructureNodeId = null;
5135
+ syncSelectionToCaret(next);
5136
+ appendDebug(next, "insertOverset", "");
5137
+ return next;
5138
+ }
5139
+ function insertUnderset(session) {
5140
+ const base = replaceSelectionFirst(session);
5141
+ const next = cloneEditorSession(base);
5142
+ const englishNode = createUndersetNode();
5143
+ const arabicNode = createUndersetNode();
5144
+ arabicNode.id = englishNode.id;
5145
+ if (arabicNode.underExpr && englishNode.underExpr) {
5146
+ arabicNode.underExpr.id = englishNode.underExpr.id;
5147
+ }
5148
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5149
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5150
+ }
5151
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5152
+ next.caret = {
5153
+ chainId: englishNode.underExpr ? englishNode.underExpr.id : next.caret.chainId,
5154
+ index: 0
5155
+ };
5156
+ next.selectedStructureNodeId = null;
5157
+ syncSelectionToCaret(next);
5158
+ appendDebug(next, "insertUnderset", "");
5159
+ return next;
5160
+ }
5161
+ function insertLimitsSeriesTemplate(session, commandId) {
5162
+ const base = replaceSelectionFirst(session);
5163
+ const next = cloneEditorSession(base);
5164
+ const { english, arabic } = buildLimitsSeriesTemplate(commandId);
5165
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
5166
+ syncSubtreeRecursive(next, english, arabic);
5167
+ next.caret = limitsSeriesTemplateInitialCaret(english);
5168
+ next.selectedStructureNodeId = null;
5169
+ syncSelectionToCaret(next);
5170
+ appendDebug(next, "insertLimitsSeriesTemplate", commandId);
5171
+ return next;
5172
+ }
5173
+ function insertAccentPair(session) {
5174
+ const base = replaceSelectionFirst(session);
5175
+ const next = cloneEditorSession(base);
5176
+ const { english, arabic } = buildAccentPairTemplate();
5177
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
5178
+ syncSubtreeRecursive(next, english, arabic);
5179
+ next.caret = accentPairTemplateInitialCaret(english);
5180
+ next.selectedStructureNodeId = null;
5181
+ syncSelectionToCaret(next);
5182
+ appendDebug(next, "insertAccentPair", "");
5183
+ return next;
5184
+ }
5185
+ function insertAccent(session, accentId) {
5186
+ const next = cloneEditorSession(session);
5187
+ const englishNode = createAccentNode(accentId);
5188
+ const arabicNode = createAccentNode(accentId);
5189
+ arabicNode.id = englishNode.id;
5190
+ if (arabicNode.baseExpr && englishNode.baseExpr) {
5191
+ arabicNode.baseExpr.id = englishNode.baseExpr.id;
5192
+ }
5193
+ if (isSelectionActive(next.selection) && next.selection) {
5194
+ const sel = next.selection;
5195
+ const { start, end } = normalizeSelection(sel);
5196
+ const englishLocated = findChainById(next.englishTree, sel.chainId);
5197
+ const arabicLocated = findChainById(next.arabicTree, sel.chainId);
5198
+ if (englishLocated && arabicLocated && end > start) {
5199
+ const count = end - start;
5200
+ const englishWrapped = englishLocated.chain.nodes.splice(start, count);
5201
+ const arabicWrapped = arabicLocated.chain.nodes.splice(start, count);
5202
+ englishNode.baseExpr.nodes = englishWrapped;
5203
+ arabicNode.baseExpr.nodes = arabicWrapped;
5204
+ englishLocated.chain.nodes.splice(start, 0, englishNode);
5205
+ arabicLocated.chain.nodes.splice(start, 0, arabicNode);
5206
+ syncSubtreeRecursive(next, englishNode, arabicNode);
5207
+ next.caret = {
5208
+ chainId: englishNode.baseExpr.id,
5209
+ index: englishWrapped.length
5210
+ };
5211
+ next.selection = null;
5212
+ next.selectedStructureNodeId = null;
5213
+ syncSelectionToCaret(next);
5214
+ appendDebug(next, "insertAccent", `${accentId}:wrap`);
5215
+ return next;
5216
+ }
5217
+ }
5218
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
5219
+ syncSubtreeRecursive(next, englishNode, arabicNode);
5220
+ next.caret = {
5221
+ chainId: englishNode.baseExpr ? englishNode.baseExpr.id : next.caret.chainId,
5222
+ index: 0
5223
+ };
5224
+ next.selection = null;
5225
+ next.selectedStructureNodeId = null;
5226
+ syncSelectionToCaret(next);
5227
+ appendDebug(next, "insertAccent", `${accentId}:empty`);
5228
+ return next;
5229
+ }
4392
5230
  function insertMatrixEnv(session, style, rows, columns) {
4393
5231
  return insertGridEnv(session, style, rows, columns);
4394
5232
  }
@@ -4636,7 +5474,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
4636
5474
  if (!previousNode) {
4637
5475
  return session;
4638
5476
  }
4639
- if ((previousNode.kind === "delimiter" || previousNode.kind === "frac" || previousNode.kind === "sqrt" || previousNode.kind === "env") && next.selectedStructureNodeId !== previousNode.id) {
5477
+ 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) {
4640
5478
  next.selectedStructureNodeId = previousNode.id;
4641
5479
  next.selectedNodeId = previousNode.id;
4642
5480
  appendDebug(next, "deleteBackward", "selected structure");
@@ -4931,6 +5769,15 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
4931
5769
  if (node.kind === "sqrt") {
4932
5770
  return buildSqrtNodeBody(node, buildChain, side);
4933
5771
  }
5772
+ if (node.kind === "overset") {
5773
+ return buildOversetNodeBody(node, buildChain);
5774
+ }
5775
+ if (node.kind === "underset") {
5776
+ return buildUndersetNodeBody(node, buildChain);
5777
+ }
5778
+ if (node.kind === "accent") {
5779
+ return buildAccentNodeBody(node, buildChain);
5780
+ }
4934
5781
  if (node.kind === "env") {
4935
5782
  return buildMatrixEnvNodeBody(node, buildChain, side);
4936
5783
  }
@@ -5639,6 +6486,26 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
5639
6486
  applyStructural((prev) => insertSqrt(prev));
5640
6487
  surfaceEl.focus();
5641
6488
  },
6489
+ insertOverset: () => {
6490
+ applyStructural((prev) => insertOverset(prev));
6491
+ surfaceEl.focus();
6492
+ },
6493
+ insertUnderset: () => {
6494
+ applyStructural((prev) => insertUnderset(prev));
6495
+ surfaceEl.focus();
6496
+ },
6497
+ insertLimitsSeriesTemplate: (commandId) => {
6498
+ applyStructural((prev) => insertLimitsSeriesTemplate(prev, commandId));
6499
+ surfaceEl.focus();
6500
+ },
6501
+ insertAccentPair: () => {
6502
+ applyStructural((prev) => insertAccentPair(prev));
6503
+ surfaceEl.focus();
6504
+ },
6505
+ insertAccent: (accentId) => {
6506
+ applyStructural((prev) => insertAccent(prev, accentId));
6507
+ surfaceEl.focus();
6508
+ },
5642
6509
  insertAtomicCommand: (commandId) => {
5643
6510
  applyStructural((prev) => insertAtomicCommand(prev, commandId));
5644
6511
  surfaceEl.focus();
@@ -5868,7 +6735,10 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
5868
6735
  // src/mathjax/svgPatcher.ts
5869
6736
  var SVG_ARABSQRT_SELECTOR = 'mjx-container[jax="SVG"] svg .mjx-rtl-mirror[data-mjx-rtl-root="true"]';
5870
6737
  var ARABSQRT_SELECTOR = '.mjx-rtl-mirror[data-mjx-rtl-root="true"]';
6738
+ var SVG_PREVIEW_MIRROR_SELECTOR = 'mjx-container[jax="SVG"] svg .butex-preview-mirror';
6739
+ var PREVIEW_MIRROR_SELECTOR = ".butex-preview-mirror";
5871
6740
  var PATCHED_ATTR = "data-butex-svg-arabsqrt";
6741
+ var MIRROR_PATCHED_ATTR = "data-butex-svg-mirror";
5872
6742
  var ROOT_INDEX_SCALE = 0.72;
5873
6743
  var ROOT_INDEX_GAP_FACTOR = 0.08;
5874
6744
  var ROOT_INDEX_MIN_GAP = 2;
@@ -5893,11 +6763,12 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
5893
6763
  return Array.from(element.children).filter((child) => child instanceof SVGElement);
5894
6764
  }
5895
6765
  function boxFor(element) {
5896
- if (!(element instanceof SVGGraphicsElement) || typeof element.getBBox !== "function") {
6766
+ const candidate = element;
6767
+ if (typeof candidate.getBBox !== "function") {
5897
6768
  return null;
5898
6769
  }
5899
6770
  try {
5900
- const box = element.getBBox();
6771
+ const box = candidate.getBBox();
5901
6772
  return {
5902
6773
  x: box.x,
5903
6774
  y: box.y,
@@ -6141,6 +7012,31 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6141
7012
  root.setAttribute(PATCHED_ATTR, "patched");
6142
7013
  rootNode.setAttribute(PATCHED_ATTR, "patched");
6143
7014
  }
7015
+ function patchPreviewMirror(element) {
7016
+ if (element.getAttribute(MIRROR_PATCHED_ATTR) === "patched") {
7017
+ return;
7018
+ }
7019
+ const box = boxFor(element);
7020
+ if (!box || box.width <= 0) {
7021
+ return;
7022
+ }
7023
+ const [tx, ty] = readTranslate(element);
7024
+ const mirrorX = tx + 2 * box.x + box.width;
7025
+ element.setAttribute(
7026
+ "transform",
7027
+ `translate(${roundSvg(mirrorX)},${roundSvg(ty)}) scale(-1,1)`
7028
+ );
7029
+ element.setAttribute(MIRROR_PATCHED_ATTR, "patched");
7030
+ }
7031
+ function collectPreviewMirrors(root) {
7032
+ let mirrors = Array.from(root.querySelectorAll(SVG_PREVIEW_MIRROR_SELECTOR));
7033
+ if (!mirrors.length) {
7034
+ mirrors = Array.from(root.querySelectorAll(PREVIEW_MIRROR_SELECTOR)).filter((candidate) => {
7035
+ return candidate.closest('mjx-container[jax="SVG"]') != null;
7036
+ });
7037
+ }
7038
+ return mirrors;
7039
+ }
6144
7040
  function patchBuTeXSvgMath(root) {
6145
7041
  if (typeof root.querySelectorAll !== "function") {
6146
7042
  return;
@@ -6152,6 +7048,7 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
6152
7048
  });
6153
7049
  }
6154
7050
  roots.sort((a, b) => rootDepth(b) - rootDepth(a)).forEach((arabSqrtRoot) => patchArabSqrtRoot(arabSqrtRoot));
7051
+ collectPreviewMirrors(root).forEach((mirror) => patchPreviewMirror(mirror));
6155
7052
  }
6156
7053
 
6157
7054
  // src/mathjax/renderIsland.ts