@drghaliasri/butex 5.4.6 → 5.5.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
@@ -253,7 +253,7 @@ const latex = document2Latex(documentNode);
253
253
  const preview = document2Preview(documentNode, 'svg');
254
254
  ```
255
255
 
256
- `document2Latex(doc)` emits a **complete Arabic XeLaTeX document** by default (preamble + `\begin{document}` + body + `\end{document}`). Pass `{ wrapDocument: false }` for body-only blocks. Optional `digitsMapping: 'arabicdigits' | 'digits'` controls eastern vs western digit font mapping in the preamble (default `'arabicdigits'`). Pass `{ twocolumn: true }` for `\documentclass[12pt,a4paper,notitlepage,twocolumn]{article}` (title block stays in-column; figures use `\columnwidth`). See [`examples/example-latex-export.tex`](examples/example-latex-export.tex) for a full sample (regenerated by the wrap vitest). Hosts can also call `getArabicXeLatexPreamble()` alone.
256
+ `document2Latex(doc)` emits a **complete Arabic XeLaTeX document** by default (preamble + `\begin{document}` + body + `\end{document}`). Pass `{ wrapDocument: false }` for body-only blocks. Paragraph blocks export as `\par` followed by the inline content, so prose, citations, and math are not wrapped inside `\paragraph{...}`. Optional `digitsMapping: 'arabicdigits' | 'digits'` controls eastern vs western digit font mapping in the preamble (default `'arabicdigits'`). Pass `{ twocolumn: true }` for `\documentclass[12pt,a4paper,notitlepage,twocolumn]{article}` (title block stays in-column; figures use `\columnwidth`). See [`examples/example-latex-export.tex`](examples/example-latex-export.tex) for a full sample (regenerated by the wrap vitest). Hosts can also call `getArabicXeLatexPreamble()` alone.
257
257
 
258
258
  Figures and tables always export as centered `figure` / `table` floats. Optional caption/label fields (checkbox-driven in the editor) emit `\caption` / `\label`. Display math stays `\[…\]` unless an equation label is enabled, then export uses `\begin{equation}…\label{…}\end{equation}`. Internal cross-refs use `\ref` / `\eqref` tokens (separate from bibliography `\cite`).
259
259
 
@@ -343,7 +343,7 @@ Host apps still register BuTeX with MathJax before preview rendering. `uiLocale`
343
343
  - Core editor classes (`.surface`, `.chain`, `.slot`, `.node`, `.scripts`, `.delim*`, etc.) are shipped from `src/editor/styles.ts`.
344
344
  - 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.
345
345
  - 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`.
