@drghaliasri/butex 5.5.4 → 5.6.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.
@@ -83,21 +83,26 @@ var BUTEX_CLOSING_HAMDALA = "\u0627\u0644\u0652\u062D\u064E\u0645\u0652\u062F\u0
83
83
  function escapeButexTextArg(text) {
84
84
  return text.replace(/\\/g, "\\textbackslash{}").replace(/[{}]/g, "\\$&");
85
85
  }
86
- function butexDiwaniDisplayTex(text) {
87
- return `\\butexdiwani{${escapeButexTextArg(text)}}`;
86
+ function butexFontDisplayTex(macro, text) {
87
+ return `${macro}{${escapeButexTextArg(text)}}`;
88
88
  }
89
- function butexDiwaniDisplayLatex(text) {
89
+ function butexMaghribiDisplayTex(text) {
90
+ return butexFontDisplayTex("\\butexmaghribi", text);
91
+ }
92
+ function butexMaghribiDisplayLatex(text) {
90
93
  return `\\[
91
- ${butexDiwaniDisplayTex(text)}
94
+ ${butexMaghribiDisplayTex(text)}
92
95
  \\]`;
93
96
  }
94
97
  var BASMALA_LINES = [BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT];
95
98
  function butexBasmalaDisplayTex() {
96
- return BASMALA_LINES.map((line) => butexDiwaniDisplayTex(line)).join(" \\\\ ");
99
+ return BASMALA_LINES.map((line) => butexMaghribiDisplayTex(line)).join(" \\\\ ");
97
100
  }
98
101
  function butexBasmalaDisplayLatex() {
99
102
  return `\\[
100
- ${butexBasmalaDisplayTex()}
103
+ \\begin{gathered}
104
+ ${BASMALA_LINES.map((line) => butexMaghribiDisplayTex(line)).join(" \\\\\n")}
105
+ \\end{gathered}
101
106
  \\]`;
102
107
  }
103
108
  function butexInColumnMaketitleHook() {
@@ -134,7 +139,7 @@ function butexBasmalaTitlingPreamble(options = {}) {
134
139
  " \\begin{center}",
135
140
  ...BASMALA_LINES.map((line, index) => {
136
141
  const suffix = index < BASMALA_LINES.length - 1 ? "\\\\" : "";
137
- return ` ${butexDiwaniDisplayTex(line)}${suffix}`;
142
+ return ` ${butexMaghribiDisplayTex(line)}${suffix}`;
138
143
  }),
139
144
  " \\par\\vspace{1.5em}",
140
145
  " \\LARGE",
@@ -2099,6 +2104,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2099
2104
  category: "operators1",
2100
2105
  Tex: "\\neq",
2101
2106
  mirror: true,
2107
+ compileMirror: true,
2102
2108
  Label: "\u2260",
2103
2109
  title: "\u0644\u0627 \u064A\u0633\u0627\u0648\u064A",
2104
2110
  svg_path: null
@@ -2138,6 +2144,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2138
2144
  Tex: "\\leq",
2139
2145
  mirror: true,
2140
2146
  displayMirror: false,
2147
+ compileMirror: true,
2141
2148
  Label: "\u2264",
2142
2149
  title: "\u0623\u0635\u063A\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
2143
2150
  svg_path: null
@@ -2148,6 +2155,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2148
2155
  Tex: "\\geq",
2149
2156
  mirror: true,
2150
2157
  displayMirror: false,
2158
+ compileMirror: true,
2151
2159
  Label: "\u2265",
2152
2160
  title: "\u0623\u0643\u0628\u0631 \u0645\u0646 \u0623\u0648 \u064A\u0633\u0627\u0648\u064A",
2153
2161
  svg_path: null
@@ -2158,6 +2166,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2158
2166
  Tex: "\\coloneqq",
2159
2167
  mirror: true,
2160
2168
  displayMirror: false,
2169
+ compileMirror: true,
2161
2170
  Label: "\u2254",
2162
2171
  title: "\u064A\u0639\u0631\u0641 \u0628\u0623\u0646\u0647 \u064A\u0633\u0627\u0648\u064A",
2163
2172
  svg_path: null
@@ -2168,6 +2177,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2168
2177
  Tex: "\\eqqcolon",
2169
2178
  mirror: true,
2170
2179
  displayMirror: false,
2180
+ compileMirror: true,
2171
2181
  Label: "\u2255",
2172
2182
  title: "\u064A\u0633\u0627\u0648\u064A \u0628\u0627\u0644\u062A\u0639\u0631\u064A\u0641",
2173
2183
  svg_path: null
@@ -2179,6 +2189,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2179
2189
  Tex: "\\propto",
2180
2190
  mirror: true,
2181
2191
  displayMirror: false,
2192
+ compileMirror: true,
2182
2193
  Label: "\u221D",
2183
2194
  title: "\u064A\u062A\u0646\u0627\u0633\u0628 \u0645\u0639",
2184
2195
  svg_path: null
@@ -2189,6 +2200,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2189
2200
  Tex: "\\in",
2190
2201
  mirror: true,
2191
2202
  displayMirror: false,
2203
+ compileMirror: true,
2192
2204
  Label: "\u2208",
2193
2205
  title: "\u064A\u0646\u062A\u0645\u064A \u0625\u0644\u0649",
2194
2206
  svg_path: null
@@ -2209,6 +2221,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2209
2221
  Tex: "\\subset",
2210
2222
  mirror: true,
2211
2223
  displayMirror: false,
2224
+ compileMirror: true,
2212
2225
  Label: "\u2282",
2213
2226
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0645\u0646",
2214
2227
  svg_path: null
@@ -2219,6 +2232,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2219
2232
  Tex: "\\supset",
2220
2233
  mirror: true,
2221
2234
  displayMirror: false,
2235
+ compileMirror: true,
2222
2236
  Label: "\u2283",
2223
2237
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0644\u0640",
2224
2238
  svg_path: null
@@ -2229,6 +2243,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2229
2243
  Tex: "\\subseteq",
2230
2244
  mirror: true,
2231
2245
  displayMirror: false,
2246
+ compileMirror: true,
2232
2247
  Label: "\u2286",
2233
2248
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
2234
2249
  svg_path: null
@@ -2239,6 +2254,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2239
2254
  Tex: "\\supseteq",
2240
2255
  mirror: true,
2241
2256
  displayMirror: false,
2257
+ compileMirror: true,
2242
2258
  Label: "\u2287",
2243
2259
  title: "\u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
2244
2260
  svg_path: null
@@ -2279,6 +2295,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2279
2295
  Tex: "\\nsubseteq",
2280
2296
  mirror: true,
2281
2297
  displayMirror: false,
2298
+ compileMirror: true,
2282
2299
  Label: "\u2288",
2283
2300
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u062C\u0632\u0626\u064A\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
2284
2301
  svg_path: null
@@ -2289,6 +2306,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2289
2306
  Tex: "\\nsupseteq",
2290
2307
  mirror: true,
2291
2308
  displayMirror: false,
2309
+ compileMirror: true,
2292
2310
  Label: "\u2289",
2293
2311
  title: "\u0644\u064A\u0633\u062A \u0645\u062C\u0645\u0648\u0639\u0629 \u0634\u0627\u0645\u0644\u0629 \u0623\u0648 \u062A\u0633\u0627\u0648\u064A",
2294
2312
  svg_path: null
@@ -2336,6 +2354,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2336
2354
  Tex: "\\ddots",
2337
2355
  mirror: true,
2338
2356
  displayMirror: false,
2357
+ compileMirror: true,
2339
2358
  Label: "\u22F1",
2340
2359
  title: "\u0646\u0642\u0627\u0637 \u0642\u0637\u0631\u064A\u0629",
2341
2360
  svg_path: null
@@ -2355,6 +2374,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2355
2374
  category: "operators3",
2356
2375
  Tex: "\\implies",
2357
2376
  mirror: true,
2377
+ compileMirror: true,
2358
2378
  Label: "\u21D2",
2359
2379
  title: "\u064A\u0633\u062A\u0644\u0632\u0645",
2360
2380
  svg_path: null
@@ -2364,6 +2384,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2364
2384
  category: "operators3",
2365
2385
  Tex: "\\impliedby",
2366
2386
  mirror: true,
2387
+ compileMirror: true,
2367
2388
  Label: "\u21D0",
2368
2389
  title: "\u0645\u0633\u062A\u0644\u0632\u0645 \u0645\u0646",
2369
2390
  svg_path: null
@@ -2382,6 +2403,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2382
2403
  category: "operators3",
2383
2404
  Tex: "\\Longrightarrow",
2384
2405
  mirror: true,
2406
+ compileMirror: true,
2385
2407
  Label: "\u27F9",
2386
2408
  title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
2387
2409
  svg_path: null
@@ -2391,6 +2413,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2391
2413
  category: "operators3",
2392
2414
  Tex: "\\Longleftarrow",
2393
2415
  mirror: true,
2416
+ compileMirror: true,
2394
2417
  Label: "\u27F8",
2395
2418
  title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0637\u0648\u064A\u0644 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
2396
2419
  svg_path: null
@@ -2400,6 +2423,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2400
2423
  category: "operators3",
2401
2424
  Tex: "\\to",
2402
2425
  mirror: true,
2426
+ compileMirror: true,
2403
2427
  Label: "\u2192",
2404
2428
  title: "\u064A\u0624\u0648\u0644 \u0625\u0644\u0649",
2405
2429
  svg_path: null
@@ -2409,6 +2433,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2409
2433
  category: "operators3",
2410
2434
  Tex: "\\rightleftharpoons",
2411
2435
  mirror: true,
2436
+ compileMirror: true,
2412
2437
  Label: "\u21CC",
2413
2438
  title: "\u0627\u062A\u0632\u0627\u0646",
2414
2439
  svg_path: null
@@ -2418,6 +2443,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2418
2443
  category: "operators3",
2419
2444
  Tex: "\\leftarrow",
2420
2445
  mirror: true,
2446
+ compileMirror: true,
2421
2447
  Label: "\u2190",
2422
2448
  title: "\u0633\u0647\u0645 \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
2423
2449
  svg_path: null
@@ -2427,6 +2453,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2427
2453
  category: "operators3",
2428
2454
  Tex: "\\rightarrow",
2429
2455
  mirror: true,
2456
+ compileMirror: true,
2430
2457
  Label: "\u2192",
2431
2458
  title: "\u0633\u0647\u0645 \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
2432
2459
  svg_path: null
@@ -2436,6 +2463,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2436
2463
  category: "operators3",
2437
2464
  Tex: "\\Leftarrow",
2438
2465
  mirror: true,
2466
+ compileMirror: true,
2439
2467
  Label: "\u21D0",
2440
2468
  title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
2441
2469
  svg_path: null
@@ -2445,6 +2473,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2445
2473
  category: "operators3",
2446
2474
  Tex: "\\Rightarrow",
2447
2475
  mirror: true,
2476
+ compileMirror: true,
2448
2477
  Label: "\u21D2",
2449
2478
  title: "\u0633\u0647\u0645 \u0645\u0632\u062F\u0648\u062C \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
2450
2479
  svg_path: null
@@ -2454,6 +2483,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2454
2483
  category: "operators3",
2455
2484
  Tex: "\\leftharpoonup",
2456
2485
  mirror: true,
2486
+ compileMirror: true,
2457
2487
  Label: "\u21BC",
2458
2488
  title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
2459
2489
  svg_path: null
@@ -2463,6 +2493,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2463
2493
  category: "operators3",
2464
2494
  Tex: "\\rightharpoonup",
2465
2495
  mirror: true,
2496
+ compileMirror: true,
2466
2497
  Label: "\u21C0",
2467
2498
  title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0639\u0644\u0648\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
2468
2499
  svg_path: null
@@ -2472,6 +2503,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2472
2503
  category: "operators3",
2473
2504
  Tex: "\\leftharpoondown",
2474
2505
  mirror: true,
2506
+ compileMirror: true,
2475
2507
  Label: "\u21BD",
2476
2508
  title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0633\u0641\u0644\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0633\u0627\u0631",
2477
2509
  svg_path: null
@@ -2481,6 +2513,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2481
2513
  category: "operators3",
2482
2514
  Tex: "\\rightharpoondown",
2483
2515
  mirror: true,
2516
+ compileMirror: true,
2484
2517
  Label: "\u21C1",
2485
2518
  title: "\u0633\u0647\u0645 \u062E\u0637\u0627\u0641\u064A \u0633\u0641\u0644\u064A \u0625\u0644\u0649 \u0627\u0644\u064A\u0645\u064A\u0646",
2486
2519
  svg_path: null
@@ -2491,6 +2524,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2491
2524
  category: "integrals",
2492
2525
  Tex: "\\int",
2493
2526
  mirror: true,
2527
+ compileMirror: true,
2494
2528
  Label: "\u222B",
2495
2529
  title: "\u062A\u0643\u0627\u0645\u0644",
2496
2530
  svg_path: null
@@ -2501,6 +2535,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2501
2535
  Tex: "\\iint",
2502
2536
  mirror: true,
2503
2537
  displayMirror: false,
2538
+ compileMirror: true,
2504
2539
  Label: "\u222C",
2505
2540
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u0632\u062F\u0648\u062C",
2506
2541
  svg_path: null
@@ -2511,6 +2546,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2511
2546
  Tex: "\\iiint",
2512
2547
  mirror: true,
2513
2548
  displayMirror: false,
2549
+ compileMirror: true,
2514
2550
  Label: "\u222D",
2515
2551
  title: "\u062A\u0643\u0627\u0645\u0644 \u062B\u0644\u0627\u062B\u064A",
2516
2552
  svg_path: null
@@ -2521,6 +2557,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2521
2557
  Tex: "\\iiiint",
2522
2558
  mirror: true,
2523
2559
  displayMirror: false,
2560
+ compileMirror: true,
2524
2561
  Label: "\u2A0C",
2525
2562
  title: "\u062A\u0643\u0627\u0645\u0644 \u0631\u0628\u0627\u0639\u064A",
2526
2563
  svg_path: null
@@ -2531,6 +2568,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2531
2568
  Tex: "\\oint",
2532
2569
  mirror: true,
2533
2570
  displayMirror: false,
2571
+ compileMirror: true,
2534
2572
  Label: "\u222E",
2535
2573
  title: "\u062A\u0643\u0627\u0645\u0644 \u0645\u063A\u0644\u0642",
2536
2574
  svg_path: null
@@ -2541,6 +2579,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2541
2579
  Tex: "\\oiint",
2542
2580
  mirror: true,
2543
2581
  displayMirror: false,
2582
+ compileMirror: true,
2544
2583
  Label: "\u222F",
2545
2584
  title: "\u062A\u0643\u0627\u0645\u0644 \u0633\u0637\u062D\u064A \u0645\u063A\u0644\u0642",
2546
2585
  svg_path: null
@@ -2551,6 +2590,7 @@ var ATOMIC_OPERATOR_COMMANDS = {
2551
2590
  Tex: "\\oiiint",
2552
2591
  mirror: true,
2553
2592
  displayMirror: false,
2593
+ compileMirror: true,
2554
2594
  Label: "\u2230",
2555
2595
  title: "\u062A\u0643\u0627\u0645\u0644 \u062D\u062C\u0645\u064A \u0645\u063A\u0644\u0642",
2556
2596
  svg_path: null
@@ -2560,8 +2600,9 @@ function shouldMirrorOperatorDisplay(command) {
2560
2600
  return command?.displayMirror ?? command?.mirror ?? false;
2561
2601
  }
2562
2602
  var MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS).filter((command) => command.mirror).map((command) => command.Tex).sort((a, b) => b.length - a.length);
2563
- function matchingMirroredOperator(tex, index) {
2564
- for (const operatorTex of MIRRORED_OPERATOR_TEX) {
2603
+ var COMPILE_MIRRORED_OPERATOR_TEX = Object.values(ATOMIC_OPERATOR_COMMANDS).filter((command) => "compileMirror" in command && command.compileMirror).map((command) => command.Tex).sort((a, b) => b.length - a.length);
2604
+ function matchingMirroredOperatorFrom(tex, index, operatorTexList) {
2605
+ for (const operatorTex of operatorTexList) {
2565
2606
  if (!tex.startsWith(operatorTex, index)) {
2566
2607
  continue;
2567
2608
  }
@@ -2592,19 +2633,26 @@ function findMatchingBrace(tex, openIndex) {
2592
2633
  }
2593
2634
  return -1;
2594
2635
  }
2595
- function mirrorBuTeXOperatorsInTex(tex) {
2636
+ function mirrorBuTeXOperatorsInTex(tex, options = {}) {
2637
+ const mirroredOperatorTex = options.target === "compile" ? COMPILE_MIRRORED_OPERATOR_TEX : MIRRORED_OPERATOR_TEX;
2596
2638
  let result = "";
2597
2639
  let index = 0;
2598
2640
  while (index < tex.length) {
2599
2641
  if (tex.startsWith("\\butexmirror{", index)) {
2600
2642
  const end = findMatchingBrace(tex, index + "\\butexmirror".length);
2601
2643
  if (end !== -1) {
2602
- result += tex.slice(index, end + 1);
2644
+ const bodyStart = index + "\\butexmirror{".length;
2645
+ const body = tex.slice(bodyStart, end);
2646
+ if (options.target === "compile" && MIRRORED_OPERATOR_TEX.includes(body) && !mirroredOperatorTex.includes(body)) {
2647
+ result += body;
2648
+ } else {
2649
+ result += tex.slice(index, end + 1);
2650
+ }
2603
2651
  index = end + 1;
2604
2652
  continue;
2605
2653
  }
2606
2654
  }
2607
- const operatorTex = matchingMirroredOperator(tex, index);
2655
+ const operatorTex = matchingMirroredOperatorFrom(tex, index, mirroredOperatorTex);
2608
2656
  if (operatorTex) {
2609
2657
  result += `\\butexmirror{${operatorTex}}`;
2610
2658
  index += operatorTex.length;
@@ -8266,18 +8314,19 @@ function mathNodeFromSession(session, opening = "$", closing = "$") {
8266
8314
  }
8267
8315
  return { nodeType: "MathObject", mathMode: opening, lines: [], closing };
8268
8316
  }
8269
- function mathTokenSourceForSide(token, side) {
8317
+ function mathTokenSourceForSide(token, side, digitForm) {
8270
8318
  if (!token.math || token.sourceOwner === "raw") {
8271
8319
  return token.source;
8272
8320
  }
8273
- if (token.sourceSide === side) {
8321
+ if (token.sourceSide === side && digitForm === void 0) {
8274
8322
  return token.source;
8275
8323
  }
8276
8324
  const result = mathTokenToEditorSession(token.math, side);
8277
8325
  if (!result.editable) {
8278
8326
  return token.source;
8279
8327
  }
8280
- return mathSourceFromSession(result.session, side, token.opening, token.closing);
8328
+ const session = digitForm === void 0 ? result.session : setCurrentDigitForm(result.session, digitForm);
8329
+ return mathSourceFromSession(session, side, token.opening, token.closing);
8281
8330
  }
8282
8331
 
8283
8332
  // src/document2/commands.ts
@@ -9011,6 +9060,19 @@ function document2KeyError(key, namespace = {}) {
9011
9060
  }
9012
9061
 
9013
9062
  // src/document2/arabicPreamble.ts
9063
+ function fontOptions(digitsMapping, includeScript = true) {
9064
+ const parts = [];
9065
+ if (includeScript) {
9066
+ parts.push("Script=Arabic");
9067
+ }
9068
+ if (digitsMapping !== "digits") {
9069
+ parts.push(`Mapping=${digitsMapping}`);
9070
+ }
9071
+ if (parts.length === 0) {
9072
+ return "";
9073
+ }
9074
+ return `[${parts.join(",")}]`;
9075
+ }
9014
9076
  function arabicXeLatexPreamblePkg(twocolumn = false) {
9015
9077
  const classOptions = twocolumn ? "12pt,a4paper,notitlepage,twocolumn" : "12pt,a4paper,notitlepage";
9016
9078
  return `
@@ -9039,25 +9101,27 @@ function arabicXeLatexPreamblePkg(twocolumn = false) {
9039
9101
  % save back tick for use - copy paste -> ` + "`";
9040
9102
  }
9041
9103
  function arabicXeLatexPreambleFont(digitsMapping = "arabicdigits") {
9042
- const customFonts = NON_DEFAULT_CHARACTER_FONT_SPECS.filter((font) => font.latexFontCommand && font.latexFontFamily).map((font) => `\\newfontfamily${font.latexFontCommand}[Script=Arabic,Mapping=${digitsMapping}]{${font.latexFontFamily}}`).join("\n");
9104
+ const customFonts = NON_DEFAULT_CHARACTER_FONT_SPECS.filter((font) => font.latexFontCommand && font.latexFontFamily).map((font) => `\\newfontfamily${font.latexFontCommand}${fontOptions(digitsMapping)}{${font.latexFontFamily}}`).join("\n");
9105
+ const mathFontOptions = fontOptions(digitsMapping, false);
9043
9106
  return `
9044
9107
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9045
9108
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9046
- % Toggle between eastern and western digits by changing the Mapping in the below fonts (inside math font as well) between "arabicdigits" and "digits"
9109
+ % Persian digits: Mapping=farsidigits
9110
+ % Arabic-Indic digits: Mapping=arabicdigits
9111
+ % Western digits: omit Mapping entirely
9047
9112
  \\setdefaultlanguage[calendar=gregorian]{arabic} % from polyglossia
9048
- \\setmainfont[Script=Arabic , Mapping=${digitsMapping}]{Amiri}
9113
+ \\setmainfont${fontOptions(digitsMapping)}{Amiri}
9049
9114
  ${customFonts}
9050
- \\newfontfamily\\boldarabic[Script=Arabic,Mapping=${digitsMapping}]{Amiri Bold}
9051
- \\newfontfamily\\italicarabic[Script=Arabic,Mapping=${digitsMapping}]{Amiri Italic}
9115
+ \\newfontfamily\\boldarabic${fontOptions(digitsMapping)}{Amiri Bold}
9116
+ \\newfontfamily\\italicarabic${fontOptions(digitsMapping)}{Amiri Italic}
9052
9117
 
9053
9118
  % for polyglossia url I dont know, sugggested by cursor
9054
- \\newfontfamily\\arabicfonttt[Script=Arabic,Mapping=${digitsMapping}]{Amiri}
9055
- \\newfontfamily\\arabicfontsf[Script=Arabic,Mapping=${digitsMapping}]{Amiri}
9119
+ \\newfontfamily\\arabicfonttt${fontOptions(digitsMapping)}{Amiri}
9120
+ \\newfontfamily\\arabicfontsf${fontOptions(digitsMapping)}{Amiri}
9056
9121
 
9057
9122
 
9058
9123
  % Explicitly set math font to XITS Math
9059
- % Remove "Script=Arabic" to cancel reflected symbols and other RTL symbols
9060
- \\setmathfont[Script=Arabic , Mapping=${digitsMapping}]{XITS Math} % Ensure XITS Math is correctly installed and available
9124
+ \\setmathfont${mathFontOptions}{XITS Math} % Ensure XITS Math is correctly installed and available
9061
9125
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9062
9126
  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
9063
9127
  `;
@@ -9219,8 +9283,20 @@ function getArabicXeLatexPreamble(digitsMappingOrOptions = "arabicdigits") {
9219
9283
  }
9220
9284
 
9221
9285
  // src/document2/exportLatex.ts
9286
+ function digitsMappingFromDigitForm(digitForm) {
9287
+ if (digitForm === "western") {
9288
+ return "digits";
9289
+ }
9290
+ if (digitForm === "persianIndic") {
9291
+ return "farsidigits";
9292
+ }
9293
+ return "arabicdigits";
9294
+ }
9222
9295
  function mathBodyLatex(token) {
9223
- if (!token.math || token.sourceOwner === "raw" || token.sourceOwner === "editor") {
9296
+ if (token.sourceOwner === "editor") {
9297
+ return stripDisplayMathDelimiters(mirrorBuTeXOperatorsInTex(token.source, { target: "compile" }));
9298
+ }
9299
+ if (!token.math || token.sourceOwner === "raw") {
9224
9300
  return stripDisplayMathDelimiters(token.source);
9225
9301
  }
9226
9302
  const rendered = renderMathNodeLatex(token.math);
@@ -9256,7 +9332,10 @@ ${body}
9256
9332
  \\label{${token.label.trim()}}
9257
9333
  \\end{equation}`;
9258
9334
  }
9259
- if (!token.math || token.sourceOwner === "raw" || token.sourceOwner === "editor") {
9335
+ if (token.sourceOwner === "editor") {
9336
+ return mirrorBuTeXOperatorsInTex(token.source, { target: "compile" });
9337
+ }
9338
+ if (!token.math || token.sourceOwner === "raw") {
9260
9339
  return token.source;
9261
9340
  }
9262
9341
  return renderMathNodeLatex(token.math);
@@ -9374,7 +9453,7 @@ function articleMaketitlePreamble(meta, twocolumn = false) {
9374
9453
  if (meta.authors.trim().length > 0) {
9375
9454
  parts.push(`\\author{${authorLatex(meta.authors)}}`);
9376
9455
  }
9377
- parts.push(`\\date{${formatHijriDate(meta.date, { locale: "ar", digitForm: "arabicIndic" })}}`);
9456
+ parts.push(`\\date{${formatHijriDate(meta.date, { locale: "ar", digitForm: "western" })}}`);
9378
9457
  return parts.join("\n");
9379
9458
  }
9380
9459
  function articleFrontMatterLatex(meta) {
@@ -9396,7 +9475,7 @@ function document2Latex(document2, options = {}) {
9396
9475
  const twocolumn = options.twocolumn === true;
9397
9476
  const front = articleFrontMatterLatex(meta);
9398
9477
  const bodyBlocks = document2.blocks.map((block) => blockLatex(block, document2.references));
9399
- const closing = butexDiwaniDisplayLatex(BUTEX_CLOSING_HAMDALA);
9478
+ const closing = butexMaghribiDisplayLatex(BUTEX_CLOSING_HAMDALA);
9400
9479
  const body = [...front, ...bodyBlocks, closing].filter((part) => part.length > 0).join("\n\n");
9401
9480
  const wrapDocument = options.wrapDocument !== false;
9402
9481
  if (!wrapDocument) {
@@ -9406,7 +9485,7 @@ function document2Latex(document2, options = {}) {
9406
9485
  ${body}` : body;
9407
9486
  }
9408
9487
  const preamble = getArabicXeLatexPreamble({
9409
- digitsMapping: options.digitsMapping ?? "arabicdigits",
9488
+ digitsMapping: options.digitsMapping ?? digitsMappingFromDigitForm(options.digitForm),
9410
9489
  twocolumn
9411
9490
  }) + "\n" + articleMaketitlePreamble(meta, twocolumn);
9412
9491
  return `${preamble}
@@ -9662,8 +9741,8 @@ function remapSelectionAfterRangeMove(selection, direction) {
9662
9741
  }
9663
9742
 
9664
9743
  // src/document2/previewModel.ts
9665
- function mathTex(token, equationSide) {
9666
- return mathTokenSourceForSide(token, equationSide);
9744
+ function mathTex(token, equationSide, digitForm) {
9745
+ return mathTokenSourceForSide(token, equationSide, digitForm);
9667
9746
  }
9668
9747
  function previewInlines(field, islands, output, equationSide, document2, previewOptions) {
9669
9748
  return field.tokens.map((token) => {
@@ -9695,7 +9774,7 @@ function previewInlines(field, islands, output, equationSide, document2, preview
9695
9774
  }
9696
9775
  const island = {
9697
9776
  id: token.id,
9698
- tex: mathTex(token, equationSide),
9777
+ tex: mathTex(token, equationSide, previewOptions.digitForm),
9699
9778
  display: token.display,
9700
9779
  output,
9701
9780
  editable: token.editable
@@ -9830,7 +9909,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
9830
9909
  blocks: [
9831
9910
  ...articleChromePreview(document2, options.uiLocale ?? "ar", options),
9832
9911
  ...body,
9833
- { kind: "closing", id: "article-closing", text: BUTEX_CLOSING_HAMDALA, tex: butexDiwaniDisplayTex(BUTEX_CLOSING_HAMDALA) }
9912
+ { kind: "closing", id: "article-closing", text: BUTEX_CLOSING_HAMDALA, tex: butexMaghribiDisplayTex(BUTEX_CLOSING_HAMDALA) }
9834
9913
  ],
9835
9914
  mathIslands
9836
9915
  };
@@ -10338,6 +10417,32 @@ function focusArticleMetaPanel(panel) {
10338
10417
  // src/react-document2/ButexDocumentEditor2.tsx
10339
10418
  var import_react13 = require("react");
10340
10419
 
10420
+ // src/debugJson.ts
10421
+ function lineColumnForPosition(text, position) {
10422
+ const before = text.slice(0, Math.max(0, position));
10423
+ const lines = before.split("\n");
10424
+ return {
10425
+ line: lines.length,
10426
+ column: (lines[lines.length - 1]?.length ?? 0) + 1
10427
+ };
10428
+ }
10429
+ function parseJsonDebugInput(text) {
10430
+ try {
10431
+ return { ok: true, value: JSON.parse(text) };
10432
+ } catch (error) {
10433
+ const message = error instanceof Error ? error.message : String(error);
10434
+ const positionMatch = message.match(/position\s+(\d+)/i);
10435
+ if (positionMatch) {
10436
+ const position = Number(positionMatch[1]);
10437
+ if (Number.isFinite(position)) {
10438
+ const location = lineColumnForPosition(text, position);
10439
+ return { ok: false, error: `Invalid JSON at line ${String(location.line)}, column ${String(location.column)}: ${message}` };
10440
+ }
10441
+ }
10442
+ return { ok: false, error: `Invalid JSON: ${message}` };
10443
+ }
10444
+ }
10445
+
10341
10446
  // src/react-document2/BlockEditor.tsx
10342
10447
  var import_react4 = require("react");
10343
10448
 
@@ -10877,6 +10982,7 @@ function MathChip({
10877
10982
  token,
10878
10983
  output = "svg",
10879
10984
  documentDirection = "rtl",
10985
+ digitForm,
10880
10986
  equationSide = "arabic",
10881
10987
  editable = true,
10882
10988
  uiLocale = "ar",
@@ -10888,7 +10994,7 @@ function MathChip({
10888
10994
  onTextInputFromFocus
10889
10995
  }) {
10890
10996
  const messages = document2Messages(uiLocale);
10891
- const tex = mathTokenSourceForSide(token, equationSide);
10997
+ const tex = mathTokenSourceForSide(token, equationSide, digitForm);
10892
10998
  const forwardArrowKey = documentDirection === "rtl" ? "ArrowLeft" : "ArrowRight";
10893
10999
  const backwardArrowKey = documentDirection === "rtl" ? "ArrowRight" : "ArrowLeft";
10894
11000
  const island = /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MathIsland, { id: token.id, tex, display: token.display, output });
@@ -11298,6 +11404,7 @@ function InlineField({
11298
11404
  token,
11299
11405
  output: mathOutput,
11300
11406
  equationSide,
11407
+ digitForm,
11301
11408
  editable: editableEquations,
11302
11409
  uiLocale,
11303
11410
  buttonRef: (element) => {
@@ -12842,6 +12949,11 @@ var WIDGET_CHROME_CSS = `
12842
12949
  font-family: ${BUTEX_DIWANI_OUTLINE_FONT_STACK};
12843
12950
  }
12844
12951
 
12952
+ .butex-widget .font-mode-btn--maghribi,
12953
+ .butex-widget .character-font-option--maghribi {
12954
+ font-family: ${BUTEX_MAGHRIBI_FONT_STACK};
12955
+ }
12956
+
12845
12957
  .butex-widget .character-font-options {
12846
12958
  position: absolute;
12847
12959
  z-index: 10;
@@ -13376,6 +13488,36 @@ var WIDGET_CHROME_CSS = `
13376
13488
  background: var(--butex-dev-inset-bg);
13377
13489
  color: var(--butex-dev-inset-fg);
13378
13490
  }
13491
+
13492
+ .butex-widget .debug-json-import {
13493
+ display: grid;
13494
+ gap: 8px;
13495
+ margin-bottom: 10px;
13496
+ }
13497
+
13498
+ .butex-widget .debug-json-import textarea {
13499
+ min-height: 150px;
13500
+ resize: vertical;
13501
+ border: 1px solid var(--butex-dev-inset-border);
13502
+ border-radius: 8px;
13503
+ padding: 8px 10px;
13504
+ direction: ltr;
13505
+ text-align: left;
13506
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
13507
+ font-size: 11px;
13508
+ background: var(--butex-dev-inset-bg);
13509
+ color: var(--butex-dev-inset-fg);
13510
+ }
13511
+
13512
+ .butex-widget .debug-json-error {
13513
+ margin: 0;
13514
+ border: 1px solid rgba(220, 38, 38, 0.45);
13515
+ background: rgba(254, 226, 226, 0.9);
13516
+ color: #991b1b;
13517
+ border-radius: 8px;
13518
+ padding: 8px 10px;
13519
+ white-space: pre-wrap;
13520
+ }
13379
13521
  `.trim();
13380
13522
  var CHROME_STYLE_ID = "butex-widget-chrome-css";
13381
13523
  function injectWidgetChromeCss(doc) {
@@ -13504,6 +13646,7 @@ ${latex || messages.empty}`;
13504
13646
  var ButexEditor = (0, import_react8.forwardRef)(
13505
13647
  function ButexEditor2({ className, debug = false, defaultSide, uiLocale = "ar", initialSession, onSessionChange }, ref) {
13506
13648
  const messages = equationEditorMessages(uiLocale);
13649
+ const debugEnabled = debug || typeof window !== "undefined" && new URLSearchParams(window.location.search).get("debug") === "1";
13507
13650
  const wrapperRef = (0, import_react8.useRef)(null);
13508
13651
  const surfaceRef = (0, import_react8.useRef)(null);
13509
13652
  const inputRef = (0, import_react8.useRef)(null);
@@ -13521,7 +13664,7 @@ var ButexEditor = (0, import_react8.forwardRef)(
13521
13664
  const digitFormBtnRef = (0, import_react8.useRef)(null);
13522
13665
  const runtimeRef = (0, import_react8.useRef)(null);
13523
13666
  const debugRef = (0, import_react8.useRef)(debug);
13524
- debugRef.current = debug;
13667
+ debugRef.current = debugEnabled;
13525
13668
  const uiLocaleRef = (0, import_react8.useRef)(uiLocale);
13526
13669
  uiLocaleRef.current = uiLocale;
13527
13670
  const onSessionChangeRef = (0, import_react8.useRef)(onSessionChange);
@@ -13529,6 +13672,9 @@ var ButexEditor = (0, import_react8.forwardRef)(
13529
13672
  const debugBodyHiddenRef = (0, import_react8.useRef)(false);
13530
13673
  const [debugBodyHidden, setDebugBodyHidden] = (0, import_react8.useState)(false);
13531
13674
  debugBodyHiddenRef.current = debugBodyHidden;
13675
+ const [debugImportOpen, setDebugImportOpen] = (0, import_react8.useState)(false);
13676
+ const [debugImportText, setDebugImportText] = (0, import_react8.useState)("");
13677
+ const [debugImportError, setDebugImportError] = (0, import_react8.useState)("");
13532
13678
  const [digitMenuOpen, setDigitMenuOpen] = (0, import_react8.useState)(false);
13533
13679
  const [characterFontMenuOpen, setCharacterFontMenuOpen] = (0, import_react8.useState)(false);
13534
13680
  const [delimiterMenuOpen, setDelimiterMenuOpen] = (0, import_react8.useState)(false);
@@ -13609,6 +13755,54 @@ ${arabic || currentMessages.empty}`;
13609
13755
  }, []);
13610
13756
  const updatePreviewRef = (0, import_react8.useRef)(updatePreview);
13611
13757
  updatePreviewRef.current = updatePreview;
13758
+ async function copyDebugText(text) {
13759
+ try {
13760
+ await navigator.clipboard.writeText(text);
13761
+ } catch {
13762
+ }
13763
+ }
13764
+ function currentMathObjectJsonText() {
13765
+ const session = runtimeRef.current?.getSession();
13766
+ if (!session) {
13767
+ return "";
13768
+ }
13769
+ const math = mathNodeFromEditorSession(session);
13770
+ if (!math.ok) {
13771
+ return "";
13772
+ }
13773
+ return JSON.stringify(toMathObjectJson(math.math), null, 2);
13774
+ }
13775
+ function openDebugMathObjectImport() {
13776
+ setDebugImportText(currentMathObjectJsonText());
13777
+ setDebugImportError("");
13778
+ setDebugImportOpen(true);
13779
+ }
13780
+ function applyDebugMathObjectImport() {
13781
+ const parsed = parseJsonDebugInput(debugImportText);
13782
+ if (!parsed.ok) {
13783
+ setDebugImportError(parsed.error);
13784
+ return;
13785
+ }
13786
+ try {
13787
+ const math = fromMathObjectJson(parsed.value, activeEditorSide);
13788
+ const result = mathObjectToEditorSession(math);
13789
+ if (!result.editable) {
13790
+ setDebugImportError(result.reason);
13791
+ return;
13792
+ }
13793
+ const next = { ...result.session, activeSide: activeEditorSide };
13794
+ runtimeRef.current?.setSession(next);
13795
+ setSelectedDigitForm(next.currentDigitForm ?? "western");
13796
+ setSelectedCharacterFont(next.currentCharacterFont ?? "default");
13797
+ setActiveEditorSide(next.activeSide);
13798
+ onSessionChangeRef.current?.(next);
13799
+ setDebugImportError("");
13800
+ setDebugImportOpen(false);
13801
+ void updatePreviewRef.current(next);
13802
+ } catch (importError) {
13803
+ setDebugImportError(importError instanceof Error ? importError.message : String(importError));
13804
+ }
13805
+ }
13612
13806
  (0, import_react8.useEffect)(() => {
13613
13807
  injectWidgetChromeCss();
13614
13808
  injectBuTeXEditorStyles(typeof document !== "undefined" ? document : void 0);
@@ -14769,7 +14963,7 @@ ${arabic || currentMessages.empty}`;
14769
14963
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: renderErrorRef, className: "error", hidden: true })
14770
14964
  ] }),
14771
14965
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("section", { className: "panel panel-preview", "aria-label": messages.renderPreview, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: mathOutputRef, className: "preview-box" }) }),
14772
- debug ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "panel", children: [
14966
+ debugEnabled ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("section", { className: "panel", children: [
14773
14967
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "dev-strip", children: [
14774
14968
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "dev-badge", children: messages.development }),
14775
14969
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: latexLinesRef, className: "ascii" }),
@@ -14777,6 +14971,8 @@ ${arabic || currentMessages.empty}`;
14777
14971
  ] }),
14778
14972
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { marginTop: 12 }, children: [
14779
14973
  /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "debug-head", children: [
14974
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", onClick: () => void copyDebugText(currentMathObjectJsonText()), children: "Copy MathObject JSON" }),
14975
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", "aria-expanded": debugImportOpen, onClick: openDebugMathObjectImport, children: "Import MathObject JSON" }),
14780
14976
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
14781
14977
  "button",
14782
14978
  {
@@ -14812,6 +15008,35 @@ ${arabic || currentMessages.empty}`;
14812
15008
  }
14813
15009
  )
14814
15010
  ] }),
15011
+ debugImportOpen ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "debug-json-import", children: [
15012
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
15013
+ "textarea",
15014
+ {
15015
+ value: debugImportText,
15016
+ "aria-label": "Import MathObject JSON",
15017
+ spellCheck: false,
15018
+ onChange: (event) => {
15019
+ setDebugImportText(event.currentTarget.value);
15020
+ setDebugImportError("");
15021
+ }
15022
+ }
15023
+ ),
15024
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { className: "debug-head", children: [
15025
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("button", { type: "button", onClick: applyDebugMathObjectImport, children: "Apply" }),
15026
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
15027
+ "button",
15028
+ {
15029
+ type: "button",
15030
+ onClick: () => {
15031
+ setDebugImportOpen(false);
15032
+ setDebugImportError("");
15033
+ },
15034
+ children: "Cancel"
15035
+ }
15036
+ )
15037
+ ] }),
15038
+ debugImportError ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "debug-json-error", children: debugImportError }) : null
15039
+ ] }) : null,
14815
15040
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { ref: debugLogRef, className: "debug-log" })
14816
15041
  ] })
14817
15042
  ] }) : null
@@ -14837,6 +15062,7 @@ function keyErrorMessage2(error, messages) {
14837
15062
  return null;
14838
15063
  }
14839
15064
  function EquationDrawer({
15065
+ debug = false,
14840
15066
  session,
14841
15067
  reason,
14842
15068
  mathMode,
@@ -14954,7 +15180,7 @@ function EquationDrawer({
14954
15180
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
14955
15181
  ButexEditor,
14956
15182
  {
14957
- debug: false,
15183
+ debug,
14958
15184
  defaultSide: equationSide,
14959
15185
  uiLocale,
14960
15186
  initialSession: session,
@@ -16536,6 +16762,42 @@ var DOCUMENT2_WIDGET_CSS = `
16536
16762
  white-space: pre-wrap;
16537
16763
  }
16538
16764
 
16765
+ .butex-document2-widget__dev-actions {
16766
+ display: flex;
16767
+ flex-wrap: wrap;
16768
+ gap: 8px;
16769
+ margin: 0 0 10px;
16770
+ }
16771
+
16772
+ .butex-document2-widget__dev-import {
16773
+ display: grid;
16774
+ gap: 8px;
16775
+ margin-bottom: 12px;
16776
+ }
16777
+
16778
+ .butex-document2-widget__dev-import textarea {
16779
+ background: var(--butex-document2-dev-code-bg);
16780
+ border: 1px solid var(--butex-document2-dev-border);
16781
+ border-radius: 8px;
16782
+ color: var(--butex-document2-dev-code-fg);
16783
+ direction: ltr;
16784
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
16785
+ min-height: 180px;
16786
+ padding: 10px;
16787
+ resize: vertical;
16788
+ text-align: left;
16789
+ }
16790
+
16791
+ .butex-document2-widget__dev-error {
16792
+ background: rgba(254, 226, 226, 0.9);
16793
+ border: 1px solid rgba(220, 38, 38, 0.45);
16794
+ border-radius: 8px;
16795
+ color: #991b1b;
16796
+ margin: 0;
16797
+ padding: 8px 10px;
16798
+ white-space: pre-wrap;
16799
+ }
16800
+
16539
16801
  .butex-document2-widget__dev-diagnostic {
16540
16802
  background: rgba(251, 191, 36, 0.18);
16541
16803
  border: 1px solid rgba(217, 119, 6, 0.4);
@@ -17399,11 +17661,17 @@ function ButexDocumentEditor2({
17399
17661
  const [labelsOpen, setLabelsOpen] = (0, import_react13.useState)(false);
17400
17662
  const [refPicker, setRefPicker] = (0, import_react13.useState)(null);
17401
17663
  const [digitFormState, setDigitFormState] = (0, import_react13.useState)(null);
17664
+ const [debugImportOpen, setDebugImportOpen] = (0, import_react13.useState)(false);
17665
+ const [debugImportText, setDebugImportText] = (0, import_react13.useState)("");
17666
+ const [debugImportError, setDebugImportError] = (0, import_react13.useState)("");
17402
17667
  const [editorFocus, setEditorFocus] = (0, import_react13.useState)(createEmptyDocument2EditorFocus());
17403
17668
  const [collapsedBlockIds, setCollapsedBlockIds] = (0, import_react13.useState)(() => /* @__PURE__ */ new Set());
17404
17669
  const [blockSelectionState, setBlockSelectionState] = (0, import_react13.useState)(emptyBlockSelection);
17405
17670
  const [historyTick, setHistoryTick] = (0, import_react13.useState)(0);
17406
17671
  const digitForm = digitFormProp ?? digitFormState ?? (documentDirection === "rtl" ? "arabicIndic" : "western");
17672
+ function equationSessionWithDocumentDigits(session) {
17673
+ return setCurrentDigitForm(session, digitForm);
17674
+ }
17407
17675
  const historyRef = (0, import_react13.useRef)(createDocument2History());
17408
17676
  const documentRef = (0, import_react13.useRef)(documentNode);
17409
17677
  const textSnapshotArmedRef = (0, import_react13.useRef)(false);
@@ -17412,7 +17680,7 @@ function ButexDocumentEditor2({
17412
17680
  const articleMetaPanelRef = (0, import_react13.useRef)(null);
17413
17681
  const pendingFocusRef = (0, import_react13.useRef)(null);
17414
17682
  documentRef.current = documentNode;
17415
- const latex = document2Latex(documentNode);
17683
+ const latex = document2Latex(documentNode, { digitForm });
17416
17684
  const documentJson = (0, import_react13.useMemo)(() => toDocumentJson2(documentNode), [documentNode]);
17417
17685
  const documentLabels = (0, import_react13.useMemo)(() => collectDocument2Labels(documentNode), [documentNode]);
17418
17686
  const preview = (0, import_react13.useMemo)(
@@ -17620,6 +17888,46 @@ function ButexDocumentEditor2({
17620
17888
  function openAllBlocks() {
17621
17889
  setCollapsedBlockIds(/* @__PURE__ */ new Set());
17622
17890
  }
17891
+ async function copyDebugText(text) {
17892
+ try {
17893
+ await navigator.clipboard.writeText(text);
17894
+ } catch {
17895
+ }
17896
+ }
17897
+ function openDebugJsonImport() {
17898
+ setDebugImportText(JSON.stringify(documentJson, null, 2));
17899
+ setDebugImportError("");
17900
+ setDebugImportOpen(true);
17901
+ }
17902
+ function applyDebugJsonImport() {
17903
+ const parsed = parseJsonDebugInput(debugImportText);
17904
+ if (!parsed.ok) {
17905
+ setDebugImportError(parsed.error);
17906
+ return;
17907
+ }
17908
+ try {
17909
+ const imported = fromDocumentJson2(parsed.value);
17910
+ textSnapshotArmedRef.current = false;
17911
+ if (textDebounceRef.current !== null) {
17912
+ window.clearTimeout(textDebounceRef.current);
17913
+ textDebounceRef.current = null;
17914
+ }
17915
+ setDocumentNode(imported);
17916
+ setError(null);
17917
+ setSelectedMath(null);
17918
+ setCitePicker(null);
17919
+ setRefPicker(null);
17920
+ clearBlockSelection();
17921
+ setCollapsedBlockIds(/* @__PURE__ */ new Set());
17922
+ setEditorFocus(createEmptyDocument2EditorFocus());
17923
+ historyRef.current = createDocument2History();
17924
+ bumpHistoryUi();
17925
+ setDebugImportError("");
17926
+ setDebugImportOpen(false);
17927
+ } catch (importError) {
17928
+ setDebugImportError(importError instanceof Error ? importError.message : String(importError));
17929
+ }
17930
+ }
17623
17931
  (0, import_react13.useEffect)(() => {
17624
17932
  const root = widgetRef.current;
17625
17933
  if (!root) {
@@ -17675,7 +17983,7 @@ function ButexDocumentEditor2({
17675
17983
  textTokenId: target?.textTokenId ?? null,
17676
17984
  insertAt: target?.caretOffset ?? 0,
17677
17985
  mathMode: mode,
17678
- session: createEmptyEquationSession(equationSide),
17986
+ session: equationSessionWithDocumentDigits(createEmptyEquationSession(equationSide)),
17679
17987
  reason: null,
17680
17988
  labelEnabled: false,
17681
17989
  label: ""
@@ -17695,7 +18003,7 @@ function ButexDocumentEditor2({
17695
18003
  insertAt: 0,
17696
18004
  textTokenId: null,
17697
18005
  mathMode: mode,
17698
- session: createEmptyEquationSession(equationSide),
18006
+ session: equationSessionWithDocumentDigits(createEmptyEquationSession(equationSide)),
17699
18007
  reason: result.reason,
17700
18008
  labelEnabled: Boolean(token.labelEnabled),
17701
18009
  label: token.label ?? ""
@@ -17708,7 +18016,7 @@ function ButexDocumentEditor2({
17708
18016
  insertAt: 0,
17709
18017
  textTokenId: null,
17710
18018
  mathMode: mode,
17711
- session: result.session,
18019
+ session: equationSessionWithDocumentDigits(result.session),
17712
18020
  reason: null,
17713
18021
  labelEnabled: Boolean(token.labelEnabled),
17714
18022
  label: token.label ?? ""
@@ -18133,14 +18441,51 @@ function ButexDocumentEditor2({
18133
18441
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: messages.importWarnings }),
18134
18442
  documentNode.diagnostics.map((diagnostic) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "butex-document2-widget__dev-diagnostic", children: formatDocument2Diagnostic(diagnostic, messages) }, `${diagnostic.path}-${diagnostic.message}`))
18135
18443
  ] }) : null,
18444
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "butex-document2-widget__dev-actions", children: [
18445
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: () => void copyDebugText(JSON.stringify(documentJson, null, 2)), children: "Copy JSON" }),
18446
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: () => void copyDebugText(latex), children: "Copy TeX" }),
18447
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", "aria-expanded": debugImportOpen, onClick: openDebugJsonImport, children: "Import JSON" })
18448
+ ] }),
18449
+ debugImportOpen ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "butex-document2-widget__dev-import", children: [
18450
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
18451
+ "textarea",
18452
+ {
18453
+ value: debugImportText,
18454
+ "aria-label": "Import Document2 JSON",
18455
+ spellCheck: false,
18456
+ onChange: (event) => {
18457
+ setDebugImportText(event.currentTarget.value);
18458
+ setDebugImportError("");
18459
+ }
18460
+ }
18461
+ ),
18462
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "butex-document2-widget__dev-actions", children: [
18463
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", onClick: applyDebugJsonImport, children: "Apply" }),
18464
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
18465
+ "button",
18466
+ {
18467
+ type: "button",
18468
+ onClick: () => {
18469
+ setDebugImportOpen(false);
18470
+ setDebugImportError("");
18471
+ },
18472
+ children: "Cancel"
18473
+ }
18474
+ )
18475
+ ] }),
18476
+ debugImportError ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "butex-document2-widget__dev-error", children: debugImportError }) : null
18477
+ ] }) : null,
18136
18478
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "LaTeX" }),
18137
18479
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { children: latex }),
18480
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "JSON" }),
18481
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { children: JSON.stringify(documentJson, null, 2) }),
18138
18482
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: "AST" }),
18139
18483
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("pre", { children: JSON.stringify(documentNode, null, 2) })
18140
18484
  ] }) : null,
18141
18485
  !previewOnly && selectedMath ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
18142
18486
  EquationDrawer,
18143
18487
  {
18488
+ debug: debugEnabled,
18144
18489
  session: selectedMath.session,
18145
18490
  reason: selectedMath.reason,
18146
18491
  mathMode: selectedMath.mathMode,