npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@drghaliasri/butex

v4.2.0

Published

MathJax extension layer for Arabic-friendly math notation (XeLaTeX-like customs beyond plain MathJax)

Readme

BuTeX

Integrators: treat Integration contract (host apps) as the source of truth for wiring MathJax and BuTeX. The npm package ships dist/ and this README.md only; design notes and ADRs live in the GitHub repo under docs/ (they are not included in the published tarball).

BuTeX is a browser-side foundation for Arabic mathematical typography and equation editing on top of MathJax. It ships thin MathJax extensions such as \arabsqrt (Arabic-style mirrored radical; CommonHTML uses CSS mirror/unmirror, SVG uses the MathJax SVG pipeline plus BuTeX SVG helpers where applicable), optional GUI/document layers, and helpers such as parseBuTeX. The longer-term direction is a GUI editor driven by structured equation ASTs.

The vendored MathJax-src/ folder in this repo is reference only — runtime integration uses the mathjax npm package.

Project direction

The intended editor model is AST-first:

  • A GUI edits equation nodes rather than raw LaTeX strings.
  • BuTeX will maintain local TypeScript ASTs for English and Arabic equation structures so users can switch views.
  • A remote service may send equations as JSON compatible with the local ASTs; the browser imports that JSON and renders/edit it locally.
  • Arabic/English TeX strings are generated from the AST for MathJax rendering. Remote-rendered strings can be useful for testing/debugging, but should not be the editor state.
  • The Python files in references/ are reference material for the emerging JSON shape and conversion behavior.

Rendering outputs and MVP scope

  • CommonHTML (chtml) and SVG are supported. Load the matching MathJax 4 bundle (tex-chtml.js vs tex-svg.js) and pass the same mode as output to renderBuTeXMathIsland / mountBuTeXMathIsland. <ButexEditor /> and document math preview follow the loaded bundle when possible (tex2chtml vs tex2svg).
  • \arabsqrt: optional index + mandatory radicand (same argument shape as \sqrt).
  • Compatibility macros: \arsqrt aliases \arabsqrt; \unit{...} and \idx{...} are browser-side passthrough wrappers for imported/reference TeX.
  • Arabic surface parser (parseBuTeX) — optional helper that maps a tiny subset of Arabic command names to MathJax-safe TeX before rendering (see below). Long-term editor state is structured AST/JSON, not this string transform alone.

Arabic preprocessor (parseBuTeX)

Convert Arabic-friendly math surface syntax to plain MathJax TeX:

| Input | Output | | ------------------- | -------------------------------- | | \جذر[3]{س} | \arabsqrt[3]{\text{س}} | | \كسر{1}{2} | \frac{1}{2} | | \كسر{\جذر{س}}{10} | \frac{\arabsqrt{\text{س}}}{10} | | \جتا | \arcos |

Pure string transform — call parseBuTeX(tex), pass the result to MathJax.

import { parseBuTeX } from 'butex';

const mjTex = parseBuTeX(String.raw`\جذر[3]{س}`);
// await renderBuTeXMathIsland(mjTex, { display: true, output: 'chtml' }) ...

Run tests with npm test. Live parser demo: demo/parser.html (after npm run build; serve the repo root).

Install

npm install butex mathjax

Peer dependency: mathjax ^4.x (aligned with MathJax 4 components). If you use butex/react, also install react and react-dom (^18 or ^19).

Usage (browser)

  1. Load MathJax (e.g. tex-chtml.js or tex-svg.js) after setting window.MathJax config.
  2. Load BuTeX’s IIFE bundle (dist/index.global.js exposes global BuTeX).
  3. In MathJax.startup.ready, call BuTeX.registerBuTeX(MathJax) before MathJax.startup.defaultReady().
  4. Inject styles once: BuTeX.injectBuTeXStyles() (or embed BuTeX.BUTEX_CHROME_CSS yourself).
  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.
  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).

Ensure TeX packages includes butex-arabic-math (use BUTEX_TEX_PACKAGE in config when using { '[+]': [...] }).

Usage (npm / bundler)

MathJax entrypoints (bundlers)

