@drghaliasri/butex 4.1.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -61,7 +61,8 @@ Peer dependency: `mathjax` ^4.x (aligned with MathJax 4 components). If you use
61
61
  2. Load BuTeX’s IIFE bundle (`dist/index.global.js` exposes global `BuTeX`).
62
62
  3. In `MathJax.startup.ready`, call `BuTeX.registerBuTeX(MathJax)` before `MathJax.startup.defaultReady()`.
63
63
  4. Inject styles once: `BuTeX.injectBuTeXStyles()` (or embed `BuTeX.BUTEX_CHROME_CSS` yourself).
64
- 5. Render math with `renderBuTeXMathIsland(tex, options?)` or mount into a host element via `mountBuTeXMathIsland(host, tex, options?)`. Pass `output: 'svg'` when the host loads `tex-svg.js`, or `output: 'chtml'` with `tex-chtml.js`. For raw Arabic TeX that did not come from the editor AST, pass `mirrorOperators: true` to wrap directional operators according to BuTeX's shared operator table. `ButexEditor` picks SVG vs CHTML automatically from the loaded MathJax bundle (`tex2svg` vs `tex2chtml`).
64
+ 5. When using **SVG** (`tex-svg.js`), call `BuTeX.registerBuTeXSvgTextWrapper(MathJax)` **after** `defaultReady()` so Takween/Diwani text, `\ad`, and Arabic atomic commands (`\arsin`, etc.) render in the preview with the correct fonts. CommonHTML (`tex-chtml.js`) uses the injected CSS classes instead.
65
+ 6. Render math with `renderBuTeXMathIsland(tex, options?)` or mount into a host element via `mountBuTeXMathIsland(host, tex, options?)`. Pass `output: 'svg'` when the host loads `tex-svg.js`, or `output: 'chtml'` with `tex-chtml.js`. For raw Arabic TeX that did not come from the editor AST, pass `mirrorOperators: true` to wrap directional operators according to BuTeX's shared operator table. `ButexEditor` picks SVG vs CHTML automatically from the loaded MathJax bundle (`tex2svg` vs `tex2chtml`).
65
66
 
66
67
  Ensure TeX `packages` includes `butex-arabic-math` (use `BUTEX_TEX_PACKAGE` in config when using `{ '[+]': [...] }`).
67
68
 
@@ -127,7 +128,7 @@ Use this when you want the same editor UX as the demo:
127
128
  - Optionally pass `buttonElements` (undo/redo/copy/cut/split toggle) for auto button state refresh.
128
129
  - Wire your toolbar/actions to runtime methods (`toggleSide`, `insertDelimiterByKind`, `addSup`, `addSub`, `removeSup`, `removeSub`, `deleteStructure`, `performUndo`, `performRedo`, `performCopy`, `performCut`, `performPaste`).
129
130
  - Use `onSessionChange(session)` to render external previews (e.g., MathJax pane, status labels).
130
- - **Imported `MathObject` / `CharObject` for the editor:** document LaTeX preview treats `CharObject.expr` as already-rendered Arabic TeX (e.g. `\text{م}`). When opening an imported equation in `<ButexEditor />` via `mathObjectToEditorSession`, BuTeX unwraps supported LaTeX text/font wrappers into plain glyph `expr` plus editor `characterFont`. Supported patterns: `\text{…}`, `\takween{…}`, `\diwani{…}`, `\butextakween{…}`, `\butexdiwani{…}`, `\butexdiwanioutline{…}`, and nested forms such as `\text{\takween{…}}`. BuTeX’s own save path already stores plain glyphs; upstream converters may emit wrapped `expr` and do not need to change for document render.
131
+ - **Imported `MathObject` / `CharObject` for the editor:** document LaTeX preview treats `CharObject.expr` as already-rendered Arabic TeX (e.g. `\text{م}`). When opening an imported equation in `<ButexEditor />` via `mathObjectToEditorSession`, BuTeX unwraps supported LaTeX text/font wrappers into plain glyph `expr` plus editor `characterFont`. Supported patterns: `\text{…}`, `\takween{…}`, `\diwani{…}`, `\butextakween{…}`, `\butexdiwani{…}`, `\butexdiwanioutline{…}`, and nested forms such as `\text{\takween{…}}`. On save, default-font chars stay plain `CharObject` nodes; non-default fonts are stored as font `CommandObject` wrappers so editor round-trip preserves `characterFont`. Upstream converters may still emit wrapped `expr` on import.
131
132
 
132
133
  Minimal browser example:
133
134
 
@@ -230,6 +231,60 @@ const preview = document2Preview(documentNode, 'svg');
230
231
 
231
232
  V2 exports Arabic TeX by default for equations saved from the embedded editor. Imported raw-only math is preserved as raw source and marked non-editable until a structured equation object is attached.
232
233
 
