@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.
@@ -1353,6 +1353,155 @@ function createEmptyDocument2() {
1353
1353
  };
1354
1354
  }
1355
1355
 
1356
+ // src/editor/accentCommands.ts
1357
+ var ACCENT_COMMANDS = {
1358
+ vec: {
1359
+ id: "vec",
1360
+ englishTex: "\\vec",
1361
+ arabicTex: "\\arabvec",
1362
+ placement: "over",
1363
+ label: "\u20D7",
1364
+ title: "\u0633\u0647\u0645 \u0641\u0648\u0642"
1365
+ },
1366
+ hat: {
1367
+ id: "hat",
1368
+ englishTex: "\\hat",
1369
+ arabicTex: "\\hat",
1370
+ placement: "over",
1371
+ label: "\u02C6",
1372
+ title: "\u0642\u0628\u0639\u0629"
1373
+ },
1374
+ tilde: {
1375
+ id: "tilde",
1376
+ englishTex: "\\tilde",
1377
+ arabicTex: "\\tilde",
1378
+ placement: "over",
1379
+ label: "\u02DC",
1380
+ title: "\u0645\u062F\u0629"
1381
+ },
1382
+ dot: {
1383
+ id: "dot",
1384
+ englishTex: "\\dot",
1385
+ arabicTex: "\\dot",
1386
+ placement: "over",
1387
+ label: "\u02D9",
1388
+ title: "\u0646\u0642\u0637\u0629 \u0641\u0648\u0642"
1389
+ },
1390
+ ddot: {
1391
+ id: "ddot",
1392
+ englishTex: "\\ddot",
1393
+ arabicTex: "\\ddot",
1394
+ placement: "over",
1395
+ label: "\xA8",
1396
+ title: "\u0646\u0642\u0637\u062A\u0627\u0646 \u0641\u0648\u0642"
1397
+ },
1398
+ dddot: {
1399
+ id: "dddot",
1400
+ englishTex: "\\dddot",
1401
+ arabicTex: "\\dddot",
1402
+ placement: "over",
1403
+ label: "\u20DB",
1404
+ title: "\u062B\u0644\u0627\u062B \u0646\u0642\u0627\u0637 \u0641\u0648\u0642"
1405
+ },
1406
+ bar: {
1407
+ id: "bar",
1408
+ englishTex: "\\bar",
1409
+ arabicTex: "\\bar",
1410
+ placement: "over",
1411
+ label: "\xAF",
1412
+ title: "\u062E\u0637 \u0641\u0648\u0642"
1413
+ },
1414
+ check: {
1415
+ id: "check",
1416
+ englishTex: "\\check",
1417
+ arabicTex: "\\check",
1418
+ placement: "over",
1419
+ label: "\u02C7",
1420
+ title: "\u0639\u0644\u0627\u0645\u0629 \u062A\u062D\u0642\u0642"
1421
+ },
1422
+ breve: {
1423
+ id: "breve",
1424
+ englishTex: "\\breve",
1425
+ arabicTex: "\\breve",
1426
+ placement: "over",
1427
+ label: "\u02D8",
1428
+ title: "\u0642\u0648\u0633 \u0642\u0635\u064A\u0631"
1429
+ },
1430
+ acute: {
1431
+ id: "acute",
1432
+ englishTex: "\\acute",
1433
+ arabicTex: "\\grave",
1434
+ placement: "over",
1435
+ label: "\xB4",
1436
+ title: "\u0646\u0628\u0631\u0629 \u062D\u0627\u062F\u0629"
1437
+ },
1438
+ grave: {
1439
+ id: "grave",
1440
+ englishTex: "\\grave",
1441
+ arabicTex: "\\acute",
1442
+ placement: "over",
1443
+ label: "`",
1444
+ title: "\u0646\u0628\u0631\u0629 \u062B\u0642\u064A\u0644\u0629"
1445
+ },
1446
+ overline: {
1447
+ id: "overline",
1448
+ englishTex: "\\overline",
1449
+ arabicTex: "\\overline",
1450
+ placement: "over",
1451
+ label: "\u203E",
1452
+ title: "\u062E\u0637 \u0639\u0644\u0648\u064A \u0645\u0645\u062A\u062F"
1453
+ },
1454
+ underline: {
1455
+ id: "underline",
1456
+ englishTex: "\\underline",
1457
+ arabicTex: "\\underline",
1458
+ placement: "under",
1459
+ label: "_",
1460
+ title: "\u062E\u0637 \u0633\u0641\u0644\u064A"
1461
+ },
1462
+ overleftarrow: {
1463
+ id: "overleftarrow",
1464
+ englishTex: "\\overleftarrow",
1465
+ arabicTex: "\\overrightarrow",
1466
+ placement: "over",
1467
+ label: "\u2190",
1468
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631"
1469
+ },
1470
+ overrightarrow: {
1471
+ id: "overrightarrow",
1472
+ englishTex: "\\overrightarrow",
1473
+ arabicTex: "\\overleftarrow",
1474
+ placement: "over",
1475
+ label: "\u2192",
1476
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646"
1477
+ },
1478
+ overleftrightarrow: {
1479
+ id: "overleftrightarrow",
1480
+ englishTex: "\\overleftrightarrow",
1481
+ arabicTex: "\\overleftrightarrow",
1482
+ placement: "over",
1483
+ label: "\u2194",
1484
+ title: "\u0633\u0647\u0645 \u0639\u0644\u0648\u064A \u0645\u0632\u062F\u0648\u062C \u0627\u0644\u0627\u062A\u062C\u0627\u0647"
1485
+ }
1486
+ };
1487
+ function accentCommandSpec(id) {
1488
+ return Object.prototype.hasOwnProperty.call(ACCENT_COMMANDS, id) ? ACCENT_COMMANDS[id] : null;
1489
+ }
1490
+ function accentCommandIdFromTex(tex) {
1491
+ const normalized = tex.startsWith("\\") ? tex : `\\${tex}`;
1492
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1493
+ if (spec.englishTex === normalized) {
1494
+ return spec.id;
1495
+ }
1496
+ }
1497
+ for (const spec of Object.values(ACCENT_COMMANDS)) {
1498
+ if (spec.arabicTex === normalized) {
1499
+ return spec.id;
1500
+ }
1501
+ }
1502
+ return null;
1503
+ }
1504
+
1356
1505
  // src/editor/atomicCommands.ts