Exact import strings depend on your bundler and how it resolves the mathjax package. Typical ESM imports for MathJax 4 components:

| Desired output | Typical import | | -------------- | -------------- | | CommonHTML | import MathJax from 'mathjax/tex-chtml.js' | | SVG | import MathJax from 'mathjax/tex-svg.js' |

Use the same mode in renderBuTeXMathIsland / mountBuTeXMathIsland via output: 'chtml' or output: 'svg'. If resolution fails, point your import at whatever path your build resolves to the same component bundle (see MathJax’s docs for your version).

import MathJax from 'mathjax/tex-chtml.js'; // or tex-svg.js — match `output` in render calls
import {
  registerBuTeX,
  injectBuTeXStyles,
  renderBuTeXMathIsland,
  BUTEX_TEX_PACKAGE,
} from 'butex';

// Before startup resolves — same timing rules as browser:
MathJax.startup.ready = () => {
  registerBuTeX(MathJax);
  injectBuTeXStyles();
  MathJax.startup.defaultReady();
};
MathJax.config.tex = {
  packages: { '[+]': ['ams', BUTEX_TEX_PACKAGE] },
};

Maintainer-facing design notes live in the GitHub repo under docs/ (not shipped on npm).

Integration contract (host apps)

BuTeX supports two integration modes. Keep this contract for stable behavior.

1) Render-only contract (MathJax + BuTeX macros)

Use this when you only need to render LaTeX strings:

  • Register BuTeX with MathJax via registerBuTeX(MathJax).
  • Include butex-arabic-math in TeX packages.
  • Inject BuTeX MathJax styles once via injectBuTeXStyles(document) (or embed BUTEX_CHROME_CSS).
  • Render expressions with renderBuTeXMathIsland / mountBuTeXMathIsland (set output to match the host bundle: tex-svg.js vs tex-chtml.js).
  • For raw Arabic TeX, set mirrorOperators: true or call mirrorBuTeXOperatorsInTex(tex) before non-island MathJax typesetting. Leave it off for editor-generated TeX because the editor already emits \butexmirror{...}.
  • For Arabic-friendly surface strings, optionally preprocess with parseBuTeX(...) before rendering.

This mode does not require the GUI editor runtime.

2) GUI editor contract (shippable editor UX)

Use this when you want the same editor UX as the demo:

  • Inject editor styles once via injectBuTeXEditorStyles(document) (or embed BUTEX_EDITOR_CSS).
  • Create runtime with Editor.createEditorRuntime({ ... }).
  • Pass your editor surface element as surfaceEl.
  • Optionally pass buttonElements (undo/redo/copy/cut/split toggle) for auto button state refresh.
  • Wire your toolbar/actions to runtime methods (toggleSide, insertDelimiterByKind, addSup, addSub, removeSup, removeSub, deleteStructure, performUndo, performRedo, performCopy, performCut, performPaste).
  • Use onSessionChange(session) to render external previews (e.g., MathJax pane, status labels).
  • 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.

Minimal browser example:

BuTeX.injectBuTeXEditorStyles(document);
const runtime = BuTeX.Editor.createEditorRuntime({
  surfaceEl: document.getElementById('surface'),
  onSessionChange: (session) => {
    // host-render math preview/status here
  },
});

React widget (butex/react)

Shipped as a separate entry so apps that do not use React never pull it in.

  • Import: import { ButexEditor } from 'butex/react'.
  • Peer dependencies when using this entry: react and react-dom (^18 or ^19).
  • The component wraps Editor.createEditorRuntime (toolbar, surface, MathJax preview strip, optional dev panels via debug).
  • Load MathJax and register BuTeX before relying on the preview (same timing as the GUI contract above). Equation preview in ButexEditor uses the same renderBuTeXMathIsland path as document math islands (output follows the loaded bundle: SVG when tex2svg is available, otherwise CHTML). Optional legacy mountBuTeXMathTypeset (typesetPromise) remains exported for hosts that still rely on it.
  • Next.js App Router: put BuTeX in a client component ('use client').
'use client';

import { ButexEditor } from 'butex/react';

