@drghaliasri/butex 5.6.1 → 6.0.1
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 +49 -3
- package/dist/document2-cli.js +3346 -0
- package/dist/document2-cli.js.map +1 -0
- package/dist/document2.d.mts +55 -2
- package/dist/document2.d.ts +55 -2
- package/dist/document2.js +566 -190
- package/dist/document2.js.map +1 -1
- package/dist/document2.mjs +561 -190
- package/dist/document2.mjs.map +1 -1
- package/dist/react-document2.d.mts +32 -3
- package/dist/react-document2.d.ts +32 -3
- package/dist/react-document2.js +572 -199
- package/dist/react-document2.js.map +1 -1
- package/dist/react-document2.mjs +606 -233
- package/dist/react-document2.mjs.map +1 -1
- package/package.json +11 -1
package/README.md
CHANGED
|
@@ -264,6 +264,47 @@ Figures and tables always export as centered `figure` / `table` floats. Optional
|
|
|
264
264
|
|
|
265
265
|
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.
|
|
266
266
|
|
|
267
|
+
### Headless document commands
|
|
268
|
+
|
|
269
|
+
Canonical `Document2Json` exports include a stable `id` on every block. Legacy input without IDs remains accepted and receives IDs on its next import/export normalization. Use the pure command and outline helpers for server-side session transforms:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import {
|
|
273
|
+
applyDocument2Command,
|
|
274
|
+
document2Outline,
|
|
275
|
+
fromDocumentJson2,
|
|
276
|
+
toDocumentJson2,
|
|
277
|
+
} from '@drghaliasri/butex/document2';
|
|
278
|
+
|
|
279
|
+
const canonical = toDocumentJson2(fromDocumentJson2(legacyDocument));
|
|
280
|
+
const outline = document2Outline(canonical);
|
|
281
|
+
const updated = applyDocument2Command(canonical, {
|
|
282
|
+
op: 'insert_text_block',
|
|
283
|
+
kind: 'paragraph',
|
|
284
|
+
text: 'New session text',
|
|
285
|
+
anchor: { end: true },
|
|
286
|
+
});
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
Commands address top-level blocks only. Insertions require either `{ end: true }` or `{ after_block_id }`; missing anchors fail explicitly. Whole-block text replacement rejects formatted text, citations, references, and math so an agent cannot silently discard structured inline content.
|
|
290
|
+
|
|
291
|
+
### Document worker CLI
|
|
292
|
+
|
|
293
|
+
Node 20+ can run the same transforms through the isolated `butex-document2` executable. One-shot mode reads one request from stdin and writes one response to stdout:
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
printf '%s' '{"action":"normalize","document":{"node_type":"DocumentObject","blocks":[]}}' | butex-document2
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
Railway HTTP mode is stateless and requires a service token:
|
|
300
|
+
|
|
301
|
+
```bash
|
|
302
|
+
BUTEX_WORKER_TOKEN=replace-me PORT=3000 \
|
|
303
|
+
butex-document2 --serve --host 0.0.0.0
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
It exposes `GET /health` plus authenticated `POST /v1/document2/normalize`, `/v1/document2/outline`, and `/v1/document2/commands`. The worker accepts document JSON and returns transformed JSON only. FastAPI remains responsible for user authentication, article/session lookup, revisions, idempotency, S3 persistence, and MCP policy; browsers and agents must never call the worker directly.
|
|
307
|
+
|
|
267
308
|
### Document JSON contract (`value` + `math_objects`)
|
|
268
309
|
|
|
269
310
|
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.
|
|
@@ -403,6 +444,7 @@ After an external upload (for example S3), insert a figure on the **live** edito
|
|
|
403
444
|
import { useRef } from 'react';
|
|
404
445
|
import {
|
|
405
446
|
ButexDocumentEditor2,
|
|
447
|
+
type ImageAssetRef,
|
|
406
448
|
type ButexDocumentEditor2Ref,
|
|
407
449
|
} from '@drghaliasri/butex/react-document2';
|
|
408
450
|
|
|
@@ -410,9 +452,9 @@ export function ArticleEditorWithUpload() {
|
|
|
410
452
|
const editorRef = useRef<ButexDocumentEditor2Ref>(null);
|
|
411
453
|
|
|
412
454
|
async function onFileUploaded(uuid: string) {
|
|
413
|
-
// Sets \\includegraphics{assets/<uuid>.jpg} after the focused block.
|
|
455
|
+
// Sets asset_id and \\includegraphics{assets/<uuid>.jpg} after the focused block.
|
|
414
456
|
// Do not call addDocument2ImageBlock outside the component or remount with key++.
|
|
415
|
-
editorRef.current?.insertImageBlock(`assets/${uuid}.jpg`);
|
|
457
|
+
editorRef.current?.insertImageBlock({ assetId: `assets/${uuid}.jpg` } satisfies ImageAssetRef);
|
|
416
458
|
}
|
|
417
459
|
|
|
418
460
|
return (
|
|
@@ -421,6 +463,10 @@ export function ArticleEditorWithUpload() {
|
|
|
421
463
|
resolveImageUrl={({ assetId, value }) =>
|
|
422
464
|
assetId ? `https://cdn.example/${assetId}` : value
|
|
423
465
|
}
|
|
466
|
+
onRequestImagePick={async ({ current }) => {
|
|
467
|
+
/* open host asset picker; return { assetId, value?, label?, thumbUrl? } or null */
|
|
468
|
+
return current;
|
|
469
|
+
}}
|
|
424
470
|
onDocumentJsonChange={(json) => {
|
|
425
471
|
/* persist json */
|
|
426
472
|
}}
|
|
@@ -429,7 +475,7 @@ export function ArticleEditorWithUpload() {
|
|
|
429
475
|
}
|
|
430
476
|
```
|
|
431
477
|
|
|
432
|
-
`insertImageBlock` matches the toolbar figure button (focus-aware insert + undo snapshot). Use `
|
|
478
|
+
`insertImageBlock` matches the toolbar figure button (focus-aware insert + undo snapshot). Pass `{ assetId, value?, label?, thumbUrl? }` to set both live `assetId` and wire `asset_id`; passing a non-empty string remains supported and treats that string as both `value` and `asset_id`. Use `updateImageBlockAsset(blockId, ref)` to set a host asset on an existing image block, `updateImageBlockValue(blockId, value)` to change only the path value while preserving any existing asset identity, and `getDocumentJson()` to read the canonical wire JSON without host-side AST mutation. BuTeX never uploads image bytes; hosts provide `resolveImageUrl`, optionally `onRequestImagePick`, `listImageAssets`, or `renderImageBlockEditor` for picker/inventory UI.
|
|
433
479
|
|
|
434
480
|
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. Optional `\includegraphics` `asset_id` is preserved on import; pass `resolveImageUrl={({ assetId, value }) => …})` so preview can load S3/CDN/local assets while plain `value` URLs keep working without a resolver. Document JSON may include root `meta` (`title`, `authors`, structured Hijri `date` `{ day, month, year }` with Arabic month names such as `"محرم"`, `abstract`) plus a `references` catalog (`key`, `authors`, `title`, `year`, `url`, `venue`) and `\cite{key1,key2}` spans in text values. Pass `documentMeta` to seed missing meta fields from the host; JSON keys win when present. The editor always centers a fixed basmala line before the title block and a closing ḥamdala after the body (preview + LaTeX). Hijri date uses day/month/year dropdowns (no calendar conversion; default year 1448). The editor shows numeric cite chips and a bibliography block. RTL preview/chips render reversed labels such as `[٣،٢،١]` (Arabic comma); LTR stays `[1, 2, 3]`. Pass `digitForm` (`western` / `arabicIndic` / `persianIndic`, defaulting from `documentDirection`) or use the toolbar digit control. LaTeX export keeps logical `\cite{…}` key order for XeLaTeX; digit shaping and bidi display in PDF belong in the host preamble (`bidi`/polyglossia + font `Mapping`, see `references/commands.py`). Range compression (`[3–7]`) is not implemented yet. 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"`.
|
|
435
481
|
|