1357
1506
  var ATOMIC_COMMANDS = {
1358
1507
  ///////////////////////// Functions ////////////////////////////////
@@ -2258,6 +2407,9 @@ function createEditorNode(kind, expr) {
2258
2407
  denominator: null,
2259
2408
  radicand: null,
2260
2409
  rootIndex: null,
2410
+ overExpr: null,
2411
+ underExpr: null,
2412
+ baseExpr: null,
2261
2413
  envName: null,
2262
2414
  matrixStyle: null,
2263
2415
  matrixRows: null,
@@ -2286,6 +2438,26 @@ function createSqrtNode() {
2286
2438
  rootIndex: createEditorChain()
2287
2439
  };
2288
2440
  }
2441
+ function createOversetNode() {
2442
+ return {
2443
+ ...createEditorNode("overset", ""),
2444
+ overExpr: createEditorChain(),
2445
+ baseExpr: createEditorChain()
2446
+ };
2447
+ }
2448
+ function createUndersetNode() {
2449
+ return {
2450
+ ...createEditorNode("underset", ""),
2451
+ underExpr: createEditorChain(),
2452
+ baseExpr: createEditorChain()
2453
+ };
2454
+ }
2455
+ function createAccentNode(accentId) {
2456
+ return {
2457
+ ...createEditorNode("accent", accentId),
2458
+ baseExpr: createEditorChain()
2459
+ };
2460
+ }
2289
2461
  function createGridEnvNode(envName, rows, columns, columnAlignments) {
2290
2462
  const safeRows = Math.max(1, Math.min(12, Math.trunc(rows)));
2291
2463
  const safeColumns = Math.max(1, Math.min(12, Math.trunc(columns)));
@@ -2344,6 +2516,15 @@ function collectNodeIds(chain, ids) {
2344
2516
  if (node.radicand) {
2345
2517
  collectNodeIds(node.radicand, ids);
2346
2518
  }
2519
+ if (node.overExpr) {
2520
+ collectNodeIds(node.overExpr, ids);
2521
+ }
2522
+ if (node.underExpr) {
2523
+ collectNodeIds(node.underExpr, ids);
2524
+ }
2525
+ if (node.baseExpr) {
2526
+ collectNodeIds(node.baseExpr, ids);
2527
+ }
2347
2528
  if (node.matrixRows) {
2348
2529
  for (const row of node.matrixRows) {
2349
2530
  for (const cell of row) {
@@ -2474,6 +2655,22 @@ function renderMatrixRowsArabic(node, options) {
2474
2655
  }
2475
2656
  return `\\begin{${envName}}${rows.join(" \\\\\n")}\\end{${envName}}`;
2476
2657
  }
2658
+ function renderAccentEnglish(command, accent, base, options) {
2659
+ const baseTex = base ? renderChainEnglish(base, options) : "";
2660
+ const accentTex = accent ? renderChainEnglish(accent, options) : "";
2661
+ if (accentTex === "") {
2662
+ return baseTex;
2663
+ }
2664
+ return `\\${command}{${accentTex}}{${baseTex}}`;
2665
+ }
2666
+ function renderAccentArabic(command, accent, base, options) {
2667
+ const baseTex = base ? renderChainArabic(base, options) : "";
2668
+ const accentTex = accent ? renderChainArabic(accent, options) : "";
2669
+ if (accentTex === "") {
2670
+ return baseTex;
2671
+ }
2672
+ return `\\${command}{${accentTex}}{${baseTex}}`;
2673
+ }
2477
2674
  function escapeText(s) {
2478
2675
  return s.replace(/\\/g, "\\textbackslash{}").replace(/[{}]/g, "\\$&");
2479
2676
  }
@@ -2503,6 +2700,19 @@ function renderNodeEnglish(node, options) {
2503
2700
  const body = `\\sqrt${optionalRootIndexEnglish(node, options)}{${renderChainEnglish(node.radicand, options)}}`;
2504
2701
  return `${body}${latinScripts(node, options)}`;
2505
2702
  }
2703
+ if (node.kind === "overset" && node.baseExpr) {
2704
+ const body = renderAccentEnglish("overset", node.overExpr, node.baseExpr, options);
2705
+ return `${body}${latinScripts(node, options)}`;
2706
+ }
2707
+ if (node.kind === "underset" && node.baseExpr) {
2708
+ const body = renderAccentEnglish("underset", node.underExpr, node.baseExpr, options);
2709
+ return `${body}${latinScripts(node, options)}`;
2710
+ }
2711
+ if (node.kind === "accent" && node.baseExpr) {
2712
+ const cmd = accentCommandSpec(node.expr)?.englishTex ?? `\\${node.expr}`;
2713
+ const body = `${cmd}{${renderChainEnglish(node.baseExpr, options)}}`;
2714
+ return `${body}${latinScripts(node, options)}`;
2715
+ }
2506
2716
  if (node.kind === "env") {
2507
2717
  return `${renderMatrixRowsEnglish(node, options)}${latinScripts(node, options)}`;
2508
2718
  }
@@ -2535,6 +2745,19 @@ function renderNodeArabic(node, options) {
2535
2745
  const content = `\\arabsqrt${optionalRootIndexArabic(node, options)}{${renderChainArabic(node.radicand, options)}}`;
2536
2746
  return arabicScripts(node, content, options);
2537
2747
  }
2748
+ if (node.kind === "overset" && node.baseExpr) {
2749
+ const content = renderAccentArabic("overset", node.overExpr, node.baseExpr, options);
2750
+ return arabicScripts(node, content, options);
2751
+ }
2752
+ if (node.kind === "underset" && node.baseExpr) {
2753
+ const content = renderAccentArabic("underset", node.underExpr, node.baseExpr, options);
2754
+ return arabicScripts(node, content, options);
2755
+ }
2756
+ if (node.kind === "accent" && node.baseExpr) {
2757
+ const cmd = accentCommandSpec(node.expr)?.arabicTex ?? `\\${node.expr}`;
2758
+ const content = `${cmd}{${renderChainArabic(node.baseExpr, options)}}`;
2759
+ return arabicScripts(node, content, options);
2760
+ }
2538
2761
  if (node.kind === "env") {
2539
2762
  return arabicScripts(node, renderMatrixRowsArabic(node, options), options);
2540
2763
  }
@@ -2739,6 +2962,109 @@ var SQRT_CSS = `
2739
2962
  }
2740
2963
  `.trim();
2741
2964
 
2965
+ // src/editor/display/overset.ts
2966
+ var OVERSET_CSS = `
2967
+ .overset {
2968
+ display: inline-flex;
2969
+ flex-direction: column;
2970
+ align-items: center;
2971
+ justify-content: center;
2972
+ vertical-align: middle;
2973
+ margin: 0 2px;
2974
+ min-width: 1.2em;
2975
+ }
2976
+
2977
+ .overset-over {
2978
+ display: inline-flex;
2979
+ justify-content: center;
2980
+ align-items: center;
2981
+ min-height: 0.85em;
2982
+ padding: 0 2px;
2983
+ font-size: 0.72em;
2984
+ line-height: 1.1;
2985
+ }
2986
+
2987
+ .overset-base {
2988
+ display: inline-flex;
2989
+ justify-content: center;
2990
+ align-items: center;
2991
+ min-height: 1.05em;
2992
+ padding: 0 2px;
2993
+ }
2994
+ `.trim();
2995
+
2996
+ // src/editor/display/underset.ts
2997
+ var UNDERSET_CSS = `
2998
+ .underset {
2999
+ display: inline-flex;
3000
+ flex-direction: column;
3001
+ align-items: center;
3002
+ justify-content: center;
3003
+ vertical-align: middle;
3004
+ margin: 0 2px;
3005
+ min-width: 1.2em;
3006
+ }
3007
+
3008
+ .underset-base {
3009
+ display: inline-flex;
3010
+ justify-content: center;
3011
+ align-items: center;
3012
+ min-height: 1.05em;
3013
+ padding: 0 2px;
3014
+ }
3015
+
3016
+ .underset-under {
3017
+ display: inline-flex;
3018
+ justify-content: center;
3019
+ align-items: center;
3020
+ min-height: 0.85em;
3021
+ padding: 0 2px;
3022
+ font-size: 0.72em;
3023
+ line-height: 1.1;
3024
+ }
3025
+ `.trim();
3026
+
3027
+ // src/editor/display/accent.ts
3028
+ var ACCENT_CSS = `
3029
+ .math-accent {
3030
+ display: inline-flex;
3031
+ flex-direction: column;
3032
+ align-items: center;
3033
+ justify-content: center;
3034
+ vertical-align: middle;
3035
+ margin: 0 2px;
3036
+ min-width: 1.1em;
3037
+ }
3038
+
3039
+ .math-accent-chrome {
3040
+ display: inline-flex;
3041
+ justify-content: center;
3042
+ align-items: center;
3043
+ min-height: 0.7em;
3044
+ padding: 0 2px;
3045
+ font-size: 0.85em;
3046
+ line-height: 1;
3047
+ color: var(--butex-script-color, #475569);
3048
+ user-select: none;
3049
+ }
3050
+
3051
+ .math-accent-base {
3052
+ display: inline-flex;
3053
+ justify-content: center;
3054
+ align-items: center;
3055
+ min-height: 1.05em;
3056
+ padding: 0 2px;
3057
+ }
3058
+
3059
+ .math-accent--under .math-accent-chrome {
3060
+ min-height: 0.45em;
3061
+ border-top: 1.5px solid currentColor;
3062
+ width: 100%;
3063
+ font-size: 0;
3064
+ color: var(--butex-surface-fg, #0f172a);
3065
+ }
3066
+ `.trim();
3067
+
2742
3068
  // src/editor/display/env.ts
2743
3069
  var MATRIX_ENV_CSS = `
2744
3070
  .matrix-env {
@@ -3126,6 +3452,12 @@ ${FRAC_CSS}
3126
3452
 
3127
3453
  ${SQRT_CSS}
3128
3454
 
3455
+ ${OVERSET_CSS}
3456
+
3457
+ ${UNDERSET_CSS}
3458
+
3459
+ ${ACCENT_CSS}
3460
+
3129
3461
  ${MATRIX_ENV_CSS}
3130
3462
 
3131
3463
  ${ATOMIC_COMMAND_CSS}
@@ -3408,6 +3740,56 @@ function commandToEditorNode(node) {
3408
3740
  }
3409
3741
  return { editable: true, node: sqrt };
3410
3742
  }
3743
+ if (node.name === "\\overset" && node.mandatoryArgs.length >= 2) {
3744
+ const overset = createOversetNode();
3745
+ const overExpr = chainToEditorChain(node.mandatoryArgs[0]);
3746
+ const baseExpr = chainToEditorChain(node.mandatoryArgs[1]);
3747
+ if (!overExpr.editable) {
3748
+ return overExpr;
3749
+ }
3750
+ if (!baseExpr.editable) {
3751
+ return baseExpr;
3752
+ }
3753
+ overset.overExpr = overExpr.chain;
3754
+ overset.baseExpr = baseExpr.chain;
3755
+ const scripts = attachScripts(node, overset);
3756
+ if (scripts) {
3757
+ return scripts;
3758
+ }
3759
+ return { editable: true, node: overset };
3760
+ }
3761
+ if (node.name === "\\underset" && node.mandatoryArgs.length >= 2) {
3762
+ const underset = createUndersetNode();
3763
+ const underExpr = chainToEditorChain(node.mandatoryArgs[0]);
3764
+ const baseExpr = chainToEditorChain(node.mandatoryArgs[1]);
3765
+ if (!underExpr.editable) {
3766
+ return underExpr;
3767
+ }
3768
+ if (!baseExpr.editable) {
3769
+ return baseExpr;
3770
+ }
3771
+ underset.underExpr = underExpr.chain;
3772
+ underset.baseExpr = baseExpr.chain;
3773
+ const scripts = attachScripts(node, underset);
3774
+ if (scripts) {
3775
+ return scripts;
3776
+ }
3777
+ return { editable: true, node: underset };
3778
+ }
3779
+ const accentId = accentCommandIdFromTex(node.name);
3780
+ if (accentId && node.mandatoryArgs.length >= 1) {
3781
+ const accent = createAccentNode(accentId);
3782
+ const baseExpr = chainToEditorChain(node.mandatoryArgs[0]);
3783
+ if (!baseExpr.editable) {
3784
+ return baseExpr;
3785
+ }
3786
+ accent.baseExpr = baseExpr.chain;
3787
+ const scripts = attachScripts(node, accent);
3788
+ if (scripts) {
3789
+ return scripts;
3790
+ }
3791
+ return { editable: true, node: accent };
3792
+ }
3411
3793
  const atomicId = commandIdForTex(node.name);
3412
3794
  if (atomicId && node.optionalArgs.length === 0 && node.mandatoryArgs.length === 0) {
3413
3795
  const atomic = createEditorNode("atomicCommand", atomicId);
@@ -3544,6 +3926,21 @@ function editorEnvToAstNode(node) {
3544
3926
  const scripts = attachAstScripts(node, env);
3545
3927
  return scripts ?? { ok: true, node: env };
3546
3928
  }
3929
+ function accentChainForExport(accent) {
3930
+ if (!accent) {
3931
+ return { ok: true, chain: new ChainNode([]) };
3932
+ }
3933
+ return editorChainToAstChain(accent);
3934
+ }
3935
+ function nodeFromAccentBase(command, accent, base) {
3936
+ if (accent.chain.length > 0) {
3937
+ return new CommandNode(command, [], [accent, base]);
3938
+ }
3939
+ if (base.chain.length === 1) {
3940
+ return base.chain[0];
3941
+ }
3942
+ return new DelimiterNode("", base, "");
3943
+ }
3547
3944
  function editorNodeToAstNode(node) {
3548
3945
  let astNode;
3549
3946
  if (node.kind === "char") {
@@ -3582,6 +3979,36 @@ function editorNodeToAstNode(node) {
3582
3979
  optionalArgs.push(rootIndex.chain);
3583
3980
  }
3584
3981
  astNode = new CommandNode("\\sqrt", optionalArgs, [radicand.chain]);
3982
+ } else if (node.kind === "overset" && node.baseExpr) {
3983
+ const accent = accentChainForExport(node.overExpr);
3984
+ if (!accent.ok) {
3985
+ return accent;
3986
+ }
3987
+ const baseExpr = editorChainToAstChain(node.baseExpr);
3988
+ if (!baseExpr.ok) {
3989
+ return baseExpr;
3990
+ }
3991
+ astNode = nodeFromAccentBase("\\overset", accent.chain, baseExpr.chain);
3992
+ } else if (node.kind === "underset" && node.baseExpr) {
3993
+ const accent = accentChainForExport(node.underExpr);
3994
+ if (!accent.ok) {
3995
+ return accent;
3996
+ }
3997
+ const baseExpr = editorChainToAstChain(node.baseExpr);
3998
+ if (!baseExpr.ok) {
3999
+ return baseExpr;
4000
+ }
4001
+ astNode = nodeFromAccentBase("\\underset", accent.chain, baseExpr.chain);
4002
+ } else if (node.kind === "accent" && node.baseExpr) {
4003
+ const tex = accentCommandSpec(node.expr)?.englishTex;
4004
+ if (!tex) {
4005
+ return { ok: false, reason: `\u0644\u0643\u0646\u0629 \u0631\u064A\u0627\u0636\u064A\u0629 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645\u0629 \u062D\u0627\u0644\u064A\u0627: ${node.expr}` };
4006
+ }
4007
+ const baseExpr = editorChainToAstChain(node.baseExpr);
4008
+ if (!baseExpr.ok) {
4009
+ return baseExpr;
4010
+ }
4011
+ astNode = new CommandNode(tex, [], [baseExpr.chain]);
3585
4012
  } else if (node.kind === "atomicCommand") {
3586
4013
  const tex = atomicCommandSpec(node.expr)?.englishTex;
3587
4014
  if (!tex) {