export default function Page() {
  return <ButexEditor uiLocale="en" defaultSide="english" />;
}

uiLocale selects Arabic ("ar", the default) or English ("en") GUI labels, tooltips, errors, accessibility text, and chrome direction. defaultSide independently selects the initial "english" or "arabic" equation side; users can still switch equation sides from the toolbar.

Document AST (butex/document)

Use this headless entry when a host app or remote service already has DocumentObject JSON and needs a structured import/export layer.

import {
  fromDocumentJson,
  createEmptyDocument,
  renderDocumentLatex,
  buildDocumentPreview,
} from 'butex/document';

const documentNode = fromDocumentJson({
  node_type: 'DocumentObject',
  blocks: [{ command: '\\section', value: 'Intro $x$' }],
});

const emptyDocument = createEmptyDocument();
const latex = renderDocumentLatex(documentNode);
const preview = buildDocumentPreview(documentNode);

V1 supports simple headings, paragraphs, itemize / enumerate, tabular, includegraphics, raw blocks, and math spans detected inside text. The document layer detects math delimiters and can align them with ordered imported MathObject JSON; it does not parse arbitrary equation LaTeX into chain nodes in the browser.

Document React widget (butex/react-document)

Use this entry for the first document-editor UI. It edits supported document blocks, shows a live semantic preview, and opens the equation editor for supported imported math islands.

'use client';

import { ButexDocumentEditor } from 'butex/react-document';

export default function Page() {
  return (
    <ButexDocumentEditor
      debug
      onLatexChange={(latex) => console.log(latex)}
    />
  );
}

The preview is semantic HTML for document structure. Math is emitted as escaped per-span islands, so host apps still need the normal MathJax + BuTeX registration when they want typeset math preview rather than TeX placeholders.

Document AST v2 (butex/document2)

Use this parallel v2 headless entry for the token-owned document model. Imported delimited math is converted into math tokens between prose tokens; normal editing should mutate text tokens and math tokens separately rather than treating raw delimited TeX as one textarea value.

import {
  fromDocumentJson2,
  document2Latex,
  document2Preview,
} from 'butex/document2';

const documentNode = fromDocumentJson2({
  node_type: 'DocumentObject',
  blocks: [{ command: '\\paragraph', value: 'نص $x$' }],
});

const latex = document2Latex(documentNode);
const preview = document2Preview(documentNode, 'svg');

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.

Document React widget v2 (butex/react-document2)

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).

'use client';

import { ButexDocumentEditor2 } from 'butex/react-document2';

export default function Page() {
  return (
    <ButexDocumentEditor2
      debug
      uiLocale="en"
      documentDirection="ltr"
      equationSide="english"
      editableEquations
      onLatexChange={(latex) => console.log(latex)}
    />
  );
}

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".

Styling/theming contract

  • Core editor classes (.surface, .chain, .slot, .node, .scripts, .delim*, etc.) are shipped from src/editor/styles.ts.
  • Theme with one namespace, --butex-*, on .butex-widget (or an ancestor of the editor surface). Defaults are set on ButexEditor’s root; hosts override accents, borders, --butex-surface-bg / --butex-surface-fg, --butex-preview-bg / --butex-preview-fg, focus/slot/selection, scripts, optional --butex-dev-* / --butex-dev-inset-* when using debug, etc., without redefining structure classes.
  • Document editor theming is scoped under .butex-document-widget. Override --butex-document-* variables on that root or an ancestor, especially --butex-document-bg, --butex-document-fg, --butex-document-panel, --butex-document-border, --butex-document-accent, --butex-document-preview-bg, --butex-document-drawer-bg, --butex-document-input-bg, --butex-document-table-border, --butex-document-math-bg, and --butex-document-dev-bg.
  • Document editor v2 theming is scoped under .butex-document2-widget. Override --butex-document2-* variables on that root or an ancestor; defaults inherit from the existing --butex-* variables where practical, including accent, panel, border, preview, focus, danger/error, and debug colors. The embedded equation editor opens as a centered modal (backdrop + panel); its BuTeX chrome reads the same --butex-document2-* tokens via a scoped bridge, so hosts normally theme once on .butex-document2-widget without a second equation theme. The built-in editor uses a sticky compact icon toolbar (heading glyphs, inline $…$ vs display \[…\] math buttons with tooltips, table size popover), focus-aware block insertion after the active block, ↑/↓ block reorder, math delete (chip × and drawer button), document undo/redo (toolbar + Ctrl/⌘Z, Ctrl/⌘Shift+Z, Ctrl+Y) via AST snapshots, and theme-tinted block cards. Preview tables use fixed black cell borders; raw \raw blocks stay out of preview until dedicated rendering exists.