234
+ ### Document JSON contract (`value` + `math_objects`)
235
+
236
+ Both document layers import the same shape. A text field holds `value` (the full string, **with math delimiters kept in place**) and an optional parallel `math_objects` array that supplies the structured equation AST for each math span found in that string.
237
+
238
+ Rules:
239
+
240
+ - **Detect, then align.** The importer scans `value` for delimiters (`$…$`, `\(…\)`, `\[…\]`, `$$…$$`, and math environments) and binds each detected span to `math_objects` **in reading order (left-to-right)**.
241
+ - **Count and order must match.** Extra or missing entries produce a diagnostic; the browser never silently remaps. `math_mode`/`closing` on each `MathObject` must match the delimiter in `value`.
242
+ - **Per field, not per document.** Each paragraph, heading, and list `item` carries its own `math_objects`.
243
+ - **Tables are the exception:** one flat `math_objects` array lives on the `\begin{tabular}` block and is consumed **row-major** across all cells (each cell takes as many entries as it has spans).
244
+ - **Missing `math_objects`** → the span renders as a non-editable raw math chip from its delimited source.
245
+ - The browser **does not** parse equation LaTeX bodies into `ChainClass`; structured chains come from `math_objects` (import) or the equation editor (GUI).
246
+
247
+ Paragraph with one inline span:
248
+
249
+ ```json
250
+ {
251
+ "command": "\\paragraph",
252
+ "value": "لدينا $x^2$ ثابت.",
253
+ "math_objects": [
254
+ { "node_type": "MathObject", "math_mode": "$",
255
+ "lines": [{ "node_type": "ChainClass", "chain": [] }], "closing": "$" }
256
+ ]
257
+ }
258
+ ```
259
+
260
+ List item with a display span (`math_mode`/`closing` match the delimiter in `value`):
261
+
262
+ ```json
263
+ {
264
+ "value": "الحل \\[a+b\\]",
265
+ "math_objects": [
266
+ { "node_type": "MathObject", "math_mode": "\\[",
267
+ "lines": [{ "node_type": "ChainClass", "chain": [] }], "closing": "\\]" }
268
+ ]
269
+ }
270
+ ```
271
+
272
+ Table: one flat array, consumed row-major (here `$x$`, then `$y$`):
273
+
274
+ ```json
275
+ {
276
+ "command": "\\begin{tabular}",
277
+ "columns": "cc",
278
+ "rows": [["الرمز $x$", "القيمة"], ["الرمز $y$", "القيمة"]],
279
+ "math_objects": [
280
+ { "node_type": "MathObject", "math_mode": "$",
281
+ "lines": [{ "node_type": "ChainClass", "chain": [] }], "closing": "$" },
282
+ { "node_type": "MathObject", "math_mode": "$",
283
+ "lines": [{ "node_type": "ChainClass", "chain": [] }], "closing": "$" }
284
+ ]
285
+ }
286
+ ```
287
+
233
288
  ### Document React widget v2 (`butex/react-document2`)
234
289
 
235
290
  Use this entry for the new document editor integration. It opens embedded `<ButexEditor />` sessions in Arabic/RTL mode by default and renders document preview math islands with MathJax **SVG** by default (`mathOutput` defaults to `'svg'`; pass `mathOutput="chtml"` only if the host loads `tex-chtml.js`).
@@ -253,7 +308,7 @@ export default function Page() {
253
308
  }
254
309
  ```
255
310
 
256
- Host apps still register BuTeX with MathJax before preview rendering. `uiLocale` selects Arabic (`"ar"`, the default) or English (`"en"`) document-editor chrome and is passed to the embedded equation editor. `documentDirection` independently controls prose inputs and preview flow without creating a second document tree. `equationSide` independently controls whether structured equations open, render, and save from the `"english"` or `"arabic"` side. Set `editableEquations={false}` to show math islands without equation insertion, deletion, or editor access. Raw-only equations keep their original source because the browser does not parse raw LaTeX into equation ASTs. Document editor v2 defaults to **`tex-svg.js`**; use `tex-chtml.js` only if you pass `mathOutput="chtml"`.
311
+ Host apps still register BuTeX with MathJax before preview rendering. `uiLocale` selects Arabic (`"ar"`, the default) or English (`"en"`) document-editor chrome and is passed to the embedded equation editor. `documentDirection` independently controls prose inputs and preview flow without creating a second document tree. `equationSide` independently controls whether structured equations open, render, and save from the `"english"` or `"arabic"` side. Set `editableEquations={false}` to show math islands without equation insertion, deletion, or editor access. Set `previewOnly={true}` to render only the read-only document preview with no toolbar, editor panel, or equation drawer. Raw-only equations keep their original source because the browser does not parse raw LaTeX into equation ASTs. Document editor v2 defaults to **`tex-svg.js`**; use `tex-chtml.js` only if you pass `mathOutput="chtml"`.
257
312
 
258
313
  ### Styling/theming contract
259
314
 
@@ -274,7 +329,7 @@ Open:
274
329
 
275
330
  - `http://localhost:4173/demo/` (MathJax + `\arabsqrt`)
276
331
  - `http://localhost:4173/demo/parser.html` (parser-only normalize preview)