346
- - 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.
346
+ - 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** (Arabic `نص` formatting icons, heading glyphs, inline `$…$` vs display `\[…\]` math buttons with tooltips, a labeled references menu, and a 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.
347
347
 
348
348
  ## Demo
349
349
 
@@ -175,6 +175,7 @@ type Document2Json = {
175
175
  type Document2BlockJson = {
176
176
  command: string;
177
177
  value?: string;
178
+ formats?: TextFormatSpan2Json[];
178
179
  /** Stable host asset identity (e.g. S3 key / UUID); optional for \\includegraphics. */
179
180
  asset_id?: string;
180
181
  math_objects?: MathObject2Json[];
@@ -182,6 +183,7 @@ type Document2BlockJson = {
182
183
  closing?: string;
183
184
  items?: Document2ListItemJson[];
184
185
  rows?: string[][];
186
+ cell_formats?: TextFormatSpan2Json[][][];
185
187
  columns?: string;
186
188
  caption?: string;
187
189
  label?: string;
@@ -191,6 +193,7 @@ type Document2BlockJson = {
191
193
  };
192
194
  type Document2ListItemJson = {
193
195
  value: string;
196
+ formats?: TextFormatSpan2Json[];
194
197
  math_objects?: MathObject2Json[];
195
198
  blocks?: Document2BlockJson[];
196
199
  };
@@ -210,10 +213,23 @@ type Reference2 = {
210
213
  /** Joins authors/title/venue/year in bibliography display and export. */
211
214
  fieldSeparator: ReferenceFieldSeparator;
212
215
  };
216
+ type TextStyle2 = {
217
+ bold?: true;
218
+ italic?: true;
219
+ underline?: true;
220
+ };
221
+ type TextFormatSpan2Json = {
222
+ start: number;
223
+ end: number;
224
+ bold?: boolean;
225
+ italic?: boolean;
226
+ underline?: boolean;
227
+ };
213
228
  type TextToken2 = {
214
229
  id: string;
215
230
  kind: 'text';
216
231
  text: string;
232
+ style?: TextStyle2;
217
233
  };
218
234
  type MathToken2 = {
219
235
  id: string;
@@ -344,6 +360,7 @@ type DetectedInlineSpan2 = ({
344
360
  type PreviewInline2 = {
345
361
  kind: 'text';
346
362
  text: string;
363
+ style?: TextStyle2;
347
364
  } | {
348
365
  kind: 'math';
349
366
  id: string;
@@ -570,6 +587,7 @@ declare function insertDocument2BlockAfter(document: Document2Node, afterBlockId
570
587
  declare function moveDocument2BlockById(document: Document2Node, blockId: string, direction: -1 | 1): Document2Node;
571
588
  declare function moveDocument2BlockRange(document: Document2Node, from: number, to: number, direction: -1 | 1): Document2Node;
572
589
  declare function removeDocument2BlockRange(document: Document2Node, from: number, to: number): Document2Node;
590
+ declare function toggleTextTokenStyle(document: Document2Node, fieldId: string, tokenId: string, selectionStart: number, selectionEnd: number, styleName: keyof TextStyle2): Document2Node;
573
591
  declare function removeMathTokenById(document: Document2Node, tokenId: string): Document2Node;
574
592
  declare function insertMathTokenAtCaret(document: Document2Node, fieldId: string, textTokenId: string | null, caretOffset: number, session: EditorSession, opening?: string, closing?: string, side?: EditorSide): Document2Node;
575
593
  declare function insertMathToken(document: Document2Node, fieldId: string, insertIndex: number, session: EditorSession, opening?: string, closing?: string, side?: EditorSide): Document2Node;
@@ -699,7 +717,7 @@ declare function toggleBlockInSelection(state: BlockSelectionState, index: numbe
699
717
  declare function extendBlockSelectionFromAnchor(state: BlockSelectionState, index: number, blockCount: number): BlockSelectionState;
700
718
  declare function remapSelectionAfterRangeMove(selection: BlockSelectionRange, direction: -1 | 1): BlockSelectionRange;
701
719
 
702
- declare function createInlineField2(value?: string, mathObjects?: MathObject2Json[], options?: ImportDocument2Options, path?: string, diagnostics?: Document2Diagnostic[]): InlineField2;
720
+ declare function createInlineField2(value?: string, mathObjects?: MathObject2Json[], options?: ImportDocument2Options, path?: string, diagnostics?: Document2Diagnostic[], formats?: TextFormatSpan2Json[]): InlineField2;
703
721
  declare function fromDocumentJson2(json: unknown, options?: ImportDocument2Options): Document2Node;
704
722
  declare function createEmptyDocument2(): Document2Node;
705
723
 
@@ -732,4 +750,4 @@ type Document2PreviewOptions = {
732
750
  };
733
751
  declare function document2Preview(document: Document2Node, output?: Document2MathOutput, equationSide?: EditorSide, previewOptions?: Document2PreviewOptions): Document2Preview;
734
752
 
735
- export { type ArabicDigitsMapping, type ArabicXeLatexPreambleOptions, BUTEX_BASMALA, BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT, BUTEX_CLOSING_HAMDALA, type BibliographyBlock2, type BlockSelectionRange, type BlockSelectionState, type CiteToken2, DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH, DEFAULT_HIJRI_DATE, DEFAULT_REFERENCE_FIELD_SEPARATOR, type Document2Block, type Document2BlockJson, type Document2Diagnostic, type Document2Direction, type Document2HijriDate, type Document2HistoryStacks, type Document2Json, type Document2KeyError, type Document2KeyNamespace, type Document2LabelEntry, type Document2LabelKind, type Document2LatexOptions, type Document2MathOutput, type Document2Meta, type Document2MetaProp, type Document2Node, type Document2Preview, type Document2PreviewOptions, type FloatMeta2, type FloatMetaPatch, type FormatCiteLabelOptions, type FormatFloatCaptionTitleOptions, HIJRI_MONTH_IDS, HIJRI_YEAR_MAX, HIJRI_YEAR_MIN, type HijriMonthId, type ImageBlock2, type ImportDocument2Options, type InlineField2, type InlineToken2, type ListBlock2, type MathIsland2, type MathObject2Json, type MathToken2, type PreviewBlock2, type PreviewInline2, type RawBlock2, type RefToken2, type Reference2, type Reference2Json, type ReferenceFieldSeparator, type TableBlock2, type TextBlock2, type TextToken2, absoluteHttpHref, addDocument2ImageBlock, addDocument2ListBlock, addDocument2ListItem, addDocument2Reference, addDocument2TableBlock, addDocument2TextBlock, applyFloatMetaPatch, arabicXeLatexPreambleCmd, arabicXeLatexPreambleFont, arabicXeLatexPreamblePkg, bibliographyEntryBody, bibliographyEntryLatex, butexBasmalaDisplayLatex, butexBasmalaDisplayTex, butexBasmalaTitlingPreamble, butexDiwaniDisplayLatex, butexDiwaniDisplayTex, butexInColumnMaketitleHook, citeTokenLatex, cloneDocument2Meta, cloneDocument2Node, collectDocument2Labels, createDocument2History, createEmptyArabicEquationSession, createEmptyDocument2, createEmptyEquationSession, createEmptyReference2, createInlineField2, defaultFloatMeta, detectInlineSpans2, detectMathSpans2, document2HasAbstract, document2HasMaketitle, document2HasTitleStack, document2HistoryCanRedo, document2HistoryCanUndo, document2KeyError, document2Latex, document2Preview, emptyBlockSelection, emptyDocument2Meta, ensureDocument2BibliographyBlock, extendBlockSelectionFromAnchor, fillDocument2MetaGaps, findFirstInlineField, formatBibliographyNumber, formatCiteLabel, formatFloatCaptionPreview, formatFloatCaptionTitle, formatHijriDate, formatRefLabel, fromDocumentJson2, getArabicXeLatexPreamble, hijriMonthLabel, inlineFieldLatex, insertCiteTokenAtCaret, insertDocument2BlockAfter, insertMathToken, insertMathTokenAtCaret, insertRefTokenAtCaret, isDuplicateDocument2Key, isValidDocument2Key, labelNumberMap, mathNodeFromArabicSession, mathNodeFromSession, mathSourceFromArabicSession, mathSourceFromSession, mathTokenSourceForSide, mathTokenToArabicEditorSession, mathTokenToEditorSession, mergeDocument2Meta, moveDocument2BlockById, moveDocument2BlockRange, moveDocument2Reference, normalizeBlockSelection, normalizeDocument2HijriDate, normalizeDocument2Key, normalizeDocument2Meta, normalizeReferenceFieldSeparator, parseCiteKeys, parseFloatMetaFromJson, parseRefKeys, pushDocument2Snapshot, refTokenLatex, referenceFromJson, referenceNumberMap, remapSelectionAfterRangeMove, removeCiteTokenById, removeDocument2BlockById, removeDocument2BlockRange, removeDocument2ListItem, removeDocument2Reference, removeMathTokenById, removeRefTokenById, replaceMathTokenFromSession, resolveCiteNumbers, restoreDocument2Redo, restoreDocument2Undo, setDocument2References, stripDisplayMathDelimiters, toggleBlockInSelection, updateCiteTokenKeys, updateDocument2ImageMeta, updateDocument2ImageValue, updateDocument2Meta, updateDocument2Reference, updateDocument2TableMeta, updateDocument2TextBlockCentered, updateMathTokenLabel, updateRefTokenKeys, updateTextToken };
753
+ export { type ArabicDigitsMapping, type ArabicXeLatexPreambleOptions, BUTEX_BASMALA, BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT, BUTEX_CLOSING_HAMDALA, type BibliographyBlock2, type BlockSelectionRange, type BlockSelectionState, type CiteToken2, DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH, DEFAULT_HIJRI_DATE, DEFAULT_REFERENCE_FIELD_SEPARATOR, type Document2Block, type Document2BlockJson, type Document2Diagnostic, type Document2Direction, type Document2HijriDate, type Document2HistoryStacks, type Document2Json, type Document2KeyError, type Document2KeyNamespace, type Document2LabelEntry, type Document2LabelKind, type Document2LatexOptions, type Document2MathOutput, type Document2Meta, type Document2MetaProp, type Document2Node, type Document2Preview, type Document2PreviewOptions, type FloatMeta2, type FloatMetaPatch, type FormatCiteLabelOptions, type FormatFloatCaptionTitleOptions, HIJRI_MONTH_IDS, HIJRI_YEAR_MAX, HIJRI_YEAR_MIN, type HijriMonthId, type ImageBlock2, type ImportDocument2Options, type InlineField2, type InlineToken2, type ListBlock2, type MathIsland2, type MathObject2Json, type MathToken2, type PreviewBlock2, type PreviewInline2, type RawBlock2, type RefToken2, type Reference2, type Reference2Json, type ReferenceFieldSeparator, type TableBlock2, type TextBlock2, type TextFormatSpan2Json, type TextStyle2, type TextToken2, absoluteHttpHref, addDocument2ImageBlock, addDocument2ListBlock, addDocument2ListItem, addDocument2Reference, addDocument2TableBlock, addDocument2TextBlock, applyFloatMetaPatch, arabicXeLatexPreambleCmd, arabicXeLatexPreambleFont, arabicXeLatexPreamblePkg, bibliographyEntryBody, bibliographyEntryLatex, butexBasmalaDisplayLatex, butexBasmalaDisplayTex, butexBasmalaTitlingPreamble, butexDiwaniDisplayLatex, butexDiwaniDisplayTex, butexInColumnMaketitleHook, citeTokenLatex, cloneDocument2Meta, cloneDocument2Node, collectDocument2Labels, createDocument2History, createEmptyArabicEquationSession, createEmptyDocument2, createEmptyEquationSession, createEmptyReference2, createInlineField2, defaultFloatMeta, detectInlineSpans2, detectMathSpans2, document2HasAbstract, document2HasMaketitle, document2HasTitleStack, document2HistoryCanRedo, document2HistoryCanUndo, document2KeyError, document2Latex, document2Preview, emptyBlockSelection, emptyDocument2Meta, ensureDocument2BibliographyBlock, extendBlockSelectionFromAnchor, fillDocument2MetaGaps, findFirstInlineField, formatBibliographyNumber, formatCiteLabel, formatFloatCaptionPreview, formatFloatCaptionTitle, formatHijriDate, formatRefLabel, fromDocumentJson2, getArabicXeLatexPreamble, hijriMonthLabel, inlineFieldLatex, insertCiteTokenAtCaret, insertDocument2BlockAfter, insertMathToken, insertMathTokenAtCaret, insertRefTokenAtCaret, isDuplicateDocument2Key, isValidDocument2Key, labelNumberMap, mathNodeFromArabicSession, mathNodeFromSession, mathSourceFromArabicSession, mathSourceFromSession, mathTokenSourceForSide, mathTokenToArabicEditorSession, mathTokenToEditorSession, mergeDocument2Meta, moveDocument2BlockById, moveDocument2BlockRange, moveDocument2Reference, normalizeBlockSelection, normalizeDocument2HijriDate, normalizeDocument2Key, normalizeDocument2Meta, normalizeReferenceFieldSeparator, parseCiteKeys, parseFloatMetaFromJson, parseRefKeys, pushDocument2Snapshot, refTokenLatex, referenceFromJson, referenceNumberMap, remapSelectionAfterRangeMove, removeCiteTokenById, removeDocument2BlockById, removeDocument2BlockRange, removeDocument2ListItem, removeDocument2Reference, removeMathTokenById, removeRefTokenById, replaceMathTokenFromSession, resolveCiteNumbers, restoreDocument2Redo, restoreDocument2Undo, setDocument2References, stripDisplayMathDelimiters, toggleBlockInSelection, toggleTextTokenStyle, updateCiteTokenKeys, updateDocument2ImageMeta, updateDocument2ImageValue, updateDocument2Meta, updateDocument2Reference, updateDocument2TableMeta, updateDocument2TextBlockCentered, updateMathTokenLabel, updateRefTokenKeys, updateTextToken };
@@ -175,6 +175,7 @@ type Document2Json = {
175
175
  type Document2BlockJson = {
176
176
  command: string;
177
177
  value?: string;
178
+ formats?: TextFormatSpan2Json[];
178
179
  /** Stable host asset identity (e.g. S3 key / UUID); optional for \\includegraphics. */
179
180
  asset_id?: string;
180
181
  math_objects?: MathObject2Json[];
@@ -182,6 +183,7 @@ type Document2BlockJson = {
182
183
  closing?: string;
183
184
  items?: Document2ListItemJson[];
184
185
  rows?: string[][];
186
+ cell_formats?: TextFormatSpan2Json[][][];
185
187
  columns?: string;
186
188
  caption?: string;
187
189
  label?: string;
@@ -191,6 +193,7 @@ type Document2BlockJson = {
191
193
  };
192
194
  type Document2ListItemJson = {
193
195
  value: string;
196
+ formats?: TextFormatSpan2Json[];
194
197
  math_objects?: MathObject2Json[];
195
198
  blocks?: Document2BlockJson[];
196
199
  };
@@ -210,10 +213,23 @@ type Reference2 = {
210
213
  /** Joins authors/title/venue/year in bibliography display and export. */
211
214
  fieldSeparator: ReferenceFieldSeparator;
212
215
  };
216
+ type TextStyle2 = {
217
+ bold?: true;
218
+ italic?: true;
219
+ underline?: true;
220
+ };
221
+ type TextFormatSpan2Json = {
222
+ start: number;
223
+ end: number;
224
+ bold?: boolean;
225
+ italic?: boolean;
226
+ underline?: boolean;
227
+ };
213
228
  type TextToken2 = {
214
229
  id: string;
215
230
  kind: 'text';
216
231
  text: string;
232
+ style?: TextStyle2;
217
233
  };
218
234
  type MathToken2 = {
219
235
  id: string;
@@ -344,6 +360,7 @@ type DetectedInlineSpan2 = ({
344
360
  type PreviewInline2 = {
345
361
  kind: 'text';
346
362
  text: string;
363
+ style?: TextStyle2;
347
364
  } | {
348
365
  kind: 'math';
349
366
  id: string;
@@ -570,6 +587,7 @@ declare function insertDocument2BlockAfter(document: Document2Node, afterBlockId
570
587
  declare function moveDocument2BlockById(document: Document2Node, blockId: string, direction: -1 | 1): Document2Node;
571
588
  declare function moveDocument2BlockRange(document: Document2Node, from: number, to: number, direction: -1 | 1): Document2Node;
572
589
  declare function removeDocument2BlockRange(document: Document2Node, from: number, to: number): Document2Node;
590
+ declare function toggleTextTokenStyle(document: Document2Node, fieldId: string, tokenId: string, selectionStart: number, selectionEnd: number, styleName: keyof TextStyle2): Document2Node;
573
591
  declare function removeMathTokenById(document: Document2Node, tokenId: string): Document2Node;
574
592
  declare function insertMathTokenAtCaret(document: Document2Node, fieldId: string, textTokenId: string | null, caretOffset: number, session: EditorSession, opening?: string, closing?: string, side?: EditorSide): Document2Node;
575
593
  declare function insertMathToken(document: Document2Node, fieldId: string, insertIndex: number, session: EditorSession, opening?: string, closing?: string, side?: EditorSide): Document2Node;
@@ -699,7 +717,7 @@ declare function toggleBlockInSelection(state: BlockSelectionState, index: numbe
699
717
  declare function extendBlockSelectionFromAnchor(state: BlockSelectionState, index: number, blockCount: number): BlockSelectionState;
700
718
  declare function remapSelectionAfterRangeMove(selection: BlockSelectionRange, direction: -1 | 1): BlockSelectionRange;
701
719
 
702
- declare function createInlineField2(value?: string, mathObjects?: MathObject2Json[], options?: ImportDocument2Options, path?: string, diagnostics?: Document2Diagnostic[]): InlineField2;
720
+ declare function createInlineField2(value?: string, mathObjects?: MathObject2Json[], options?: ImportDocument2Options, path?: string, diagnostics?: Document2Diagnostic[], formats?: TextFormatSpan2Json[]): InlineField2;
703
721
  declare function fromDocumentJson2(json: unknown, options?: ImportDocument2Options): Document2Node;
704
722
  declare function createEmptyDocument2(): Document2Node;
705
723
 
@@ -732,4 +750,4 @@ type Document2PreviewOptions = {
732
750
  };
733
751
  declare function document2Preview(document: Document2Node, output?: Document2MathOutput, equationSide?: EditorSide, previewOptions?: Document2PreviewOptions): Document2Preview;
734
752
 
735
- export { type ArabicDigitsMapping, type ArabicXeLatexPreambleOptions, BUTEX_BASMALA, BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT, BUTEX_CLOSING_HAMDALA, type BibliographyBlock2, type BlockSelectionRange, type BlockSelectionState, type CiteToken2, DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH, DEFAULT_HIJRI_DATE, DEFAULT_REFERENCE_FIELD_SEPARATOR, type Document2Block, type Document2BlockJson, type Document2Diagnostic, type Document2Direction, type Document2HijriDate, type Document2HistoryStacks, type Document2Json, type Document2KeyError, type Document2KeyNamespace, type Document2LabelEntry, type Document2LabelKind, type Document2LatexOptions, type Document2MathOutput, type Document2Meta, type Document2MetaProp, type Document2Node, type Document2Preview, type Document2PreviewOptions, type FloatMeta2, type FloatMetaPatch, type FormatCiteLabelOptions, type FormatFloatCaptionTitleOptions, HIJRI_MONTH_IDS, HIJRI_YEAR_MAX, HIJRI_YEAR_MIN, type HijriMonthId, type ImageBlock2, type ImportDocument2Options, type InlineField2, type InlineToken2, type ListBlock2, type MathIsland2, type MathObject2Json, type MathToken2, type PreviewBlock2, type PreviewInline2, type RawBlock2, type RefToken2, type Reference2, type Reference2Json, type ReferenceFieldSeparator, type TableBlock2, type TextBlock2, type TextToken2, absoluteHttpHref, addDocument2ImageBlock, addDocument2ListBlock, addDocument2ListItem, addDocument2Reference, addDocument2TableBlock, addDocument2TextBlock, applyFloatMetaPatch, arabicXeLatexPreambleCmd, arabicXeLatexPreambleFont, arabicXeLatexPreamblePkg, bibliographyEntryBody, bibliographyEntryLatex, butexBasmalaDisplayLatex, butexBasmalaDisplayTex, butexBasmalaTitlingPreamble, butexDiwaniDisplayLatex, butexDiwaniDisplayTex, butexInColumnMaketitleHook, citeTokenLatex, cloneDocument2Meta, cloneDocument2Node, collectDocument2Labels, createDocument2History, createEmptyArabicEquationSession, createEmptyDocument2, createEmptyEquationSession, createEmptyReference2, createInlineField2, defaultFloatMeta, detectInlineSpans2, detectMathSpans2, document2HasAbstract, document2HasMaketitle, document2HasTitleStack, document2HistoryCanRedo, document2HistoryCanUndo, document2KeyError, document2Latex, document2Preview, emptyBlockSelection, emptyDocument2Meta, ensureDocument2BibliographyBlock, extendBlockSelectionFromAnchor, fillDocument2MetaGaps, findFirstInlineField, formatBibliographyNumber, formatCiteLabel, formatFloatCaptionPreview, formatFloatCaptionTitle, formatHijriDate, formatRefLabel, fromDocumentJson2, getArabicXeLatexPreamble, hijriMonthLabel, inlineFieldLatex, insertCiteTokenAtCaret, insertDocument2BlockAfter, insertMathToken, insertMathTokenAtCaret, insertRefTokenAtCaret, isDuplicateDocument2Key, isValidDocument2Key, labelNumberMap, mathNodeFromArabicSession, mathNodeFromSession, mathSourceFromArabicSession, mathSourceFromSession, mathTokenSourceForSide, mathTokenToArabicEditorSession, mathTokenToEditorSession, mergeDocument2Meta, moveDocument2BlockById, moveDocument2BlockRange, moveDocument2Reference, normalizeBlockSelection, normalizeDocument2HijriDate, normalizeDocument2Key, normalizeDocument2Meta, normalizeReferenceFieldSeparator, parseCiteKeys, parseFloatMetaFromJson, parseRefKeys, pushDocument2Snapshot, refTokenLatex, referenceFromJson, referenceNumberMap, remapSelectionAfterRangeMove, removeCiteTokenById, removeDocument2BlockById, removeDocument2BlockRange, removeDocument2ListItem, removeDocument2Reference, removeMathTokenById, removeRefTokenById, replaceMathTokenFromSession, resolveCiteNumbers, restoreDocument2Redo, restoreDocument2Undo, setDocument2References, stripDisplayMathDelimiters, toggleBlockInSelection, updateCiteTokenKeys, updateDocument2ImageMeta, updateDocument2ImageValue, updateDocument2Meta, updateDocument2Reference, updateDocument2TableMeta, updateDocument2TextBlockCentered, updateMathTokenLabel, updateRefTokenKeys, updateTextToken };
753
+ export { type ArabicDigitsMapping, type ArabicXeLatexPreambleOptions, BUTEX_BASMALA, BUTEX_BASMALA_LINE1, BUTEX_BASMALA_LINE2, BUTEX_BASMALA_SALAWAT, BUTEX_CLOSING_HAMDALA, type BibliographyBlock2, type BlockSelectionRange, type BlockSelectionState, type CiteToken2, DEFAULT_DOCUMENT2_HISTORY_MAX_DEPTH, DEFAULT_HIJRI_DATE, DEFAULT_REFERENCE_FIELD_SEPARATOR, type Document2Block, type Document2BlockJson, type Document2Diagnostic, type Document2Direction, type Document2HijriDate, type Document2HistoryStacks, type Document2Json, type Document2KeyError, type Document2KeyNamespace, type Document2LabelEntry, type Document2LabelKind, type Document2LatexOptions, type Document2MathOutput, type Document2Meta, type Document2MetaProp, type Document2Node, type Document2Preview, type Document2PreviewOptions, type FloatMeta2, type FloatMetaPatch, type FormatCiteLabelOptions, type FormatFloatCaptionTitleOptions, HIJRI_MONTH_IDS, HIJRI_YEAR_MAX, HIJRI_YEAR_MIN, type HijriMonthId, type ImageBlock2, type ImportDocument2Options, type InlineField2, type InlineToken2, type ListBlock2, type MathIsland2, type MathObject2Json, type MathToken2, type PreviewBlock2, type PreviewInline2, type RawBlock2, type RefToken2, type Reference2, type Reference2Json, type ReferenceFieldSeparator, type TableBlock2, type TextBlock2, type TextFormatSpan2Json, type TextStyle2, type TextToken2, absoluteHttpHref, addDocument2ImageBlock, addDocument2ListBlock, addDocument2ListItem, addDocument2Reference, addDocument2TableBlock, addDocument2TextBlock, applyFloatMetaPatch, arabicXeLatexPreambleCmd, arabicXeLatexPreambleFont, arabicXeLatexPreamblePkg, bibliographyEntryBody, bibliographyEntryLatex, butexBasmalaDisplayLatex, butexBasmalaDisplayTex, butexBasmalaTitlingPreamble, butexDiwaniDisplayLatex, butexDiwaniDisplayTex, butexInColumnMaketitleHook, citeTokenLatex, cloneDocument2Meta, cloneDocument2Node, collectDocument2Labels, createDocument2History, createEmptyArabicEquationSession, createEmptyDocument2, createEmptyEquationSession, createEmptyReference2, createInlineField2, defaultFloatMeta, detectInlineSpans2, detectMathSpans2, document2HasAbstract, document2HasMaketitle, document2HasTitleStack, document2HistoryCanRedo, document2HistoryCanUndo, document2KeyError, document2Latex, document2Preview, emptyBlockSelection, emptyDocument2Meta, ensureDocument2BibliographyBlock, extendBlockSelectionFromAnchor, fillDocument2MetaGaps, findFirstInlineField, formatBibliographyNumber, formatCiteLabel, formatFloatCaptionPreview, formatFloatCaptionTitle, formatHijriDate, formatRefLabel, fromDocumentJson2, getArabicXeLatexPreamble, hijriMonthLabel, inlineFieldLatex, insertCiteTokenAtCaret, insertDocument2BlockAfter, insertMathToken, insertMathTokenAtCaret, insertRefTokenAtCaret, isDuplicateDocument2Key, isValidDocument2Key, labelNumberMap, mathNodeFromArabicSession, mathNodeFromSession, mathSourceFromArabicSession, mathSourceFromSession, mathTokenSourceForSide, mathTokenToArabicEditorSession, mathTokenToEditorSession, mergeDocument2Meta, moveDocument2BlockById, moveDocument2BlockRange, moveDocument2Reference, normalizeBlockSelection, normalizeDocument2HijriDate, normalizeDocument2Key, normalizeDocument2Meta, normalizeReferenceFieldSeparator, parseCiteKeys, parseFloatMetaFromJson, parseRefKeys, pushDocument2Snapshot, refTokenLatex, referenceFromJson, referenceNumberMap, remapSelectionAfterRangeMove, removeCiteTokenById, removeDocument2BlockById, removeDocument2BlockRange, removeDocument2ListItem, removeDocument2Reference, removeMathTokenById, removeRefTokenById, replaceMathTokenFromSession, resolveCiteNumbers, restoreDocument2Redo, restoreDocument2Undo, setDocument2References, stripDisplayMathDelimiters, toggleBlockInSelection, toggleTextTokenStyle, updateCiteTokenKeys, updateDocument2ImageMeta, updateDocument2ImageValue, updateDocument2Meta, updateDocument2Reference, updateDocument2TableMeta, updateDocument2TextBlockCentered, updateMathTokenLabel, updateRefTokenKeys, updateTextToken };
package/dist/document2.js CHANGED
@@ -133,6 +133,7 @@ __export(document2_exports, {
133
133
  setDocument2References: () => setDocument2References,
134
134
  stripDisplayMathDelimiters: () => stripDisplayMathDelimiters,
135
135
  toggleBlockInSelection: () => toggleBlockInSelection,
136
+ toggleTextTokenStyle: () => toggleTextTokenStyle,
136
137
  updateCiteTokenKeys: () => updateCiteTokenKeys,
137
138
  updateDocument2ImageMeta: () => updateDocument2ImageMeta,
138
139
  updateDocument2ImageValue: () => updateDocument2ImageValue,
@@ -1281,7 +1282,7 @@ function parseReferences(json) {
1281
1282
  }
1282
1283
  return references;
1283
1284
  }
1284
- function createInlineField2(value = "", mathObjects = [], options = {}, path = "$", diagnostics = []) {
1285
+ function createInlineField2(value = "", mathObjects = [], options = {}, path = "$", diagnostics = [], formats = []) {
1285
1286
  const mode = options.mode ?? "english";
1286
1287
  const spans = detectInlineSpans2(value);
1287
1288
  const mathSpans = spans.filter((span) => span.kind === "math");
@@ -1293,7 +1294,7 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
1293
1294
  }
1294
1295
  for (const span of spans) {
1295
1296
  if (span.start > index) {
1296
- tokens.push({ id: document2Id("text"), kind: "text", text: value.slice(index, span.start) });
1297
+ pushFormattedTextTokens(tokens, value.slice(index, span.start), index, formats);
1297
1298
  }
1298
1299
  if (span.kind === "cite") {
1299
1300
  tokens.push({
@@ -1349,9 +1350,81 @@ function createInlineField2(value = "", mathObjects = [], options = {}, path = "
1349
1350
  index = span.end;
1350
1351
  }
1351
1352
  if (index < value.length || tokens.length === 0) {
1352
- tokens.push({ id: document2Id("text"), kind: "text", text: value.slice(index) });
1353
+ pushFormattedTextTokens(tokens, value.slice(index), index, formats);
1354
+ }
1355
+ return { id: document2Id("field"), tokens: compactTextTokens(tokens) };
1356
+ }
1357
+ function styleFromFormat(format) {
1358
+ const style = {};
1359
+ if (format.bold === true) {
1360
+ style.bold = true;
1361
+ }
1362
+ if (format.italic === true) {
1363
+ style.italic = true;
1364
+ }
1365
+ if (format.underline === true) {
1366
+ style.underline = true;
1367
+ }
1368
+ return style.bold || style.italic || style.underline ? style : null;
1369
+ }
1370
+ function mergeTextStyle(base, added) {
1371
+ return {
1372
+ ...base?.bold ? { bold: true } : {},
1373
+ ...base?.italic ? { italic: true } : {},
1374
+ ...base?.underline ? { underline: true } : {},
1375
+ ...added.bold ? { bold: true } : {},
1376
+ ...added.italic ? { italic: true } : {},
1377
+ ...added.underline ? { underline: true } : {}
1378
+ };
1379
+ }
1380
+ function textStylesEqual(a, b) {
1381
+ return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
1382
+ }
1383
+ function compactTextTokens(tokens) {
1384
+ const compacted = [];
1385
+ for (const token of tokens) {
1386
+ const previous = compacted[compacted.length - 1];
1387
+ if (previous?.kind === "text" && token.kind === "text" && textStylesEqual(previous.style, token.style)) {
1388
+ previous.text += token.text;
1389
+ } else {
1390
+ compacted.push(token);
1391
+ }
1392
+ }
1393
+ return compacted;
1394
+ }
1395
+ function styleKey(style) {
1396
+ return `${style?.bold ? "b" : ""}${style?.italic ? "i" : ""}${style?.underline ? "u" : ""}`;
1397
+ }
1398
+ function pushFormattedTextTokens(tokens, text, sourceStart, formats) {
1399
+ if (text.length === 0) {
1400
+ tokens.push({ id: document2Id("text"), kind: "text", text });
1401
+ return;
1402
+ }
1403
+ const styles = Array.from({ length: text.length });
1404
+ for (const format of formats) {
1405
+ const style = styleFromFormat(format);
1406
+ if (!style || !Number.isFinite(format.start) || !Number.isFinite(format.end)) {
1407
+ continue;
1408
+ }
1409
+ const start = Math.max(0, Math.min(text.length, Math.trunc(format.start) - sourceStart));
1410
+ const end = Math.max(0, Math.min(text.length, Math.trunc(format.end) - sourceStart));
1411
+ if (end <= start) {
1412
+ continue;
1413
+ }
1414
+ for (let index = start; index < end; index += 1) {
1415
+ styles[index] = mergeTextStyle(styles[index], style);
1416
+ }
1417
+ }
1418
+ let chunkStart = 0;
1419
+ for (let index = 1; index <= text.length; index += 1) {
1420
+ if (index < text.length && styleKey(styles[index]) === styleKey(styles[chunkStart])) {
1421
+ continue;
1422
+ }
1423
+ const chunk = text.slice(chunkStart, index);
1424
+ const style = styles[chunkStart];
1425
+ tokens.push({ id: document2Id("text"), kind: "text", text: chunk, ...style ? { style } : {} });
1426
+ chunkStart = index;
1353
1427
  }
1354
- return { id: document2Id("field"), tokens };
1355
1428
  }
1356
1429
  function closingForList(command) {
1357
1430
  return command === "\\begin{itemize}" ? "\\end{itemize}" : "\\end{enumerate}";
@@ -1362,7 +1435,7 @@ function parseTextBlock(json, options, path, diagnostics) {
1362
1435
  id: document2Id("block"),
1363
1436
  kind: "textBlock",
1364
1437
  command: json.command,
1365
- field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics),
1438
+ field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.command === "\\paragraph" ? json.formats ?? [] : []),
1366
1439
  ...json.centered === true ? { centered: true } : {}
1367
1440
  };
1368
1441
  }
@@ -1371,7 +1444,7 @@ function parseListItem(json, options, path, diagnostics) {
1371
1444
  const blocksJson = Array.isArray(json.blocks) ? json.blocks : [];
1372
1445
  return {
1373
1446
  id: document2Id("item"),
1374
- field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics),
1447
+ field: createInlineField2(value, json.math_objects ?? [], options, `${path}.value`, diagnostics, json.formats ?? []),
1375
1448
  blocks: blocksJson.map((block, index) => parseBlock(asBlockJson(block), options, `${path}.blocks[${String(index)}]`, diagnostics))
1376
1449
  };
1377
1450
  }
@@ -1404,7 +1477,8 @@ function parseTableBlock(json, options, path, diagnostics) {
1404
1477
  const spanCount = detectMathSpans2(value).length;
1405
1478
  const cellMathObjects = mathObjects.slice(mathObjectIndex, mathObjectIndex + spanCount);
1406
1479
  mathObjectIndex += spanCount;
1407
- return createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics);
1480
+ const cellFormats = json.cell_formats?.[rowIndex]?.[columnIndex] ?? [];
1481
+ return createInlineField2(value, cellMathObjects, options, `${path}.rows[${String(rowIndex)}][${String(columnIndex)}]`, diagnostics, cellFormats);
1408
1482
  });
1409
1483
  });
1410
1484
  if (mathObjects.length > 0 && mathObjects.length !== mathObjectIndex) {
@@ -4444,6 +4518,79 @@ function normalizeFieldTokens(tokens) {
4444
4518
  }
4445
4519
  return tokens;
4446
4520
  }
4521
+ function textStylesEqual2(a, b) {
4522
+ return Boolean(a?.bold) === Boolean(b?.bold) && Boolean(a?.italic) === Boolean(b?.italic) && Boolean(a?.underline) === Boolean(b?.underline);
4523
+ }
4524
+ function compactAdjacentTextTokens(tokens) {
4525
+ const compacted = [];
4526
+ for (const token of tokens) {
4527
+ const previous = compacted[compacted.length - 1];
4528
+ if (previous?.kind === "text" && token.kind === "text" && textStylesEqual2(previous.style, token.style)) {
4529
+ previous.text += token.text;
4530
+ } else {
4531
+ compacted.push(token);
4532
+ }
4533
+ }
4534
+ return normalizeFieldTokens(compacted);
4535
+ }
4536
+ function withoutEmptyStyle(style) {
4537
+ const next = {};
4538
+ if (style.bold) {
4539
+ next.bold = true;
4540
+ }
4541
+ if (style.italic) {
4542
+ next.italic = true;
4543
+ }
4544
+ if (style.underline) {
4545
+ next.underline = true;
4546
+ }
4547
+ return next.bold || next.italic || next.underline ? next : void 0;
4548
+ }
4549
+ function textTokenPart(text, style, id = document2Id("text")) {
4550
+ return { id, kind: "text", text, ...style ? { style } : {} };
4551
+ }
4552
+ function toggleTextTokenStyle(document2, fieldId, tokenId, selectionStart, selectionEnd, styleName) {
4553
+ if (selectionEnd <= selectionStart) {
4554
+ return document2;
4555
+ }
4556
+ const next = cloneDocument(document2);
4557
+ visitFields(next.blocks, (field) => {
4558
+ if (field.id !== fieldId) {
4559
+ return false;
4560
+ }
4561
+ const tokenIndex = field.tokens.findIndex((entry) => entry.id === tokenId && entry.kind === "text");
4562
+ if (tokenIndex < 0) {
4563
+ return true;
4564
+ }
4565
+ const token = field.tokens[tokenIndex];
4566
+ const start = Math.max(0, Math.min(token.text.length, selectionStart));
4567
+ const end = Math.max(0, Math.min(token.text.length, selectionEnd));
4568
+ if (end <= start) {
4569
+ return true;
4570
+ }
4571
+ const selectedStyle = token.style ?? {};
4572
+ const enabled = selectedStyle[styleName] === true;
4573
+ const nextStyle = withoutEmptyStyle({ ...selectedStyle, [styleName]: enabled ? void 0 : true });
4574
+ const parts = [];
4575
+ const before = token.text.slice(0, start);
4576
+ const selected = token.text.slice(start, end);
4577
+ const after = token.text.slice(end);
4578
+ if (before.length > 0) {
4579
+ parts.push(textTokenPart(before, token.style, token.id));
4580
+ }
4581
+ parts.push(textTokenPart(selected, nextStyle, before.length > 0 ? document2Id("text") : token.id));
4582
+ if (after.length > 0) {
4583
+ parts.push(textTokenPart(after, token.style));
4584
+ }
4585
+ field.tokens = compactAdjacentTextTokens([
4586
+ ...field.tokens.slice(0, tokenIndex),
4587
+ ...parts,
4588
+ ...field.tokens.slice(tokenIndex + 1)
4589
+ ]);
4590
+ return true;
4591
+ });
4592
+ return next;
4593
+ }
4447
4594
  function stitchTextAroundRemovedToken(tokens, index) {
4448
4595
  const before = tokens[index - 1];
4449
4596
  const after = tokens[index + 1];
@@ -4471,8 +4618,8 @@ function removeMathTokenById(document2, tokenId) {
4471
4618
  function splitTextTokenAt(token, offset) {
4472
4619
  const safeOffset = Math.max(0, Math.min(offset, token.text.length));
4473
4620
  return [
4474
- { id: token.id, kind: "text", text: token.text.slice(0, safeOffset) },
4475
- { id: document2Id("text"), kind: "text", text: token.text.slice(safeOffset) }
4621
+ { id: token.id, kind: "text", text: token.text.slice(0, safeOffset), ...token.style ? { style: token.style } : {} },
4622
+ { id: document2Id("text"), kind: "text", text: token.text.slice(safeOffset), ...token.style ? { style: token.style } : {} }
4476
4623
  ];
4477
4624
  }
4478
4625
  function insertMathTokenAtCaret(document2, fieldId, textTokenId, caretOffset, session, opening = "$", closing = "$", side = "arabic") {
@@ -5214,9 +5361,22 @@ function mathBodyLatex(token) {
5214
5361
  const rendered = renderMathNodeLatex(token.math);
5215
5362
  return stripDisplayMathDelimiters(rendered);
5216
5363
  }
5364
+ function styledTextLatex(text, style) {
5365
+ let output = text;
5366
+ if (style?.bold) {
5367
+ output = `\\textbf{${output}}`;
5368
+ }
5369
+ if (style?.italic) {
5370
+ output = `\\textit{${output}}`;
5371
+ }
5372
+ if (style?.underline) {
5373
+ output = `\\underline{${output}}`;
5374
+ }
5375
+ return output;
5376
+ }
5217
5377
  function tokenLatex(token) {
5218
5378
  if (token.kind === "text") {
5219
- return token.text;
5379
+ return styledTextLatex(token.text, token.style);
5220
5380
  }
5221
5381
  if (token.kind === "cite") {
5222
5382
  return citeTokenLatex(token.keys);
@@ -5240,7 +5400,9 @@ function inlineFieldLatex(field) {
5240
5400
  return field.tokens.map((token) => tokenLatex(token)).join("");
5241
5401
  }
5242
5402
  function textBlockLatex(block) {
5243
- const body = `${block.command}{${inlineFieldLatex(block.field)}}`;
5403
+ const content = inlineFieldLatex(block.field);
5404
+ const body = block.command === "\\paragraph" ? `\\par
5405
+ ${content}` : `${block.command}{${content}}`;
5244
5406
  if (block.command === "\\paragraph" && block.centered) {
5245
5407
  return `\\begin{center}
5246
5408
  ${body}
@@ -5492,7 +5654,7 @@ function mathTex(token, equationSide) {
5492
5654
  function previewInlines(field, islands, output, equationSide, document2, previewOptions) {
5493
5655
  return field.tokens.map((token) => {
5494
5656
  if (token.kind === "text") {
5495
- return { kind: "text", text: token.text };
5657
+ return { kind: "text", text: token.text, ...token.style ? { style: token.style } : {} };
5496
5658
  }
5497
5659
  if (token.kind === "cite") {
5498
5660
  return {
@@ -5774,6 +5936,7 @@ function document2Preview(document2, output = "svg", equationSide = "arabic", pr
5774
5936
  setDocument2References,
5775
5937
  stripDisplayMathDelimiters,
5776
5938
  toggleBlockInSelection,
5939
+ toggleTextTokenStyle,
5777
5940
  updateCiteTokenKeys,
5778
5941
  updateDocument2ImageMeta,
5779
5942
  updateDocument2ImageValue,