@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.
@@ -935,6 +935,16 @@ var ATOMIC_COMMANDS = {
935
935
  arabicLabel: "\u0645\u062D\u062F\u062F",
936
936
  title: "\u0645\u062D\u062F\u062F"
937
937
  },
938
+ ////////////////////// Derivatives ////////////////////////////////
939
+ ad: {
940
+ id: "ad",
941
+ category: "derivative",
942
+ englishTex: "\\mathrm{d}",
943
+ englishLabel: "d",
944
+ arabicTex: "\\ad",
945
+ arabicLabel: "\u0621",
946
+ title: "\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0627\u0634\u062A\u0642\u0627\u0642"
947
+ },
938
948
  ////////////////////// Groups /////////////////////////////////
939
949
  N: {
940
950
  id: "N",
@@ -1758,6 +1768,22 @@ function createEditorSession(englishTree, arabicTree, activeSide = "arabic") {
1758
1768
  };
1759
1769
  }
1760
1770
 
1771
+ // src/editor/divideOperator.ts
1772
+ var DIVIDE_OPERATOR_EN = "/";
1773
+ var DIVIDE_OPERATOR_AR = "\\";
1774
+ function isDivideOperatorExpr(expr) {
1775
+ return expr === DIVIDE_OPERATOR_EN || expr === DIVIDE_OPERATOR_AR;
1776
+ }
1777
+ function divideOperatorSurfaceExpr(expr, side) {
1778
+ if (!isDivideOperatorExpr(expr)) {
1779
+ return expr;
1780
+ }
1781
+ return side === "arabic" ? DIVIDE_OPERATOR_AR : DIVIDE_OPERATOR_EN;
1782
+ }
1783
+ function renderDivideOperatorLatex(side) {
1784
+ return side === "arabic" ? "\\backslash" : DIVIDE_OPERATOR_EN;
1785
+ }
1786
+
1761
1787
  // src/editor/digits.ts
1762
1788
  var WESTERN = "0123456789";
1763
1789
  var ARABIC_INDIC = "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669";
@@ -1906,6 +1932,9 @@ function renderNodeEnglish(node, options) {
1906
1932
  if (node.kind === "char") {
1907
1933
  return `${renderCharContent(node, options)}${latinScripts(node, options)}`;
1908
1934
  }
1935
+ if (node.kind === "operator" && isDivideOperatorExpr(node.expr)) {
1936
+ return `${renderDivideOperatorLatex("english")}${latinScripts(node, options)}`;
1937
+ }
1909
1938
  return `${formatDigits(node.expr, selectedDigitForm(options))}${latinScripts(node, options)}`;
1910
1939
  }
1911
1940
  function renderNodeArabic(node, options) {
@@ -1940,6 +1969,9 @@ function renderNodeArabic(node, options) {
1940
1969
  const content = renderCharContent(node, options);
1941
1970
  return arabicScripts(node, (node.characterFont ?? "default") === "default" ? `\\text{${escapeText(expr)}}` : content, options);
1942
1971
  }
1972
+ if (node.kind === "operator" && isDivideOperatorExpr(node.expr)) {
1973
+ return arabicScripts(node, renderDivideOperatorLatex("arabic"), options);
1974
+ }
1943
1975
  return arabicScripts(node, formatDigits(node.expr, selectedDigitForm(options)), options);
1944
1976
  }