277
- - **Equation editor (React):** run `cd demo/editor-app && npm install && npm run dev`, then open the URL Vite prints (see `demo/editor.html` for a short pointer).
332
+ - **Equation editor (React):** run `cd demo/editor-app && npm install && npm run dev`, then open the URL Vite prints (see `demo/editor.html` for a short pointer). The equation editor demo loads MathJax SVG from `public/vendor/`, matching document editor v2.
278
333
  - **Document editor (React):** run `cd demo/document-editor-app && npm install && npm run dev`, then open the URL Vite prints (see `demo/document.html` for a short pointer).
279
334
  - **Document editor v2 (React):** run `cd demo/document-editor-app2 && npm install && npm run dev`, then open the URL Vite prints. The v2 demo loads MathJax SVG and includes grouped insert controls (sections, lists, tables, figures, equations), per-block delete, list item controls, and editor/preview toggles. Optional bottom dev panels (LaTeX + AST) appear only if you append `?debug=1` to the URL or pass the `debug` prop from your host app.
280
335
 
package/dist/document.js CHANGED
@@ -1020,6 +1020,16 @@ var ATOMIC_COMMANDS = {
1020
1020
  arabicLabel: "\u0645\u062D\u062F\u062F",
1021
1021
  title: "\u0645\u062D\u062F\u062F"
1022
1022
  },
1023
+ ////////////////////// Derivatives ////////////////////////////////
1024
+ ad: {
1025
+ id: "ad",
1026
+ category: "derivative",
1027
+ englishTex: "\\mathrm{d}",
1028
+ englishLabel: "d",
1029
+ arabicTex: "\\ad",
1030
+ arabicLabel: "\u0621",
1031
+ title: "\u0639\u0644\u0627\u0645\u0629 \u0627\u0644\u0627\u0634\u062A\u0642\u0627\u0642"
1032
+ },
1023
1033
  ////////////////////// Groups /////////////////////////////////
1024
1034
  N: {
1025
1035
  id: "N",
@@ -1611,6 +1621,16 @@ function atomicOperatorCommandSpec(id) {
1611
1621
  return Object.prototype.hasOwnProperty.call(ATOMIC_OPERATOR_COMMANDS, id) ? ATOMIC_OPERATOR_COMMANDS[id] : null;
1612
1622
  }
1613
1623
 
1624
+ // src/editor/divideOperator.ts
1625
+ var DIVIDE_OPERATOR_EN = "/";
1626
+ var DIVIDE_OPERATOR_AR = "\\";
1627
+ function isDivideOperatorExpr(expr) {
1628
+ return expr === DIVIDE_OPERATOR_EN || expr === DIVIDE_OPERATOR_AR;
1629
+ }
1630
+ function renderDivideOperatorLatex(side) {
1631
+ return side === "arabic" ? "\\backslash" : DIVIDE_OPERATOR_EN;
1632
+ }
1633
+
1614
1634
  // src/editor/digits.ts
1615
1635
  var WESTERN = "0123456789";
1616
1636
  var ARABIC_INDIC = "\u0660\u0661\u0662\u0663\u0664\u0665\u0666\u0667\u0668\u0669";
@@ -1733,6 +1753,9 @@ function renderNodeArabic(node, options) {
1733
1753
  const content = renderCharContent(node, options);
1734
1754
  return arabicScripts(node, (node.characterFont ?? "default") === "default" ? `\\text{${escapeText(expr)}}` : content, options);
1735
1755
  }
1756
+ if (node.kind === "operator" && isDivideOperatorExpr(node.expr)) {
1757
+ return arabicScripts(node, renderDivideOperatorLatex("arabic"), options);
1758
+ }
1736
1759
  return arabicScripts(node, formatDigits(node.expr, selectedDigitForm(options)), options);
1737
1760
  }
1738
1761
  function renderChainArabic(chain, options) {
@@ -2304,6 +2327,19 @@ ${ATOMIC_OPERATOR_COMMAND_CSS}
2304
2327
  `.trim();
2305
2328
 
2306
2329
  // src/document/mathEditorAdapter.ts
2330
+ var CHAR_FONT_EXPORT_TEX = {
2331
+ takween: "\\butextakween",
2332
+ diwani: "\\butexdiwani",
2333
+ diwaniOutline: "\\butexdiwanioutline"
2334
+ };
2335
+ function charEditorNodeToAstNode(node) {
2336
+ const font = node.characterFont ?? "default";
2337
+ const charNode = new CharNode(node.expr);
2338
+ if (font === "default") {
2339
+ return charNode;
2340
+ }
2341
+ return new CommandNode(CHAR_FONT_EXPORT_TEX[font], [], [new ChainNode([charNode])]);
2342
+ }
2307
2343
  function attachAstScripts(editorNode, astNode) {
2308
2344
  if (editorNode.superscript) {
2309
2345
  const sup = editorChainToAstChain(editorNode.superscript);
@@ -2359,7 +2395,7 @@ function editorEnvToAstNode(node) {
2359
2395
  function editorNodeToAstNode(node) {
2360
2396
  let astNode;
2361
2397
  if (node.kind === "char") {
2362
- astNode = new CharNode(node.expr);
2398
+ astNode = charEditorNodeToAstNode(node);
2363
2399
  } else if (node.kind === "number") {
2364
2400
  astNode = new NumberNode(node.expr);
2365
2401
  } else if (node.kind === "operator") {