@drghaliasri/butex 4.0.1 → 4.2.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.
@@ -917,6 +917,16 @@ var ATOMIC_COMMANDS = {
917
917
  arabicLabel: "\u0645\u062D\u062F\u062F",
918
918
  title: "\u0645\u062D\u062F\u062F"
919
919
  },
920
+ ////////////////////// Derivatives ////////////////////////////////
921
+ ad: {
922
+ id: "ad",
923
+ category: "derivative",
924
+ englishTex: "\\mathrm{d}",
925
+ englishLabel: "d",
926
+ arabicTex: "\\ad",
927
+ arabicLabel: "\u0621",
928
+ title: "\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0627\u0634\u062A\u0642\u0627\u0642"
929
+ },
920
930
  ////////////////////// Groups /////////////////////////////////
921
931
  N: {
922
932
  id: "N",
@@ -1740,6 +1750,22 @@ function createEditorSession(englishTree, arabicTree, activeSide = "arabic") {
1740
1750
  };
1741
1751
  }
1742
1752
 
1753
+ // src/editor/divideOperator.ts
1754
+ var DIVIDE_OPERATOR_EN = "/";
1755
+ var DIVIDE_OPERATOR_AR = "\\";
1756
+ function isDivideOperatorExpr(expr) {
1757
+ return expr === DIVIDE_OPERATOR_EN || expr === DIVIDE_OPERATOR_AR;
1758
+ }
1759
+ function divideOperatorSurfaceExpr(expr, side) {
1760
+ if (!isDivideOperatorExpr(expr)) {
1761
+ return expr;
1762
+ }
1763
+ return side === "arabic" ? DIVIDE_OPERATOR_AR : DIVIDE_OPERATOR_EN;
1764
+ }
1765
+ function renderDivideOperatorLatex(side) {
1766
+ return side === "arabic" ? "\\backslash" : DIVIDE_OPERATOR_EN;
1767
+ }
1768
+
1743
1769
  // src/editor/digits.ts
1744
1770
  var WESTERN = "0123456789";
1745
1771
  var ARABIC_INDIC = "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669";
@@ -1888,6 +1914,9 @@ function renderNodeEnglish(node, options) {
1888
1914
  if (node.kind === "char") {
1889
1915
  return `${renderCharContent(node, options)}${latinScripts(node, options)}`;
1890
1916
  }
1917
+ if (node.kind === "operator" && isDivideOperatorExpr(node.expr)) {
1918
+ return `${renderDivideOperatorLatex("english")}${latinScripts(node, options)}`;
1919
+ }
1891
1920
  return `${formatDigits(node.expr, selectedDigitForm(options))}${latinScripts(node, options)}`;
1892
1921
  }
1893
1922
  function renderNodeArabic(node, options) {
@@ -1922,6 +1951,9 @@ function renderNodeArabic(node, options) {
1922
1951
  const content = renderCharContent(node, options);
1923
1952
  return arabicScripts(node, (node.characterFont ?? "default") === "default" ? `\\text{${escapeText(expr)}}` : content, options);
1924
1953
  }
1954
+ if (node.kind === "operator" && isDivideOperatorExpr(node.expr)) {
1955
+ return arabicScripts(node, renderDivideOperatorLatex("arabic"), options);
1956
+ }
1925
1957
  return arabicScripts(node, formatDigits(node.expr, selectedDigitForm(options)), options);
1926
1958
  }