1945
1977
  function renderChainEnglish(chain, options) {
@@ -2463,6 +2495,128 @@ function undoRedoCanRedo(stacks) {
2463
2495
  return stacks.future.length > 0;
2464
2496
  }
2465
2497
 
2498
+ // src/editor/derivativeTemplates.ts
2499
+ var ARABIC_VAR = "\u0633";
2500
+ var ENGLISH_VAR = "x";
2501
+ function mirroredAd() {
2502
+ const english = createAtomicCommandNode("ad");
2503
+ const arabic = createAtomicCommandNode("ad");
2504
+ arabic.id = english.id;
2505
+ return { english, arabic };
2506
+ }
2507
+ function mirroredVar() {
2508
+ const english = createEditorNode("char", ENGLISH_VAR);
2509
+ const arabic = createEditorNode("char", ARABIC_VAR);
2510
+ arabic.id = english.id;
2511
+ return { english, arabic };
2512
+ }
2513
+ function withMirroredSuperscript2(english, arabic) {
2514
+ const englishSup = createEditorChain([createEditorNode("number", "2")]);
2515
+ const arabicSup = createEditorChain([createEditorNode("number", "2")]);
2516
+ arabicSup.id = englishSup.id;
2517
+ arabicSup.nodes[0].id = englishSup.nodes[0].id;
2518
+ english.superscript = englishSup;
2519
+ arabic.superscript = arabicSup;
2520
+ }
2521
+ function syncChainIds(english, arabic) {
2522
+ arabic.id = english.id;
2523
+ const limit = Math.min(english.nodes.length, arabic.nodes.length);
2524
+ for (let index = 0; index < limit; index += 1) {
2525
+ arabic.nodes[index].id = english.nodes[index].id;
2526
+ }
2527
+ }
2528
+ function syncFracIds(englishFrac, arabicFrac) {
2529
+ arabicFrac.id = englishFrac.id;
2530
+ if (englishFrac.numerator && arabicFrac.numerator) {
2531
+ syncChainIds(englishFrac.numerator, arabicFrac.numerator);
2532
+ }
2533
+ if (englishFrac.denominator && arabicFrac.denominator) {
2534
+ syncChainIds(englishFrac.denominator, arabicFrac.denominator);
2535
+ }
2536
+ }
2537
+ function buildAdVarChain() {
2538
+ const ad = mirroredAd();
2539
+ const variable = mirroredVar();
2540
+ const english = createEditorChain([ad.english, variable.english]);
2541
+ const arabic = createEditorChain([ad.arabic, variable.arabic]);
2542
+ syncChainIds(english, arabic);
2543
+ return { english, arabic };
2544
+ }
2545
+ function mirroredEmptyDelimiter() {
2546
+ const english = createDelimiterNode("", "");
2547
+ const arabic = createDelimiterNode("", "");
2548
+ arabic.id = english.id;
2549
+ if (english.innerExpr && arabic.innerExpr) {
2550
+ syncChainIds(english.innerExpr, arabic.innerExpr);
2551
+ }
2552
+ return { english, arabic };
2553
+ }
2554
+ function setMirroredDelimiterInner(english, arabic, pairs) {
2555
+ const englishInner = createEditorChain(pairs.map((pair) => pair.english));
2556
+ const arabicInner = createEditorChain(pairs.map((pair) => pair.arabic));
2557
+ syncChainIds(englishInner, arabicInner);
2558
+ english.innerExpr = englishInner;
2559
+ arabic.innerExpr = arabicInner;
2560
+ }
2561
+ function buildFirstDerivativeFrac() {
2562
+ const englishFrac = createFracNode();
2563
+ const arabicFrac = createFracNode();
2564
+ syncFracIds(englishFrac, arabicFrac);
2565
+ const numerator = buildAdVarChain();
2566
+ const denominator = buildAdVarChain();
2567
+ englishFrac.numerator = numerator.english;
2568
+ englishFrac.denominator = denominator.english;
2569
+ arabicFrac.numerator = numerator.arabic;
2570
+ arabicFrac.denominator = denominator.arabic;
2571
+ return { english: englishFrac, arabic: arabicFrac };
2572
+ }
2573
+ function buildSecondDerivativeFrac() {
2574
+ const englishFrac = createFracNode();
2575
+ const arabicFrac = createFracNode();
2576
+ syncFracIds(englishFrac, arabicFrac);
2577
+ const numAd = mirroredAd();
2578
+ const numVar = mirroredVar();
2579
+ withMirroredSuperscript2(numAd.english, numAd.arabic);
2580
+ const englishNumerator = createEditorChain([numAd.english, numVar.english]);
2581
+ const arabicNumerator = createEditorChain([numAd.arabic, numVar.arabic]);
2582
+ syncChainIds(englishNumerator, arabicNumerator);
2583
+ englishFrac.numerator = englishNumerator;
2584
+ arabicFrac.numerator = arabicNumerator;
2585
+ const denGroup = mirroredEmptyDelimiter();
2586
+ const denInnerAd = mirroredAd();
2587
+ const denInnerVar = mirroredVar();
2588
+ setMirroredDelimiterInner(denGroup.english, denGroup.arabic, [
2589
+ { english: denInnerAd.english, arabic: denInnerAd.arabic },
2590
+ { english: denInnerVar.english, arabic: denInnerVar.arabic }
2591
+ ]);
2592
+ withMirroredSuperscript2(denGroup.english, denGroup.arabic);
2593
+ englishFrac.denominator = createEditorChain([denGroup.english]);
2594
+ arabicFrac.denominator = createEditorChain([denGroup.arabic]);
2595
+ syncChainIds(englishFrac.denominator, arabicFrac.denominator);
2596
+ return { english: englishFrac, arabic: arabicFrac };
2597
+ }
2598
+ var DERIVATIVE_TEMPLATE_VAR_CARET_INDEX = 1;
2599
+ function derivativeTemplateInitialCaret(englishFrac) {
2600
+ const denominator = englishFrac.denominator;
2601
+ if (!denominator) {
2602
+ return {
2603
+ chainId: englishFrac.numerator?.id ?? "",
2604
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2605
+ };
2606
+ }
2607
+ const loneDelimiter = denominator.nodes.length === 1 && denominator.nodes[0]?.kind === "delimiter" && denominator.nodes[0].innerExpr;
2608
+ if (loneDelimiter) {
2609
+ return {
2610
+ chainId: denominator.nodes[0].innerExpr.id,
2611
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2612
+ };
2613
+ }
2614
+ return {
2615
+ chainId: denominator.id,
2616
+ index: DERIVATIVE_TEMPLATE_VAR_CARET_INDEX
2617
+ };
2618
+ }
2619
+
2466
2620
  // src/editor/uiLocale.ts
2467
2621
  var ENGLISH_COMMAND_TITLES = {
2468
2622
  cos: "Cosine",
@@ -2493,6 +2647,7 @@ var ENGLISH_COMMAND_TITLES = {
2493
2647
  ln: "Natural logarithm",
2494
2648
  log: "Logarithm",
2495
2649
  det: "Determinant",
2650
+ ad: "Derivative (d / ad)",
2496
2651
  N: "Natural numbers",
2497
2652
  Z: "Integers",
2498
2653
  Q: "Rational numbers",
@@ -2604,6 +2759,10 @@ var EQUATION_EDITOR_MESSAGES = {
2604
2759
  insertFunction: "\u0625\u062F\u0631\u0627\u062C \u062F\u0627\u0644\u0629",
2605
2760
  insertLimitsSeries: "\u0625\u062F\u0631\u0627\u062C \u062D\u062F\u0648\u062F \u0648\u0645\u062A\u0633\u0644\u0633\u0644\u0627\u062A",
2606
2761
  insertAdditionalFunctions: "\u0625\u062F\u0631\u0627\u062C \u062F\u0648\u0627\u0644 \u0625\u0636\u0627\u0641\u064A\u0629",
2762
+ derivatives: "\u0627\u0644\u0627\u0634\u062A\u0642\u0627\u0642",
2763
+ insertDerivative: "\u0625\u062F\u0631\u0627\u062C \u0639\u0644\u0627\u0645\u0629 \u0627\u0634\u062A\u0642\u0627\u0642",
2764
+ insertFirstDerivative: "\u0625\u062F\u0631\u0627\u062C \u0627\u0634\u062A\u0642\u0627\u0642 \u0623\u0648\u0644",
2765
+ insertSecondDerivative: "\u0625\u062F\u0631\u0627\u062C \u0627\u0634\u062A\u0642\u0627\u0642 \u062B\u0627\u0646\u064A",
2607
2766
  insertNumberSets: "\u0625\u062F\u0631\u0627\u062C \u0645\u062C\u0645\u0648\u0639\u0627\u062A \u0623\u0639\u062F\u0627\u062F",
2608
2767
  operations: "\u0627\u0644\u0639\u0645\u0644\u064A\u0627\u062A",
2609
2768
  insertOperation: "\u0625\u062F\u0631\u0627\u062C \u0631\u0645\u0632 \u0639\u0645\u0644\u064A\u0629",
@@ -2707,6 +2866,10 @@ var EQUATION_EDITOR_MESSAGES = {
2707
2866
  insertFunction: "Insert function",
2708
2867
  insertLimitsSeries: "Insert limits and series",
2709
2868
  insertAdditionalFunctions: "Insert additional functions",
2869
+ derivatives: "Derivatives",
2870
+ insertDerivative: "Insert derivative marker",
2871
+ insertFirstDerivative: "Insert first derivative",
2872
+ insertSecondDerivative: "Insert second derivative",
2710
2873
  insertNumberSets: "Insert number sets",
2711
2874
  operations: "Operators",
2712
2875
  insertOperation: "Insert operator",
@@ -3414,10 +3577,27 @@ function insertNumber(session, expr) {
3414
3577
  inserted.forceSplitNextLeaf = false;
3415
3578
  return inserted;
3416
3579
  }
3580
+ function insertDivideOperator(session) {
3581
+ const base = replaceSelectionFirst(session);
3582
+ const next = cloneEditorSession(base);
3583
+ const englishNode = createEditorNode("operator", DIVIDE_OPERATOR_EN);
3584
+ const arabicNode = createEditorNode("operator", DIVIDE_OPERATOR_AR);
3585
+ arabicNode.id = englishNode.id;
3586
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, englishNode, arabicNode);
3587
+ markExprSync(next, englishNode.id);
3588
+ next.caret.index += 1;
3589
+ next.selectedStructureNodeId = null;
3590
+ syncSelectionToCaret(next);
3591
+ appendDebug(next, "insertDivideOperator", "");
3592
+ return next;
3593
+ }
3417
3594
  function insertOperator(session, expr) {
3418
3595
  if (expr === "." && !session.splitLeafTyping && precedingIsExtendableNumber(session)) {
3419
3596
  return insertNumber(session, ".");
3420
3597
  }
3598
+ if (expr === DIVIDE_OPERATOR_EN || expr === DIVIDE_OPERATOR_AR) {
3599
+ return insertDivideOperator(session);
3600
+ }
3421
3601
  const base = replaceSelectionFirst(session);
3422
3602
  return insertLeaf(base, "operator", expr);
3423
3603
  }
@@ -3488,6 +3668,24 @@ function insertFraction(session) {
3488
3668
  appendDebug(next, "insertFraction", "");
3489
3669
  return next;
3490
3670
  }
3671
+ function insertDerivativeFrac(session, build, debugLabel) {
3672
+ const base = replaceSelectionFirst(session);
3673
+ const next = cloneEditorSession(base);
3674
+ const { english, arabic } = build();
3675
+ insertMirroredNode(next, next.caret.chainId, next.caret.index, english, arabic);
3676
+ syncSubtreeRecursive(next, english, arabic);
3677
+ next.caret = derivativeTemplateInitialCaret(english);
3678
+ next.selectedStructureNodeId = null;
3679
+ syncSelectionToCaret(next);
3680
+ appendDebug(next, debugLabel, "");
3681
+ return next;
3682
+ }
3683
+ function insertFirstDerivative(session) {
3684
+ return insertDerivativeFrac(session, buildFirstDerivativeFrac, "insertFirstDerivative");
3685
+ }
3686
+ function insertSecondDerivative(session) {
3687
+ return insertDerivativeFrac(session, buildSecondDerivativeFrac, "insertSecondDerivative");
3688
+ }
3491
3689
  function insertSqrt(session) {
3492
3690
  const base = replaceSelectionFirst(session);
3493
3691
  const next = cloneEditorSession(base);
@@ -3958,6 +4156,11 @@ function pasteText(session, text) {
3958
4156
  i += 1;
3959
4157
  continue;
3960
4158
  }
4159
+ if (ch === DIVIDE_OPERATOR_AR) {
4160
+ s = insertDivideOperator(s);
4161
+ i += 1;
4162
+ continue;
4163
+ }
3961
4164
  s = insertChar(s, ch);
3962
4165
  i += 1;
3963
4166
  }
@@ -3965,7 +4168,7 @@ function pasteText(session, text) {
3965
4168
  }
3966
4169
 
3967
4170
  // src/editor/display/base.ts
3968
- function buildBaseNodeBody(node, digitForm = "western") {
4171
+ function buildBaseNodeBody(node, digitForm = "western", side = "english") {
3969
4172
  const value = document.createElement("span");
3970
4173
  value.className = "node-value";
3971
4174
  if (node.kind === "char" && node.characterFont === "takween") {
@@ -3975,7 +4178,8 @@ function buildBaseNodeBody(node, digitForm = "western") {
3975
4178
  } else if (node.kind === "char" && node.characterFont === "diwaniOutline") {
3976
4179
  value.classList.add("node-value--diwani-outline");
3977
4180
  }
3978
- value.textContent = node.expr === "" ? "\u25A1" : formatDigits(node.expr, digitForm);
4181
+ const surfaceExpr = node.kind === "operator" ? divideOperatorSurfaceExpr(node.expr, side) : node.expr;
4182
+ value.textContent = surfaceExpr === "" ? "\u25A1" : formatDigits(surfaceExpr, digitForm);
3979
4183
  return value;
3980
4184
  }
3981
4185
 
@@ -4496,7 +4700,7 @@ function buildFunctionAtomicCommandBody(node, side, spec) {
4496
4700
  value.appendChild(label);
4497
4701
  return value;
4498
4702
  }
4499
- value.textContent = side === "arabic" ? spec?.arabicLabel ?? node.expr : spec?.englishTex.replace("\\", "") ?? node.expr;
4703
+ value.textContent = side === "arabic" ? spec?.arabicLabel ?? node.expr : spec?.englishLabel ?? spec?.englishTex.replace(/^\\/, "") ?? node.expr;
4500
4704
  return value;
4501
4705
  }
4502
4706
  function buildSpacingAtomicCommandBody(spec, side, uiLocale) {
@@ -4622,7 +4826,7 @@ function buildNodeBody(node, buildChain, side, digitForm = "western", uiLocale =
4622
4826
  if (node.kind === "atomicOperatorCommand") {
4623
4827
  return buildAtomicOperatorCommandNodeBody(node, side, uiLocale);
4624
4828
  }
4625
- return buildBaseNodeBody(node, digitForm);
4829
+ return buildBaseNodeBody(node, digitForm, side);
4626
4830
  }
4627
4831
 
4628
4832
  // src/editor/styles.ts
@@ -5340,6 +5544,10 @@ function createEditorRuntime(options) {
5340
5544
  applyStructural((prev) => insertNumber(prev, char));
5341
5545
  return;
5342
5546
  }
5547
+ if (char === "\\") {
5548
+ applyStructural((prev) => insertDivideOperator(prev));
5549
+ return;
5550
+ }
5343
5551
  if (isOperator(char)) {
5344
5552
  applyStructural((prev) => insertOperator(prev, char));
5345
5553
  return;
@@ -5503,6 +5711,14 @@ function createEditorRuntime(options) {
5503
5711
  applyStructural((prev) => insertFraction(prev));
5504
5712
  surfaceEl.focus();
5505
5713
  },
5714
+ insertFirstDerivative: () => {
5715
+ applyStructural((prev) => insertFirstDerivative(prev));
5716
+ surfaceEl.focus();
5717
+ },
5718
+ insertSecondDerivative: () => {
5719
+ applyStructural((prev) => insertSecondDerivative(prev));
5720
+ surfaceEl.focus();
5721
+ },
5506
5722
  insertMatrixEnv: (style, rows, columns) => {
5507
5723
  applyStructural((prev) => insertMatrixEnv(prev, style, rows, columns));
5508
5724
  surfaceEl.focus();
@@ -5570,7 +5786,95 @@ function createEditorRuntime(options) {
5570
5786
  return api;
5571
5787
  }
5572
5788
 
5789
+ // src/document/normalizeCharImport.ts
5790
+ var WRAPPER_SPECS = [
5791
+ { prefix: "\\butexdiwanioutline", font: "diwaniOutline" },
5792
+ { prefix: "\\diwanioutlineshaded", font: "diwaniOutline" },
5793
+ { prefix: "\\butexdiwani", font: "diwani" },
5794
+ { prefix: "\\butextakween", font: "takween" },
5795
+ { prefix: "\\diwani", font: "diwani" },
5796
+ { prefix: "\\takween", font: "takween" },
5797
+ { prefix: "\\text" }
5798
+ ];
5799
+ function readBracedArg(source, openBraceIndex) {
5800
+ if (source[openBraceIndex] !== "{") {
5801
+ return null;
5802
+ }
5803
+ let depth = 0;
5804
+ for (let index = openBraceIndex; index < source.length; index += 1) {
5805
+ const char = source[index];
5806
+ if (char === "{") {
5807
+ depth += 1;
5808
+ } else if (char === "}") {
5809
+ depth -= 1;
5810
+ if (depth === 0) {
5811
+ return { inner: source.slice(openBraceIndex + 1, index), end: index + 1 };
5812
+ }
5813
+ }
5814
+ }
5815
+ return null;
5816
+ }
5817
+ function peelWrapper(source) {
5818
+ for (const wrapper of WRAPPER_SPECS) {
5819
+ if (!source.startsWith(wrapper.prefix)) {
5820
+ continue;
5821
+ }
5822
+ const braced = readBracedArg(source, wrapper.prefix.length);
5823
+ if (!braced || braced.end !== source.length) {
5824
+ continue;
5825
+ }
5826
+ return { inner: braced.inner, font: wrapper.font };
5827
+ }
5828
+ return null;
5829
+ }
5830
+ function normalizeCharImportExpr(expr) {
5831
+ const original = expr;
5832
+ let current = expr;
5833
+ let characterFont = "default";
5834
+ let changed = false;
5835
+ while (true) {
5836
+ const peeled = peelWrapper(current);
5837
+ if (!peeled) {
5838
+ break;
5839
+ }
5840
+ current = peeled.inner;
5841
+ if (peeled.font) {
5842
+ characterFont = peeled.font;
5843
+ }
5844
+ changed = true;
5845
+ }
5846
+ if (!changed) {
5847
+ return { expr: original, characterFont: "default" };
5848
+ }
5849
+ if (current.includes("\\")) {
5850
+ return { expr: original, characterFont: "default" };
5851
+ }
5852
+ return { expr: current, characterFont };
5853
+ }
5854
+
5573
5855
  // src/document/mathEditorAdapter.ts
5856
+ var COMMAND_FONT_MAP = {
5857
+ "\\text": "infer",
5858
+ "\\butextakween": "takween",
5859
+ "\\takween": "takween",
5860
+ "\\butexdiwani": "diwani",
5861
+ "\\diwani": "diwani",
5862
+ "\\butexdiwanioutline": "diwaniOutline",
5863
+ "\\diwanioutlineshaded": "diwaniOutline"
5864
+ };
5865
+ var CHAR_FONT_EXPORT_TEX = {
5866
+ takween: "\\butextakween",
5867
+ diwani: "\\butexdiwani",
5868
+ diwaniOutline: "\\butexdiwanioutline"
5869
+ };
5870
+ function charEditorNodeToAstNode(node) {
5871
+ const font = node.characterFont ?? "default";
5872
+ const charNode = new CharNode(node.expr);
5873
+ if (font === "default") {
5874
+ return charNode;
5875
+ }
5876
+ return new CommandNode(CHAR_FONT_EXPORT_TEX[font], [], [new ChainNode([charNode])]);
5877
+ }
5574
5878
  function commandIdForTex(tex) {
5575
5879
  for (const spec of Object.values(ATOMIC_COMMANDS)) {
5576
5880
  const renderTex = spec.arabicRenderTex;
@@ -5682,6 +5986,42 @@ function envToEditorNode(node) {
5682
5986
  const scripts = attachScripts(node, env);
5683
5987
  return scripts ?? { editable: true, node: env };
5684
5988
  }
5989
+ function charFromTextLikeCommand(node) {
5990
+ const commandFont = COMMAND_FONT_MAP[node.name];
5991
+ if (commandFont === void 0) {
5992
+ return null;
5993
+ }
5994
+ if (node.optionalArgs.length > 0 || node.mandatoryArgs.length !== 1) {
5995
+ return null;
5996
+ }
5997
+ const arg = node.mandatoryArgs[0];
5998
+ if (arg.chain.length !== 1) {
5999
+ return null;
6000
+ }
6001
+ const child = arg.chain[0];
6002
+ if (child instanceof CommandNode) {
6003
+ const nested = charFromTextLikeCommand(child);
6004
+ if (!nested?.editable) {
6005
+ return null;
6006
+ }
6007
+ if (commandFont !== "infer") {
6008
+ nested.node.characterFont = commandFont;
6009
+ }
6010
+ const scripts2 = attachScripts(node, nested.node);
6011
+ return scripts2 ?? nested;
6012
+ }
6013
+ if (!(child instanceof CharNode)) {
6014
+ return null;
6015
+ }
6016
+ const normalized = normalizeCharImportExpr(child.expr);
6017
+ const characterFont = commandFont === "infer" ? normalized.characterFont : commandFont;
6018
+ const editorNode = createEditorNode("char", normalized.expr);
6019
+ if (characterFont !== "default") {
6020
+ editorNode.characterFont = characterFont;
6021
+ }
6022
+ const scripts = attachScripts(node, editorNode);
6023
+ return scripts ?? { editable: true, node: editorNode };
6024
+ }
5685
6025
  function commandToEditorNode(node) {
5686
6026
  if (node.name === "\\frac" && node.mandatoryArgs.length >= 2) {
5687
6027
  const frac = createFracNode();
@@ -5739,11 +6079,19 @@ function commandToEditorNode(node) {
5739
6079
  }
5740
6080
  return { editable: true, node: atomicOperator };
5741
6081
  }
6082
+ const textLike = charFromTextLikeCommand(node);
6083
+ if (textLike) {
6084
+ return textLike;
6085
+ }
5742
6086
  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}` };
5743
6087
  }
5744
6088
  function astNodeToEditorNode(node) {
5745
6089
  if (node instanceof CharNode) {
5746
- const editorNode = createEditorNode("char", node.expr);
6090
+ const normalized = normalizeCharImportExpr(node.expr);
6091
+ const editorNode = createEditorNode("char", normalized.expr);
6092
+ if (normalized.characterFont !== "default") {
6093
+ editorNode.characterFont = normalized.characterFont;
6094
+ }
5747
6095
  const scripts = attachScripts(node, editorNode);
5748
6096
  return scripts ?? { editable: true, node: editorNode };
5749
6097
  }
@@ -5852,7 +6200,7 @@ function editorEnvToAstNode(node) {
5852
6200
  function editorNodeToAstNode(node) {
5853
6201
  let astNode;
5854
6202
  if (node.kind === "char") {
5855
- astNode = new CharNode(node.expr);
6203
+ astNode = charEditorNodeToAstNode(node);
5856
6204
  } else if (node.kind === "number") {
5857
6205
  astNode = new NumberNode(node.expr);
5858
6206
  } else if (node.kind === "operator") {
@@ -8653,6 +9001,7 @@ var CHARACTER_FONT_OPTIONS = [
8653
9001
  var FUNCTION_COMMANDS = atomicCommandsByCategory("function");
8654
9002
  var LIMITS_SERIES_COMMANDS = atomicCommandsByCategory("limits_series");
8655
9003
  var FUNCTION2_COMMANDS = atomicCommandsByCategory("function2");
9004
+ var DERIVATIVE_COMMANDS = atomicCommandsByCategory("derivative");
8656
9005
  var GROUP_COMMANDS = atomicCommandsByCategory("groups");
8657
9006
  var SPACING_COMMANDS = atomicCommandsByCategory("spacing").filter(isSpacingCommandSpec);
8658
9007
  var OPERATOR_COMMANDS = atomicOperatorCommandsByCategory("operators1");
@@ -8790,6 +9139,7 @@ var ButexEditor = forwardRef(
8790
9139
  const [functionMenuOpen, setFunctionMenuOpen] = useState3(false);
8791
9140
  const [limitsSeriesMenuOpen, setLimitsSeriesMenuOpen] = useState3(false);
8792
9141
  const [function2MenuOpen, setFunction2MenuOpen] = useState3(false);
9142
+ const [derivativeMenuOpen, setDerivativeMenuOpen] = useState3(false);
8793
9143
  const [groupMenuOpen, setGroupMenuOpen] = useState3(false);
8794
9144
  const [operatorMenuOpen, setOperatorMenuOpen] = useState3(false);
8795
9145
  const [operator2MenuOpen, setOperator2MenuOpen] = useState3(false);
@@ -9448,6 +9798,87 @@ ${arabic || currentMessages.empty}`;
9448
9798
  ]
9449
9799
  }
9450
9800
  ),
9801
+ /* @__PURE__ */ jsxs6(
9802
+ "div",
9803
+ {
9804
+ className: "function-command-menu function-command-menu--derivative",
9805
+ onBlur: (event) => {
9806
+ const nextFocus = event.relatedTarget;
9807
+ if (!(nextFocus instanceof Node) || !event.currentTarget.contains(nextFocus)) {
9808
+ setDerivativeMenuOpen(false);
9809
+ }
9810
+ },
9811
+ children: [
9812
+ /* @__PURE__ */ jsx8(
9813
+ "button",
9814
+ {
9815
+ className: "icon-btn function-command-btn",
9816
+ type: "button",
9817
+ title: messages.insertDerivative,
9818
+ "aria-label": messages.insertDerivative,
9819
+ "aria-haspopup": "listbox",
9820
+ "aria-expanded": derivativeMenuOpen,
9821
+ onClick: () => setDerivativeMenuOpen((open) => !open),
9822
+ children: DERIVATIVE_COMMANDS[0]?.arabicLabel ?? "\u0621"
9823
+ }
9824
+ ),
9825
+ /* @__PURE__ */ jsxs6("div", { className: "function-command-options", role: "listbox", "aria-label": messages.insertDerivative, hidden: !derivativeMenuOpen, children: [
9826
+ DERIVATIVE_COMMANDS.map((command) => /* @__PURE__ */ jsx8(
9827
+ "button",
9828
+ {
9829
+ className: "function-command-option",
9830
+ type: "button",
9831
+ role: "option",
9832
+ title: atomicCommandTitle(command, uiLocale),
9833
+ "aria-label": atomicCommandTitle(command, uiLocale),
9834
+ onMouseDown: (event) => event.preventDefault(),
9835
+ onClick: () => {
9836
+ runtimeRef.current?.insertAtomicCommand(command.id);
9837
+ setDerivativeMenuOpen(false);
9838
+ focusSurface();
9839
+ },
9840
+ children: command.arabicLabel
9841
+ },
9842
+ command.id
9843
+ )),
9844
+ /* @__PURE__ */ jsx8(
9845
+ "button",
9846
+ {
9847
+ className: "function-command-option",
9848
+ type: "button",
9849
+ role: "option",
9850
+ title: messages.insertFirstDerivative,
9851
+ "aria-label": messages.insertFirstDerivative,
9852
+ onMouseDown: (event) => event.preventDefault(),
9853
+ onClick: () => {
9854
+ runtimeRef.current?.insertFirstDerivative();
9855
+ setDerivativeMenuOpen(false);
9856
+ focusSurface();
9857
+ },
9858
+ children: "\u0621/\u0633"
9859
+ }
9860
+ ),
9861
+ /* @__PURE__ */ jsx8(
9862
+ "button",
9863
+ {
9864
+ className: "function-command-option",
9865
+ type: "button",
9866
+ role: "option",
9867
+ title: messages.insertSecondDerivative,
9868
+ "aria-label": messages.insertSecondDerivative,
9869
+ onMouseDown: (event) => event.preventDefault(),
9870
+ onClick: () => {
9871
+ runtimeRef.current?.insertSecondDerivative();
9872
+ setDerivativeMenuOpen(false);
9873
+ focusSurface();
9874
+ },
9875
+ children: "\u0621\xB2/\u0633\xB2"
9876
+ }
9877
+ )
9878
+ ] })
9879
+ ]
9880
+ }
9881
+ ),
9451
9882
  /* @__PURE__ */ jsxs6(
9452
9883
  "div",
9453
9884
  {