Demo

From repo root (after npm run build):

npm run demo

Open:

  • http://localhost:4173/demo/ (MathJax + \arabsqrt)
  • http://localhost:4173/demo/parser.html (parser-only normalize preview)
  • 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.
  • 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).
  • 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.

Editor MVP notes (demo/editor-app)

  • Editing is AST-first (not raw LaTeX text editing).
  • End-user UI is Arabic-first.
  • Supported structures in this MVP: chars, numbers, operators, delimiter pairs (), [], {}, fractions (\frac), and sup/sub chains.
  • Caret: Left/Right walk every insertion gap in a fixed depth-first order (baseline and nested chains). Up/Down move between superscript and subscript where applicable (from the baseline, Up prefers superscript and Down prefers subscript when both exist). On the Arabic surface, arrow keys follow RTL progression.
  • Char/number typing: by default keystrokes merge into the same leaf along the caret gap (digits only extend number, letters only extend char). Use the Split leaf typing toolbar control to toggle split mode (one new leaf per keystroke). Delete/Backspace trim inside the merged string when split mode is off.
  • Structural edits are mirrored across Arabic/English trees; text edits apply to the active side.
  • Undo/redo: full-session snapshots (createUndoRedoStacks, pushUndoRedoSnapshot, restoreUndo, restoreRedo). The demo exposes toolbar buttons plus Ctrl+Z / ⌘Z for undo and Ctrl+Shift+Z / ⌘⇧Z / Ctrl+Y for redo while the editing surface is focused. Caret moves and language switching are not recorded so undo targets content edits only. History caps at ~100 steps by default (DEFAULT_UNDO_HISTORY_MAX_DEPTH).
  • Selection + copy/cut/paste: range selection lives at the slot level inside a single chain (no cross-chain selection in the MVP). Whole nodes are the copy unit, so superscripts/subscripts/inner subtrees always travel with their owner.
    • Keyboard: Shift+ArrowLeft/ArrowRight extend selection (RTL-aware), Ctrl/⌘+C/X/V copy/cut/paste, Backspace/Delete and typing replace an active selection.
    • Mouse: click-drag from one slot to another inside the same chain. Cross-chain mouse moves are ignored.
    • Clipboard format: application/x-butex-fragment+json with both EN and AR mirrored nodes (EditorFragment v1) plus a plain-text LaTeX fallback for cross-app pasting. External plain text re-enters through the typing path so split/merge mode applies.
    • Future node types: the single helper nodeChildChains(node) enumerates a node's nested chains. Adding command, env, or math-object kinds (see [references/nodes.py](references/nodes.py)) only requires extending this helper; selection, copy, paste, and id-remap stay unchanged.
  • Debug panels are dev-only (debug prop on <ButexEditor />, or ?debug=1 in the Vite demo URL).
    • Includes LaTeX dump, passive chain preview, and copyable command/render log.

Editor theming (CSS variables)

Override these on :root (or a host container) to customize colors:

  • --butex-bg
  • --butex-fg
  • --butex-muted
  • --butex-accent
  • --butex-border
  • --butex-panel
  • --butex-caret
  • --butex-selected
  • --butex-error
  • --butex-error-bg
  • --butex-accent-hover (optional, demo toolbar)
  • --butex-shadow-sm / --butex-shadow-md (optional, panels)
  • --butex-dev-bg / --butex-dev-border / --butex-dev-badge / --butex-dev-muted (optional, developer-only strips when debug is on)

License

ISC (BuTeX package). MathJax is Apache-2.0 — see upstream.