1927
1959
  function renderChainEnglish(chain, options) {
@@ -2445,6 +2477,128 @@ function undoRedoCanRedo(stacks) {
2445
2477
  return stacks.future.length > 0;
2446
2478
  }
2447
2479
 
2480
+ // src/editor/derivativeTemplates.ts
2481
+ var ARABIC_VAR = "\u0633";
2482
+ var ENGLISH_VAR = "x";
2483
+ function mirroredAd() {
2484
+ const english = createAtomicCommandNode("ad");
2485
+ const arabic = createAtomicCommandNode("ad");
2486
+ arabic.id = english.id;
2487
+ return { english, arabic };
2488
+ }
2489
+ function mirroredVar() {
2490
+ const english = createEditorNode("char", ENGLISH_VAR);
2491
+ const arabic = createEditorNode("char", ARABIC_VAR);
2492
+ arabic.id = english.id;
2493
+ return { english, arabic };
2494
+ }
2495
+ function withMirroredSuperscript2(english, arabic) {
2496
+ const englishSup = createEditorChain([createEditorNode("number", "2")]);
2497
+ const arabicSup = createEditorChain([createEditorNode("number", "2")]);
2498
+ arabicSup.id = englishSup.id;
2499
+ arabicSup.nodes[0].id = englishSup.nodes[0].id;
2500
+ english.superscript = englishSup;
2501
+ arabic.superscript = arabicSup;
2502
+ }
2503
+ function syncChainIds(english, arabic) {
2504
+ arabic.id = english.id;
2505
+ const limit = Math.min(english.nodes.length, arabic.nodes.length);
2506
+ for (let index = 0; index < limit; index += 1) {
2507
+ arabic.nodes[index].id = english.nodes[index].id;
2508
+ }
2509
+ }
2510
+ function syncFracIds(englishFrac, arabicFrac) {
2511
+ arabicFrac.id = englishFrac.id;
2512
+ if (englishFrac.numerator && arabicFrac.numerator) {
2513
+ syncChainIds(englishFrac.numerator, arabicFrac.numerator);
2514
+ }
2515
+ if (englishFrac.denominator && arabicFrac.denominator) {
2516
+ syncChainIds(englishFrac.denominator, arabicFrac.denominator);
2517
+ }
2518
+ }
2519
+ function buildAdVarChain() {
2520
+ const ad = mirroredAd();
2521
+ const variable = mirroredVar();
2522
+ const english = createEditorChain([ad.english, variable.english]);
2523
+ const arabic = createEditorChain([ad.arabic, variable.arabic]);
2524
+ syncChainIds(english, arabic);
2525
+ return { english, arabic };
2526
+ }
2527
+ function mirroredEmptyDelimiter() {
2528
+ const english = createDelimiterNode("", "");
2529
+ const arabic = createDelimiterNode("", "");
2530
+ arabic.id = english.id;
2531
+ if (english.innerExpr && arabic.innerExpr) {
2532
+ syncChainIds(english.innerExpr, arabic.innerExpr);
2533
+ }
2534
+ return { english, arabic };
2535
+ }
2536
+ function setMirroredDelimiterInner(english, arabic, pairs) {
2537
+ const englishInner = createEditorChain(pairs.map((pair) => pair.english));
2538
+ const arabicInner = createEditorChain(pairs.map((pair) => pair.arabic));
2539
+ syncChainIds(englishInner, arabicInner);
2540
+ english.innerExpr = englishInner;
2541
+ arabic.innerExpr = arabicInner;
2542
+ }
2543
+ function buildFirstDerivativeFrac() {
2544
+ const englishFrac = createFracNode();
2545
+ const arabicFrac = createFracNode();
2546
+ syncFracIds(englishFrac, arabicFrac);
2547
+ const numerator = buildAdVarChain();
2548
+ const denominator = buildAdVarChain();
2549
+ englishFrac.numerator = numerator.english;
2550
+ englishFrac.denominator = denominator.english;
2551
+ arabicFrac.numerator = numerator.arabic;
2552
+ arabicFrac.denominator = denominator.arabic;
2553
+ return { english: englishFrac, arabic: arabicFrac };
2554
+ }
2555
+ function buildSecondDerivativeFrac() {
2556
+ const englishFrac = createFracNode();
2557
+ const arabicFrac = createFracNode();
2558
+ syncFracIds(englishFrac, arabicFrac);
2559
+ const numAd = mirroredAd();
2560
+ const numVar = mirroredVar();
2561
+ withMirroredSuperscript2(numAd.english, numAd.arabic);
2562
+ const englishNumerator = createEditorChain([numAd.english, numVar.english]);
2563
+ const arabicNumerator = createEditorChain([numAd.arabic, numVar.arabic]);
2564
+ syncChainIds(englishNumerator, arabicNumerator);
2565
+ englishFrac.numerator = englishNumerator;
2566
+ arabicFrac.numerator = arabicNumerator;
2567
+ const denGroup = mirroredEmptyDelimiter();
2568
+ const denInnerAd = mirroredAd();
2569
+ const denInnerVar = mirroredVar();
2570
+ setMirroredDelimiterInner(denGroup.english, denGroup.arabic, [
2571
+ { english: denInnerAd.english, arabic: denInnerAd.arabic },
2572
+ { english: denInnerVar.english, arabic: denInnerVar.arabic }
2573
+ ]);
2574
+ withMirroredSuperscript2(denGroup.english, denGroup.arabic);
2575
+ englishFrac.denominator = createEditorChain([denGroup.english]);
2576
+ arabicFrac.denominator = createEditorChain([denGroup.arabic]);
2577
+ syncChainIds(englishFrac.denominator, arabicFrac.denominator);
2578
+ return { english: englishFrac, arabic: arabicFrac };
2579
+ }
2580
+ var DERIVATIVE_TEMPLATE_VAR_CARET_INDEX = 1;
2581
+ function derivativeTemplateInitialCaret(englishFrac) {
2582
+ const denominator = englishFrac.denominator;
2583
+ if (!denominator) {
2584
+ return {
2585
+ chainId: englishFrac.numerator?.id ?? "",
2586
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2587
+ };
2588
+ }
2589
+ const loneDelimiter = denominator.nodes.length === 1 && denominator.nodes[0]?.kind === "delimiter" && denominator.nodes[0].innerExpr;
2590
+ if (loneDelimiter) {
2591
+ return {
2592
+ chainId: denominator.nodes[0].innerExpr.id,
2593
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2594
+ };
2595
+ }
2596
+ return {
2597
+ chainId: denominator.id,
2598
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2599
+ };
2600
+ }
2601
+
2448
2602
  // src/editor/uiLocale.ts
2449
2603
  var ENGLISH_COMMAND_TITLES = {
2450
2604
  cos: "Cosine",
@@ -2475,6 +2629,7 @@ var ENGLISH_COMMAND_TITLES = {
2475
2629
  ln: "Natural logarithm",
2476
2630
  log: "Logarithm",
2477
2631
  det: "Determinant",
2632
+ ad: "Derivative (d / ad)",
2478
2633
  N: "Natural numbers",
2479
2634
  Z: "Integers",
2480
2635
  Q: "Rational numbers",
@@ -2586,6 +2741,10 @@ var EQUATION_EDITOR_MESSAGES = {
2586
2741
  insertFunction: "\u0625\u062F\u0631\u0627\u062C \u062F\u0627\u0644\u0629",
2587
2742
  insertLimitsSeries: "\u0625\u062F\u0631\u0627\u062C \u062D\u062F\u0648\u062F \u0648\u0645\u062A\u0633\u0644\u0633\u0644\u0627\u062A",
2588
2743
  insertAdditionalFunctions: "\u0625\u062F\u0631\u0627\u062C \u062F\u0648\u0627\u0644 \u0625\u0636\u0627\u0641\u064A\u0629",
2744
+ derivatives: "\u0627\u0644\u0627\u0634\u062A\u0642\u0627\u0642",
2745
+ insertDerivative: "\u0625\u062F\u0631\u0627\u062C \u0639\u0644\u0627\u0645\u0629 \u0627\u0634\u062A\u0642\u0627\u0642",
2746
+ insertFirstDerivative: "\u0625\u062F\u0631\u0627\u062C \u0627\u0634\u062A\u0642\u0627\u0642 \u0623\u0648\u0644",
2747
+ insertSecondDerivative: "\u0625\u062F\u0631\u0627\u062C \u0627\u0634\u062A\u0642\u0627\u0642 \u062B\u0627\u0646\u064A",
2589
2748
  insertNumberSets: "\u0625\u062F\u0631\u0627\u062C \u0645\u062C\u0645\u0648\u0639\u0627\u062A \u0623\u0639\u062F\u0627\u062F",
2590
2749
  operations: "\u0627\u0644\u0639\u0645\u0644\u064A\u0627\u062A",
2591
2750
  insertOperation: "\u0625\u062F\u0631\u0627\u062C \u0631\u0645\u0632 \u0639\u0645\u0644\u064A\u0629",
@@ -2689,6 +2848,10 @@ var EQUATION_EDITOR_MESSAGES = {
2689
2848
  insertFunction: "Insert function",
2690
2849
  insertLimitsSeries: "Insert limits and series",
2691
2850
  insertAdditionalFunctions: "Insert additional functions",
2851
+ derivatives: "Derivatives",
2852
+ insertDerivative: "Insert derivative marker",
2853
+ insertFirstDerivative: "Insert first derivative",
2854
+ insertSecondDerivative: "Insert second derivative",
2692
2855
  insertNumberSets: "Insert number sets",
2693
2856
  operations: "Operators",
2694
2857
  insertOperation: "Insert operator",
@@ -3396,10 +3559,27 @@ function insertNumber(session, expr) {
3396
3559
  inserted.forceSplitNextLeaf = false;
3397
3560
  return inserted;
3398
3561
  }
3562
+ function insertDivideOperator(session) {
3563
+ const base = replaceSelectionFirst(session);
3564
+ const next = cloneEditorSession(base);
3565
+ const englishNode = createEditorNode("operator", DIVIDE_OPERATOR_EN);
3566
+ const arabicNode = createEditorNode("operator", DIVIDE_OPERATOR_AR);
3567
+ arabicNode.id = englishNode.id;
3568
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
3569
+ markExprSync(next, englishNode.id);
3570
+ next.caret.index += 1;
3571
+ next.selectedStructureNodeId = null;
3572
+ syncSelectionToCaret(next);
3573
+ appendDebug(next, "insertDivideOperator", "");
3574
+ return next;
3575
+ }
3399
3576
  function insertOperator(session, expr) {
3400
3577
  if (expr === "." && !session.splitLeafTyping && precedingIsExtendableNumber(session)) {
3401
3578
  return insertNumber(session, ".");
3402
3579
  }
3580
+ if (expr === DIVIDE_OPERATOR_EN || expr === DIVIDE_OPERATOR_AR) {
3581
+ return insertDivideOperator(session);
3582
+ }
3403
3583
  const base = replaceSelectionFirst(session);
3404
3584
  return insertLeaf(base, "operator", expr);
3405
3585
  }
@@ -3470,6 +3650,24 @@ function insertFraction(session) {
3470
3650
  appendDebug(next, "insertFraction", "");
3471
3651
  return next;
3472
3652
  }
3653
+ function insertDerivativeFrac(session, build, debugLabel) {
3654
+ const base = replaceSelectionFirst(session);
3655
+ const next = cloneEditorSession(base);
3656
+ const { english, arabic } = build();
3657
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
3658
+ syncSubtreeRecursive(next, english, arabic);
3659
+ next.caret = derivativeTemplateInitialCaret(english);
3660
+ next.selectedStructureNodeId = null;
3661
+ syncSelectionToCaret(next);
3662
+ appendDebug(next, debugLabel, "");
3663
+ return next;
3664
+ }
3665
+ function insertFirstDerivative(session) {
3666
+ return insertDerivativeFrac(session, buildFirstDerivativeFrac, "insertFirstDerivative");
3667
+ }
3668
+ function insertSecondDerivative(session) {
3669
+ return insertDerivativeFrac(session, buildSecondDerivativeFrac, "insertSecondDerivative");
3670
+ }
3473
3671
  function insertSqrt(session) {
3474
3672
  const base = replaceSelectionFirst(session);
3475
3673
  const next = cloneEditorSession(base);
@@ -3940,6 +4138,11 @@ function pasteText(session, text) {
3940
4138
  i += 1;
3941
4139
  continue;
3942
4140
  }
4141
+ if (ch === DIVIDE_OPERATOR_AR) {
4142
+ s = insertDivideOperator(s);
4143
+ i += 1;
4144
+ continue;
4145
+ }
3943
4146
  s = insertChar(s, ch);
3944
4147
  i += 1;
3945
4148
  }
@@ -3947,7 +4150,7 @@ function pasteText(session, text) {
3947
4150
  }
3948
4151
 
3949
4152
  // src/editor/display/base.ts
3950
- function buildBaseNodeBody(node, digitForm = "western") {
4153
+ function buildBaseNodeBody(node, digitForm = "western", side = "english") {
3951
4154
  const value = document.createElement("span");
3952
4155
  value.className = "node-value";
3953
4156
  if (node.kind === "char" && node.characterFont === "takween") {
@@ -3957,7 +4160,8 @@ function buildBaseNodeBody(node, digitForm = "western") {
3957
4160
  } else if (node.kind === "char" && node.characterFont === "diwaniOutline") {
3958
4161
  value.classList.add("node-value--diwani-outline");
3959
4162
  }
3960
- value.textContent = node.expr === "" ? "\u25A1" : formatDigits(node.expr, digitForm);
4163
+ const surfaceExpr = node.kind === "operator" ? divideOperatorSurfaceExpr(node.expr, side) : node.expr;
4164
+ value.textContent = surfaceExpr === "" ? "\u25A1" : formatDigits(surfaceExpr, digitForm);
3961
4165
  return value;
3962
4166
  }
3963
4167
 
@@ -4478,7 +4682,7 @@ function buildFunctionAtomicCommandBody(node, side, spec) {
4478
4682
  value.appendChild(label);
4479
4683
  return value;
4480
4684
  }
4481
- value.textContent = side === "arabic" ? spec?.arabicLabel ?? node.expr : spec?.englishTex.replace("\\", "") ?? node.expr;
4685
+ value.textContent = side === "arabic" ? spec?.arabicLabel ?? node.expr : spec?.englishLabel ?? spec?.englishTex.replace(/^\\/, "") ?? node.expr;
4482
4686
  return value;
4483
4687
  }
4484
4688
  function buildSpacingAtomicCommandBody(spec, side, uiLocale) {
@@ -4604,7 +4808,7 @@ function buildNodeBody(node, buildChain, side, digitForm = "western", uiLocale =
4604
4808
  if (node.kind === "atomicOperatorCommand") {
4605
4809
  return buildAtomicOperatorCommandNodeBody(node, side, uiLocale);
4606
4810
  }
4607
- return buildBaseNodeBody(node, digitForm);
4811
+ return buildBaseNodeBody(node, digitForm, side);
4608
4812
  }
4609
4813
 
4610
4814
  // src/editor/styles.ts
@@ -5322,6 +5526,10 @@ function createEditorRuntime(options) {
5322
5526
  applyStructural((prev) => insertNumber(prev, char));
5323
5527
  return;
5324
5528
  }
5529
+ if (char === "\\") {
5530
+ applyStructural((prev) => insertDivideOperator(prev));
5531
+ return;
5532
+ }
5325
5533
  if (isOperator(char)) {
5326
5534
  applyStructural((prev) => insertOperator(prev, char));
5327
5535
  return;
@@ -5485,6 +5693,14 @@ function createEditorRuntime(options) {
5485
5693
  applyStructural((prev) => insertFraction(prev));
5486
5694
  surfaceEl.focus();
5487
5695
  },
5696
+ insertFirstDerivative: () => {
5697
+ applyStructural((prev) => insertFirstDerivative(prev));
5698
+ surfaceEl.focus();
5699
+ },
5700
+ insertSecondDerivative: () => {
5701
+ applyStructural((prev) => insertSecondDerivative(prev));
5702
+ surfaceEl.focus();
5703
+ },
5488
5704
  insertMatrixEnv: (style, rows, columns) => {
5489
5705
  applyStructural((prev) => insertMatrixEnv(prev, style, rows, columns));
5490
5706
  surfaceEl.focus();
@@ -5552,7 +5768,95 @@ function createEditorRuntime(options) {
5552
5768
  return api;
5553
5769
  }
5554
5770
 
5771
+ // src/document/normalizeCharImport.ts
5772
+ var WRAPPER_SPECS = [
5773
+ { prefix: "\\butexdiwanioutline", font: "diwaniOutline" },
5774
+ { prefix: "\\diwanioutlineshaded", font: "diwaniOutline" },
5775
+ { prefix: "\\butexdiwani", font: "diwani" },
5776
+ { prefix: "\\butextakween", font: "takween" },
5777
+ { prefix: "\\diwani", font: "diwani" },
5778
+ { prefix: "\\takween", font: "takween" },
5779
+ { prefix: "\\text" }
5780
+ ];
5781
+ function readBracedArg(source, openBraceIndex) {
5782
+ if (source[openBraceIndex] !== "{") {
5783
+ return null;
5784
+ }
5785
+ let depth = 0;
5786
+ for (let index = openBraceIndex; index < source.length; index += 1) {
5787
+ const char = source[index];
5788
+ if (char === "{") {
5789
+ depth += 1;
5790
+ } else if (char === "}") {
5791
+ depth -= 1;
5792
+ if (depth === 0) {
5793
+ return { inner: source.slice(openBraceIndex + 1, index), end: index + 1 };
5794
+ }
5795
+ }
5796
+ }
5797
+ return null;
5798
+ }
5799
+ function peelWrapper(source) {
5800
+ for (const wrapper of WRAPPER_SPECS) {
5801
+ if (!source.startsWith(wrapper.prefix)) {
5802
+ continue;
5803
+ }
5804
+ const braced = readBracedArg(source, wrapper.prefix.length);
5805
+ if (!braced || braced.end !== source.length) {
5806
+ continue;
5807
+ }
5808
+ return { inner: braced.inner, font: wrapper.font };
5809
+ }
5810
+ return null;
5811
+ }
5812
+ function normalizeCharImportExpr(expr) {
5813
+ const original = expr;
5814
+ let current = expr;
5815
+ let characterFont = "default";
5816
+ let changed = false;
5817
+ while (true) {
5818
+ const peeled = peelWrapper(current);
5819
+ if (!peeled) {
5820
+ break;
5821
+ }
5822
+ current = peeled.inner;
5823
+ if (peeled.font) {
5824
+ characterFont = peeled.font;
5825
+ }
5826
+ changed = true;
5827
+ }
5828
+ if (!changed) {
5829
+ return { expr: original, characterFont: "default" };
5830
+ }
5831
+ if (current.includes("\\")) {
5832
+ return { expr: original, characterFont: "default" };
5833
+ }
5834
+ return { expr: current, characterFont };
5835
+ }
5836
+
5555
5837
  // src/document/mathEditorAdapter.ts
5838
+ var COMMAND_FONT_MAP = {
5839
+ "\\text": "infer",
5840
+ "\\butextakween": "takween",
5841
+ "\\takween": "takween",
5842
+ "\\butexdiwani": "diwani",
5843
+ "\\diwani": "diwani",
5844
+ "\\butexdiwanioutline": "diwaniOutline",
5845
+ "\\diwanioutlineshaded": "diwaniOutline"
5846
+ };
5847
+ var CHAR_FONT_EXPORT_TEX = {
5848
+ takween: "\\butextakween",
5849
+ diwani: "\\butexdiwani",
5850
+ diwaniOutline: "\\butexdiwanioutline"
5851
+ };
5852
+ function charEditorNodeToAstNode(node) {
5853
+ const font = node.characterFont ?? "default";
5854
+ const charNode = new CharNode(node.expr);
5855
+ if (font === "default") {
5856
+ return charNode;
5857
+ }
5858
+ return new CommandNode(CHAR_FONT_EXPORT_TEX[font], [], [new ChainNode([charNode])]);
5859
+ }
5556
5860
  function commandIdForTex(tex) {
5557
5861
  for (const spec of Object.values(ATOMIC_COMMANDS)) {
5558
5862
  const renderTex = spec.arabicRenderTex;
@@ -5664,6 +5968,42 @@ function envToEditorNode(node) {
5664
5968
  const scripts = attachScripts(node, env);
5665
5969
  return scripts ?? { editable: true, node: env };
5666
5970
  }
5971
+ function charFromTextLikeCommand(node) {
5972
+ const commandFont = COMMAND_FONT_MAP[node.name];
5973
+ if (commandFont === void 0) {
5974
+ return null;
5975
+ }
5976
+ if (node.optionalArgs.length > 0 || node.mandatoryArgs.length !== 1) {
5977
+ return null;
5978
+ }
5979
+ const arg = node.mandatoryArgs[0];
5980
+ if (arg.chain.length !== 1) {
5981
+ return null;
5982
+ }
5983
+ const child = arg.chain[0];
5984
+ if (child instanceof CommandNode) {
5985
+ const nested = charFromTextLikeCommand(child);
5986
+ if (!nested?.editable) {
5987
+ return null;
5988
+ }
5989
+ if (commandFont !== "infer") {
5990
+ nested.node.characterFont = commandFont;
5991
+ }
5992
+ const scripts2 = attachScripts(node, nested.node);
5993
+ return scripts2 ?? nested;
5994
+ }
5995
+ if (!(child instanceof CharNode)) {
5996
+ return null;
5997
+ }
5998
+ const normalized = normalizeCharImportExpr(child.expr);
5999
+ const characterFont = commandFont === "infer" ? normalized.characterFont : commandFont;
6000
+ const editorNode = createEditorNode("char", normalized.expr);
6001
+ if (characterFont !== "default") {
6002
+ editorNode.characterFont = characterFont;
6003
+ }
6004
+ const scripts = attachScripts(node, editorNode);
6005
+ return scripts ?? { editable: true, node: editorNode };
6006
+ }
5667
6007
  function commandToEditorNode(node) {
5668
6008
  if (node.name === "\\frac" && node.mandatoryArgs.length >= 2) {
5669
6009
  const frac = createFracNode();
@@ -5721,11 +6061,19 @@ function commandToEditorNode(node) {
5721
6061
  }
5722
6062
  return { editable: true, node: atomicOperator };
5723
6063
  }
6064
+ const textLike = charFromTextLikeCommand(node);
6065
+ if (textLike) {
6066
+ return textLike;
6067
+ }
5724
6068
  return { editable: false, reason: `\u0623\u0645\u0631 \u0631\u064A\u0627\u0636\u064A \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645 \u062D\u0627\u0644\u064A\u0627: ${node.name}` };
5725
6069
  }
5726
6070
  function astNodeToEditorNode(node) {
5727
6071
  if (node instanceof CharNode) {
5728
- const editorNode = createEditorNode("char", node.expr);
6072
+ const normalized = normalizeCharImportExpr(node.expr);
6073
+ const editorNode = createEditorNode("char", normalized.expr);
6074
+ if (normalized.characterFont !== "default") {
6075
+ editorNode.characterFont = normalized.characterFont;
6076
+ }
5729
6077
  const scripts = attachScripts(node, editorNode);
5730
6078
  return scripts ?? { editable: true, node: editorNode };
5731
6079
  }
@@ -5834,7 +6182,7 @@ function editorEnvToAstNode(node) {
5834
6182
  function editorNodeToAstNode(node) {
5835
6183
  let astNode;
5836
6184
  if (node.kind === "char") {
5837
- astNode = new CharNode(node.expr);
6185
+ astNode = charEditorNodeToAstNode(node);
5838
6186
  } else if (node.kind === "number") {
5839
6187
  astNode = new NumberNode(node.expr);
5840
6188
  } else if (node.kind === "operator") {
@@ -7712,6 +8060,7 @@ var CHARACTER_FONT_OPTIONS = [
7712
8060
  var FUNCTION_COMMANDS = atomicCommandsByCategory("function");
7713
8061
  var LIMITS_SERIES_COMMANDS = atomicCommandsByCategory("limits_series");
7714
8062
  var FUNCTION2_COMMANDS = atomicCommandsByCategory("function2");
8063
+ var DERIVATIVE_COMMANDS = atomicCommandsByCategory("derivative");
7715
8064
  var GROUP_COMMANDS = atomicCommandsByCategory("groups");
7716
8065
  var SPACING_COMMANDS = atomicCommandsByCategory("spacing").filter(isSpacingCommandSpec);
7717
8066
  var OPERATOR_COMMANDS = atomicOperatorCommandsByCategory("operators1");
@@ -7849,6 +8198,7 @@ var ButexEditor = forwardRef(
7849
8198
  const [functionMenuOpen, setFunctionMenuOpen] = useState(false);
7850
8199
  const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = useState(false);
7851
8200
  const [function2MenuOpen, setFunction2MenuOpen] = useState(false);
8201
+ const [derivativeMenuOpen, setDerivativeMenuOpen] = useState(false);
7852
8202
  const [groupMenuOpen, setGroupMenuOpen] = useState(false);
7853
8203
  const [operatorMenuOpen, setOperatorMenuOpen] = useState(false);
7854
8204
  const [operator2MenuOpen, setOperator2MenuOpen] = useState(false);
@@ -8507,6 +8857,87 @@ ${arabic || currentMessages.empty}`;
8507
8857
  ]
8508
8858
  }
8509
8859
  ),
8860
+ /* @__PURE__ */ jsxs(
8861
+ "div",
8862
+ {
8863
+ className: "function-command-menu function-command-menu--derivative",
8864
+ onBlur: (event) => {
8865
+ const nextFocus = event.relatedTarget;
8866
+ if (!(nextFocus instanceof Node) || !event.currentTarget.contains(nextFocus)) {
8867
+ setDerivativeMenuOpen(false);
8868
+ }
8869
+ },
8870
+ children: [
8871
+ /* @__PURE__ */ jsx(
8872
+ "button",
8873
+ {
8874
+ className: "icon-btn function-command-btn",
8875
+ type: "button",
8876
+ title: messages.insertDerivative,
8877
+ "aria-label": messages.insertDerivative,
8878
+ "aria-haspopup": "listbox",
8879
+ "aria-expanded": derivativeMenuOpen,
8880
+ onClick: () => setDerivativeMenuOpen((open) => !open),
8881
+ children: DERIVATIVE_COMMANDS[0]?.arabicLabel ?? "\u0621"
8882
+ }
8883
+ ),
8884
+ /* @__PURE__ */ jsxs("div", { className: "function-command-options", role: "listbox", "aria-label": messages.insertDerivative, hidden: !derivativeMenuOpen, children: [
8885
+ DERIVATIVE_COMMANDS.map((command) => /* @__PURE__ */ jsx(
8886
+ "button",
8887
+ {
8888
+ className: "function-command-option",
8889
+ type: "button",
8890
+ role: "option",
8891
+ title: atomicCommandTitle(command, uiLocale),
8892
+ "aria-label": atomicCommandTitle(command, uiLocale),
8893
+ onMouseDown: (event) => event.preventDefault(),
8894
+ onClick: () => {
8895
+ runtimeRef.current?.insertAtomicCommand(command.id);
8896
+ setDerivativeMenuOpen(false);
8897
+ focusSurface();
8898
+ },
8899
+ children: command.arabicLabel
8900
+ },
8901
+ command.id
8902
+ )),
8903
+ /* @__PURE__ */ jsx(
8904
+ "button",
8905
+ {
8906
+ className: "function-command-option",
8907
+ type: "button",
8908
+ role: "option",
8909
+ title: messages.insertFirstDerivative,
8910
+ "aria-label": messages.insertFirstDerivative,
8911
+ onMouseDown: (event) => event.preventDefault(),
8912
+ onClick: () => {
8913
+ runtimeRef.current?.insertFirstDerivative();
8914
+ setDerivativeMenuOpen(false);
8915
+ focusSurface();
8916
+ },
8917
+ children: "\u0621/\u0633"
8918
+ }
8919
+ ),
8920
+ /* @__PURE__ */ jsx(
8921
+ "button",
8922
+ {
8923
+ className: "function-command-option",
8924
+ type: "button",
8925
+ role: "option",
8926
+ title: messages.insertSecondDerivative,
8927
+ "aria-label": messages.insertSecondDerivative,
8928
+ onMouseDown: (event) => event.preventDefault(),
8929
+ onClick: () => {
8930
+ runtimeRef.current?.insertSecondDerivative();
8931
+ setDerivativeMenuOpen(false);
8932
+ focusSurface();
8933
+ },
8934
+ children: "\u0621\xB2/\u0633\xB2"
8935
+ }
8936
+ )
8937
+ ] })
8938
+ ]
8939
+ }
8940
+ ),
8510
8941
  /* @__PURE__ */ jsxs(
8511
8942
  "div",
8512
8943
  {