@drghaliasri/butex 5.3.3 → 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
@@ -745,11 +745,20 @@ function passthroughArgument(parser, name) {
745
745
  const inner = new TexParserClass(arg, parser.stack.env, parser.configuration).mml();
746
746
  parser.Push(inner);
747
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
+ }
748
755
  var passthroughArgumentTyped = passthroughArgument;
756
+ var arabvecArgumentTyped = arabvecArgument;
749
757
  function registerPassthroughCommandMacros(CommandMap) {
750
758
  new CommandMap(COMMAND_MAP6, {
751
759
  unit: passthroughArgumentTyped,
752
- idx: passthroughArgumentTyped
760
+ idx: passthroughArgumentTyped,
761
+ arabvec: arabvecArgumentTyped
753
762
  });
754
763
  return COMMAND_MAP6;
755
764
  }
@@ -1075,6 +1084,320 @@ function buildSqrtNodeBody(node, buildChain, side) {
1075
1084
  return wrap;
1076
1085
  }
1077
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
+
1078
1401
  // src/editor/display/env.ts
1079
1402
  var WRAPPERS = {
1080
1403
  matrix: { left: "", right: "" },
@@ -1300,6 +1623,10 @@ var EQUATION_EDITOR_MESSAGES = {
1300
1623
  insertBraces: "\u0625\u062F\u0631\u0627\u062C \u062D\u0627\u0635\u0631\u062A\u064A\u0646",
1301
1624
  insertFraction: "\u0625\u062F\u0631\u0627\u062C \u0643\u0633\u0631",
1302
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",
1303
1630
  environments: "\u0627\u0644\u0628\u064A\u0626\u0627\u062A",
1304
1631
  insertEnvironment: "\u0625\u062F\u0631\u0627\u062C \u0628\u064A\u0626\u0629 \u0634\u0628\u0643\u064A\u0629",
1305
1632
  environmentType: "\u0646\u0648\u0639 \u0627\u0644\u0628\u064A\u0626\u0629",
@@ -1407,6 +1734,10 @@ var EQUATION_EDITOR_MESSAGES = {
1407
1734
  insertBraces: "Insert braces",
1408
1735
  insertFraction: "Insert fraction",
1409
1736
  insertRoot: "Insert root",
1737
+ insertOverset: "Insert overset",
1738
+ insertUnderset: "Insert underset",
1739
+ insertAccentPair: "Insert overset and underset",
1740
+ insertAccents: "Insert accent",
1410
1741
  environments: "Environments",
1411
1742
  insertEnvironment: "Insert grid environment",
1412
1743
  environmentType: "Environment type",
@@ -2443,6 +2774,12 @@ ${FRAC_CSS}
2443
2774
 
2444
2775
  ${SQRT_CSS}
2445
2776
 
2777
+ ${OVERSET_CSS}
2778
+
2779
+ ${UNDERSET_CSS}
2780
+
2781
+ ${ACCENT_CSS}
2782
+
2446
2783
  ${MATRIX_ENV_CSS}
2447
2784
 
2448
2785
  ${ATOMIC_COMMAND_CSS}
@@ -2469,6 +2806,8 @@ function injectBuTeXEditorStyles(doc) {
2469
2806
  // src/editor/index.ts
2470
2807
  var editor_exports = {};
2471
2808
  __export(editor_exports, {
2809
+ ACCENT_COMMANDS: () => ACCENT_COMMANDS,
2810
+ ACCENT_CSS: () => ACCENT_CSS,
2472
2811
  ATOMIC_COMMANDS: () => ATOMIC_COMMANDS,
2473
2812
  ATOMIC_COMMAND_CSS: () => ATOMIC_COMMAND_CSS,
2474
2813
  ATOMIC_OPERATOR_COMMANDS: () => ATOMIC_OPERATOR_COMMANDS,
@@ -2479,7 +2818,12 @@ __export(editor_exports, {
2479
2818
  DELIMITER_CSS: () => DELIMITER_CSS,
2480
2819
  FRAC_CSS: () => FRAC_CSS,
2481
2820
  MATRIX_ENV_CSS: () => MATRIX_ENV_CSS,
2821
+ OVERSET_CSS: () => OVERSET_CSS,
2482
2822
  SQRT_CSS: () => SQRT_CSS,
2823
+ UNDERSET_CSS: () => UNDERSET_CSS,
2824
+ accentCommandIdFromTex: () => accentCommandIdFromTex,
2825
+ accentCommandSpec: () => accentCommandSpec,
2826
+ accentCommandsList: () => accentCommandsList,
2483
2827
  activeSideLabel: () => activeSideLabel,
2484
2828
  activeTreeKey: () => activeTreeKey,
2485
2829
  addMatrixColumn: () => addMatrixColumn,
@@ -2500,6 +2844,7 @@ __export(editor_exports, {
2500
2844
  collectCaretPositions: () => collectCaretPositions,
2501
2845
  copySelection: () => copySelection,
2502
2846
  coveredNodeIds: () => coveredNodeIds,
2847
+ createAccentNode: () => createAccentNode,
2503
2848
  createAtomicCommandNode: () => createAtomicCommandNode,
2504
2849
  createAtomicOperatorCommandNode: () => createAtomicOperatorCommandNode,
2505
2850
  createDelimiterNode: () => createDelimiterNode,
@@ -2510,8 +2855,10 @@ __export(editor_exports, {
2510
2855
  createFracNode: () => createFracNode,
2511
2856
  createGridEnvNode: () => createGridEnvNode,
2512
2857
  createMatrixEnvNode: () => createMatrixEnvNode,
2858
+ createOversetNode: () => createOversetNode,
2513
2859
  createSqrtNode: () => createSqrtNode,
2514
2860
  createStarterSession: () => createStarterSession,
2861
+ createUndersetNode: () => createUndersetNode,
2515
2862
  createUndoRedoStacks: () => createUndoRedoStacks,
2516
2863
  cutSelection: () => cutSelection,
2517
2864
  deleteBackward: () => deleteBackward,
@@ -2525,6 +2872,8 @@ __export(editor_exports, {
2525
2872
  fragmentToPlainText: () => fragmentToPlainText,
2526
2873
  horizontalCaretDelta: () => horizontalCaretDelta,
2527
2874
  injectBuTeXEditorStyles: () => injectBuTeXEditorStyles,
2875
+ insertAccent: () => insertAccent,
2876
+ insertAccentPair: () => insertAccentPair,
2528
2877
  insertAlignedEnv: () => insertAlignedEnv,
2529
2878
  insertArrayEnv: () => insertArrayEnv,
2530
2879
  insertAtomicCommand: () => insertAtomicCommand,
@@ -2534,11 +2883,14 @@ __export(editor_exports, {
2534
2883
  insertDivideOperator: () => insertDivideOperator,
2535
2884
  insertFirstDerivative: () => insertFirstDerivative,
2536
2885
  insertFraction: () => insertFraction,
2886
+ insertLimitsSeriesTemplate: () => insertLimitsSeriesTemplate,
2537
2887
  insertMatrixEnv: () => insertMatrixEnv,
2538
2888
  insertNumber: () => insertNumber,
2539
2889
  insertOperator: () => insertOperator,
2890
+ insertOverset: () => insertOverset,
2540
2891
  insertSecondDerivative: () => insertSecondDerivative,
2541
2892
  insertSqrt: () => insertSqrt,
2893
+ insertUnderset: () => insertUnderset,
2542
2894
  isSelectionActive: () => isSelectionActive,
2543
2895
  isSpacingCommandSpec: () => isSpacingCommandSpec,
2544
2896
  mirrorBuTeXOperatorsInTex: () => mirrorBuTeXOperatorsInTex,
@@ -2612,6 +2964,9 @@ function createEditorNode(kind, expr) {
2612
2964
  denominator: null,
2613
2965
  radicand: null,
2614
2966
  rootIndex: null,
2967
+ overExpr: null,
2968
+ underExpr: null,
2969
+ baseExpr: null,
2615
2970
  envName: null,
2616
2971
  matrixStyle: null,
2617
2972
  matrixRows: null,
@@ -2640,6 +2995,26 @@ function createSqrtNode() {
2640
2995
  rootIndex: createEditorChain()
2641
2996
  };
2642
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
+ }
2643
3018
  function createMatrixEnvNode(style, rows, columns) {
2644
3019
  return createGridEnvNode(style, rows, columns);
2645
3020
  }
@@ -2707,6 +3082,15 @@ function collectNodeIds(chain, ids) {
2707
3082
  if (node.radicand) {
2708
3083
  collectNodeIds(node.radicand, ids);
2709
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
+ }
2710
3094
  if (node.matrixRows) {
2711
3095
  for (const row of node.matrixRows) {
2712
3096
  for (const cell of row) {
@@ -2871,6 +3255,22 @@ function renderMatrixRowsArabic(node, options) {
2871
3255
  }
2872
3256
  return `\\begin{${envName}}${rows.join(" \\\\\n")}\\end{${envName}}`;
2873
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
+ }
2874
3274
  function escapeText(s) {
2875
3275
  return s.replace(/\\/g, "\\textbackslash{}").replace(/[{}]/g, "\\$&");
2876
3276
  }
@@ -2900,6 +3300,19 @@ function renderNodeEnglish(node, options) {
2900
3300
  const body = `\\sqrt${optionalRootIndexEnglish(node, options)}{${renderChainEnglish(node.radicand, options)}}`;
2901
3301
  return `${body}${latinScripts(node, options)}`;
2902
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
+ }
2903
3316
  if (node.kind === "env") {
2904
3317
  return `${renderMatrixRowsEnglish(node, options)}${latinScripts(node, options)}`;
2905
3318
  }
@@ -2932,6 +3345,19 @@ function renderNodeArabic(node, options) {
2932
3345
  const content = `\\arabsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
2933
3346
  return arabicScripts(node, content, options);
2934
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
+ }
2935
3361
  if (node.kind === "env") {
2936
3362
  return arabicScripts(node, renderMatrixRowsArabic(node, options), options);
2937
3363
  }
@@ -2988,6 +3414,35 @@ function collectCaretPositions(chain) {
2988
3414
  if (node.radicand) {
2989
3415
  walkChain(node.radicand);
2990
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
+ }
2991
3446
  if (node.matrixRows) {
2992
3447
  for (const row of node.matrixRows) {
2993
3448
  for (const cell of row) {
@@ -3121,6 +3576,42 @@ function findChainById(root, chainId) {
3121
3576
  return nested;
3122
3577
  }
3123
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
+ }
3124
3615
  if (node.matrixRows) {
3125
3616
  for (let rowIndex = 0; rowIndex < node.matrixRows.length; rowIndex += 1) {
3126
3617
  const row = node.matrixRows[rowIndex];
@@ -3194,6 +3685,24 @@ function findNodeById(root, nodeId) {
3194
3685
  return nested;
3195
3686
  }
3196
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
+ }
3197
3706
  if (node.matrixRows) {
3198
3707
  for (const row of node.matrixRows) {
3199
3708
  for (const cell of row) {
@@ -3232,6 +3741,15 @@ function nodeChildChains(node) {
3232
3741
  if (node.radicand) {
3233
3742
  chains.push(node.radicand);
3234
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
+ }
3235
3753
  if (node.matrixRows) {
3236
3754
  for (const row of node.matrixRows) {
3237
3755
  chains.push(...row);
@@ -3602,6 +4120,91 @@ function derivativeTemplateInitialCaret(englishFrac) {
3602
4120
  };
3603
4121
  }
3604
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
+
3605
4208
  // src/editor/state.ts
3606
4209
  function ensureSyncEntry(session, nodeId) {
3607
4210
  if (!session.sync[nodeId]) {
@@ -3635,7 +4238,7 @@ function syncSelectionToCaret(session) {
3635
4238
  session.selectedNodeId = located.relation.ownerNodeId;
3636
4239
  return;
3637
4240
  }
3638
- 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") {
3639
4242
  session.selectedNodeId = located.relation.ownerNodeId;
3640
4243
  return;
3641
4244
  }
@@ -3992,6 +4595,106 @@ function moveCaretVertical(session, direction) {
3992
4595
  appendDebug(next, "moveCaretVertical", "sqrt-radicand-down-exit");
3993
4596
  return next;
3994
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
+ }
3995
4698
  if (located.relation.kind === "matrixCell" && ownerLocated && ownerNode?.matrixRows) {
3996
4699
  const rowIndex = located.relation.rowIndex ?? 0;
3997
4700
  const columnIndex = located.relation.columnIndex ?? 0;
@@ -4369,6 +5072,119 @@ function insertSqrt(session) {
4369
5072
  appendDebug(next, "insertSqrt", "");
4370
5073
  return next;
4371
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
+ }
4372
5188
  function insertMatrixEnv(session, style, rows, columns) {
4373
5189
  return insertGridEnv(session, style, rows, columns);
4374
5190
  }
@@ -4616,7 +5432,7 @@ function deleteBackward(session) {
4616
5432
  if (!previousNode) {
4617
5433
  return session;
4618
5434
  }
4619
- 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) {
4620
5436
  next.selectedStructureNodeId = previousNode.id;
4621
5437
  next.selectedNodeId = previousNode.id;
4622
5438
  appendDebug(next, "deleteBackward", "selected structure");
@@ -4911,6 +5727,15 @@ function buildNodeBody(node, buildChain, side, digitForm = "western", uiLocale =
4911
5727
  if (node.kind === "sqrt") {
4912
5728
  return buildSqrtNodeBody(node, buildChain, side);
4913
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
+ }
4914
5739
  if (node.kind === "env") {
4915
5740
  return buildMatrixEnvNodeBody(node, buildChain, side);
4916
5741
  }
@@ -5619,6 +6444,26 @@ function createEditorRuntime(options) {
5619
6444
  applyStructural((prev) => insertSqrt(prev));
5620
6445
  surfaceEl.focus();
5621
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
+ },
5622
6467
  insertAtomicCommand: (commandId) => {
5623
6468
  applyStructural((prev) => insertAtomicCommand(prev, commandId));
5624
6469
  surfaceEl.focus();