@scrider/formatter 1.8.1 → 1.8.2

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/dist/index.d.cts CHANGED
@@ -481,9 +481,13 @@ declare class BlockHandlerRegistry {
481
481
  }
482
482
 
483
483
  /**
484
- * Cell alignment options
484
+ * Column alignment options (GFM column-level subset).
485
485
  */
486
486
  type CellAlign = 'left' | 'center' | 'right';
487
+ /** Per-cell horizontal alignment (includes justify; not used in colAligns). */
488
+ type CellHorizontalAlign = CellAlign | 'justify';
489
+ /** Per-cell vertical alignment (schema in 1.8.2; HTML round-trip in 1.8.4). */
490
+ type CellVerticalAlign = 'top' | 'middle' | 'bottom';
487
491
  /**
488
492
  * Data for a single cell in an Extended Table.
489
493
  *
@@ -497,6 +501,10 @@ interface CellData {
497
501
  colspan?: number;
498
502
  /** Number of rows this cell spans (default: 1) */
499
503
  rowspan?: number;
504
+ /** Per-cell horizontal override (default: inherit column via colAligns). */
505
+ align?: CellHorizontalAlign;
506
+ /** Per-cell vertical alignment (HTML ingest/emit in formatter 1.8.4). */
507
+ vAlign?: CellVerticalAlign;
500
508
  }
501
509
  /**
502
510
  * Extended Table block data.
@@ -2052,4 +2060,4 @@ declare function collectAdjacentTableLines<T extends {
2052
2060
  */
2053
2061
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
2054
2062
 
2055
- export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type EmbedIsolationOptions, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatRenderContext, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableCellCoords, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, collectAdjacentTableLines, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isAdjacentSimpleTableGridBoundary, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableCellCoordsFromAttributes, tableCellCoordsFromOp, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
2063
+ export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type CellHorizontalAlign, type CellVerticalAlign, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type EmbedIsolationOptions, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatRenderContext, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableCellCoords, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, collectAdjacentTableLines, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isAdjacentSimpleTableGridBoundary, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableCellCoordsFromAttributes, tableCellCoordsFromOp, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
package/dist/index.d.ts CHANGED
@@ -481,9 +481,13 @@ declare class BlockHandlerRegistry {
481
481
  }
482
482
 
483
483
  /**
484
- * Cell alignment options
484
+ * Column alignment options (GFM column-level subset).
485
485
  */
486
486
  type CellAlign = 'left' | 'center' | 'right';
487
+ /** Per-cell horizontal alignment (includes justify; not used in colAligns). */
488
+ type CellHorizontalAlign = CellAlign | 'justify';
489
+ /** Per-cell vertical alignment (schema in 1.8.2; HTML round-trip in 1.8.4). */
490
+ type CellVerticalAlign = 'top' | 'middle' | 'bottom';
487
491
  /**
488
492
  * Data for a single cell in an Extended Table.
489
493
  *
@@ -497,6 +501,10 @@ interface CellData {
497
501
  colspan?: number;
498
502
  /** Number of rows this cell spans (default: 1) */
499
503
  rowspan?: number;
504
+ /** Per-cell horizontal override (default: inherit column via colAligns). */
505
+ align?: CellHorizontalAlign;
506
+ /** Per-cell vertical alignment (HTML ingest/emit in formatter 1.8.4). */
507
+ vAlign?: CellVerticalAlign;
500
508
  }
501
509
  /**
502
510
  * Extended Table block data.
@@ -2052,4 +2060,4 @@ declare function collectAdjacentTableLines<T extends {
2052
2060
  */
2053
2061
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
2054
2062
 
2055
- export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type EmbedIsolationOptions, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatRenderContext, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableCellCoords, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, collectAdjacentTableLines, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isAdjacentSimpleTableGridBoundary, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableCellCoordsFromAttributes, tableCellCoordsFromOp, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
2063
+ export { ALERT_TYPES, type AlertBlockData, type AlertType, type AlignType, BOX_FLOAT_VALUES, BOX_OVERFLOW_VALUES, type BlockContext, type BlockHandler, BlockHandlerRegistry, type BlockRenderOptions, type BoxBlockData, type BoxFloat, type BoxOpAttributes, type BoxOverflow, BrowserDOMAdapter, type CellAlign, type CellData, type CellHorizontalAlign, type CellVerticalAlign, type ColumnsBlockData, type DOMAdapter, type DOMDocument, type DOMDocumentFragment, type DOMElement, type DOMNode, type DOMNodeList, type DeltaToHtmlOptions, type DeltaToMarkdownOptions, type DocumentPresentation, type EmbedIsolationOptions, type FootnotesBlockData, type Format, type FormatDefinition, type FormatMatchResult, type FormatRenderContext, type FormatScope, type HtmlToDeltaOptions, LINE_HEIGHT_BLOCK_TAGS, type ListType, type MarkdownToDeltaOptions, NODE_TYPE, NodeDOMAdapter, PARAGRAPH_SPACING_BLOCK_TAGS, Registry, type ResolvedDocumentPresentation, type ResolvedTablePresentation, SCRIDER_LINE_HEIGHT_KEY, SCRIDER_MARGIN_AFTER_KEY, SCRIDER_MARGIN_BEFORE_KEY, type SanitizeOptions, type TableBlockData, type TableCellAlign, type TableCellCoords, type TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, collectAdjacentTableLines, colorFormat, columnsBlockHandler, createDefaultBlockHandlers, createDefaultRegistry, defaultBlockFormats, defaultEmbedFormats, defaultFormats, defaultInlineFormats, deltaToHtml, deltaToMarkdown, dividerFormat, documentPresentationStyleParts, escapeHtml, extractBoxOpAttributes, extractTableRegion, fontFormat, footnoteRefFormat, footnotesBlockHandler, formulaFormat, getAdapter, getNamedColors, headerFormat, headerIdFormat, htmlToDelta, imageFormat, indentFormat, isAdapterAvailable, isAdjacentSimpleTableGridBoundary, isElement, isRemarkAvailable, isTableNewlineOp, isTextNode, isValidColor, isValidHexColor, isZebraBodyRow, italicFormat, kbdFormat, linkFormat, listFormat, markFormat, markdownToDelta, markdownToDeltaSync, nodeAdapter, normalizeDelta, parseScriderLineHeightMultiplier, parseScriderMarginAfterEm, parseScriderMarginBeforeEm, parseScriderMarginEm, preloadRemark, resolveDocumentPresentation, resolveTablePresentation, sanitizeDelta, sizeFormat, slugify, slugifyWithDedup, softBreakFormat, strikeFormat, subscriptFormat, superscriptFormat, tableBlockHandler, tableCellCoordsFromAttributes, tableCellCoordsFromOp, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
package/dist/index.js CHANGED
@@ -199,7 +199,7 @@ var BlockHandlerRegistry = class {
199
199
  };
200
200
 
201
201
  // src/schema/blocks/table.ts
202
- import { Delta as Delta2 } from "@scrider/delta";
202
+ import { Delta as Delta2, isInsert as isInsert2, isTextInsert } from "@scrider/delta";
203
203
 
204
204
  // src/conversion/sanitize.ts
205
205
  import { Delta, isInsert, isRetain, isEmbedInsert, deepClone } from "@scrider/delta";
@@ -362,6 +362,13 @@ function isTextNode(node) {
362
362
  }
363
363
 
364
364
  // src/schema/blocks/table.ts
365
+ var VALID_CELL_HORIZONTAL_ALIGNS = [
366
+ "left",
367
+ "center",
368
+ "right",
369
+ "justify"
370
+ ];
371
+ var VALID_CELL_VERTICAL_ALIGNS = ["top", "middle", "bottom"];
365
372
  var CELL_KEY_RE = /^(\d+):(\d+)$/;
366
373
  function parseCellKey(key) {
367
374
  const match = CELL_KEY_RE.exec(key);
@@ -382,7 +389,22 @@ function getGridDimensions(cells) {
382
389
  return [maxRow + 1, maxCol + 1];
383
390
  }
384
391
  function isValidCellData(cell) {
385
- return typeof cell === "object" && cell !== null && Array.isArray(cell.ops) && cell.ops.length > 0 && (cell.colspan === void 0 || Number.isInteger(cell.colspan) && cell.colspan >= 1) && (cell.rowspan === void 0 || Number.isInteger(cell.rowspan) && cell.rowspan >= 1);
392
+ if (typeof cell !== "object" || cell === null || !Array.isArray(cell.ops) || cell.ops.length === 0) {
393
+ return false;
394
+ }
395
+ if (cell.colspan !== void 0 && (!Number.isInteger(cell.colspan) || cell.colspan < 1)) {
396
+ return false;
397
+ }
398
+ if (cell.rowspan !== void 0 && (!Number.isInteger(cell.rowspan) || cell.rowspan < 1)) {
399
+ return false;
400
+ }
401
+ if (cell.align !== void 0 && !VALID_CELL_HORIZONTAL_ALIGNS.includes(cell.align)) {
402
+ return false;
403
+ }
404
+ if (cell.vAlign !== void 0 && !VALID_CELL_VERTICAL_ALIGNS.includes(cell.vAlign)) {
405
+ return false;
406
+ }
407
+ return true;
386
408
  }
387
409
  function validateMergedCells(cells, rows, cols) {
388
410
  const covered = /* @__PURE__ */ new Set();
@@ -412,6 +434,38 @@ function validateMergedCells(cells, rows, cols) {
412
434
  }
413
435
  return true;
414
436
  }
437
+ function parseHorizontalAlign(value) {
438
+ const normalized = value?.trim().toLowerCase();
439
+ if (normalized === "left" || normalized === "center" || normalized === "right") {
440
+ return normalized;
441
+ }
442
+ if (normalized === "justify") return "justify";
443
+ return null;
444
+ }
445
+ function resolveCellHorizontalAlign(cell, col, colAligns) {
446
+ if (cell.align !== void 0) return cell.align;
447
+ const colAlign = colAligns?.[col];
448
+ if (colAlign) return colAlign;
449
+ return "left";
450
+ }
451
+ function promoteAlignFromCellOps(cell) {
452
+ if (cell.align !== void 0) return cell;
453
+ for (let i = cell.ops.length - 1; i >= 0; i--) {
454
+ const op = cell.ops[i];
455
+ if (!op || !isInsert2(op) || !isTextInsert(op) || !op.insert.includes("\n")) continue;
456
+ const align = op.attributes?.align;
457
+ const parsed = typeof align === "string" ? parseHorizontalAlign(align) : null;
458
+ if (!parsed) continue;
459
+ const ops = cell.ops.map((item, idx) => {
460
+ if (idx !== i || !isInsert2(item) || item.attributes == null) return item;
461
+ const rest = { ...item.attributes };
462
+ delete rest.align;
463
+ return Object.keys(rest).length > 0 ? { insert: item.insert, attributes: rest } : { insert: item.insert };
464
+ });
465
+ return { ...cell, ops, align: parsed };
466
+ }
467
+ return cell;
468
+ }
415
469
  function renderExtendedRow(data, row, cols, defaultCellTag, context, pretty) {
416
470
  const nl = pretty ? "\n" : "";
417
471
  const ind = (level) => pretty ? " ".repeat(level) : "";
@@ -429,11 +483,16 @@ function renderExtendedRow(data, row, cols, defaultCellTag, context, pretty) {
429
483
  if (cell.rowspan && cell.rowspan > 1) {
430
484
  attrs.push(`rowspan="${cell.rowspan}"`);
431
485
  }
432
- if (data.colAligns) {
433
- const align = data.colAligns[c];
434
- if (align && align !== "left") {
435
- attrs.push(`style="text-align: ${align}"`);
436
- }
486
+ const colDefault = data.colAligns?.[c] ?? "left";
487
+ const effectiveAlign = resolveCellHorizontalAlign(cell, c, data.colAligns);
488
+ let alignStyle = null;
489
+ if (effectiveAlign !== "left") {
490
+ alignStyle = `text-align: ${effectiveAlign}`;
491
+ } else if (cell.align === "left" && colDefault !== "left") {
492
+ alignStyle = "text-align: left";
493
+ }
494
+ if (alignStyle) {
495
+ attrs.push(`style="${alignStyle}"`);
437
496
  }
438
497
  const attrStr = attrs.length > 0 ? " " + attrs.join(" ") : "";
439
498
  let content = "";
@@ -449,6 +508,9 @@ function isGfmCompatible(data) {
449
508
  if (data.colWidths && data.colWidths.some((w) => w > 0)) {
450
509
  return false;
451
510
  }
511
+ for (const cell of Object.values(data.cells)) {
512
+ if (cell !== null && cell.align !== void 0) return false;
513
+ }
452
514
  for (const cell of Object.values(data.cells)) {
453
515
  if (cell === null) return false;
454
516
  if (cell.colspan && cell.colspan > 1) return false;
@@ -559,14 +621,28 @@ function extractColWidths(table) {
559
621
  return void 0;
560
622
  }
561
623
  function extractCellAlign(cell) {
562
- const textAlign = cell.style?.textAlign || cell.style?.getPropertyValue?.("text-align");
563
- if (textAlign === "left" || textAlign === "center" || textAlign === "right") {
564
- return textAlign;
624
+ const direct = extractInlineHorizontalAlign(cell);
625
+ if (direct) return direct;
626
+ const children = cell.childNodes;
627
+ for (let i = 0; i < children.length; i++) {
628
+ const child = children[i];
629
+ if (!child || !isElement(child)) continue;
630
+ const tag = child.tagName.toLowerCase();
631
+ if (tag === "p" || tag === "div") {
632
+ const align = extractInlineHorizontalAlign(child);
633
+ if (align) return align;
634
+ }
565
635
  }
566
- const style = cell.getAttribute("style") || "";
567
- const match = style.match(/text-align:\s*(left|center|right)/);
636
+ return null;
637
+ }
638
+ function extractInlineHorizontalAlign(element) {
639
+ const textAlign = element.style?.textAlign || element.style?.getPropertyValue?.("text-align");
640
+ const fromStyle = parseHorizontalAlign(textAlign);
641
+ if (fromStyle) return fromStyle;
642
+ const style = element.getAttribute("style") || "";
643
+ const match = style.match(/text-align:\s*(left|center|right|justify)/i);
568
644
  if (match?.[1]) {
569
- return match[1];
645
+ return parseHorizontalAlign(match[1]);
570
646
  }
571
647
  return null;
572
648
  }
@@ -575,6 +651,7 @@ function parseTableElement(table, context) {
575
651
  if (rows.length === 0) return null;
576
652
  const cells = {};
577
653
  const colAligns = [];
654
+ const rawAligns = {};
578
655
  let maxCol = 0;
579
656
  let firstRowProcessed = false;
580
657
  const occupied = /* @__PURE__ */ new Set();
@@ -603,10 +680,20 @@ function parseTableElement(table, context) {
603
680
  } else {
604
681
  ops = [{ insert: "\n" }];
605
682
  }
606
- const cellData = { ops };
683
+ let cellData = { ops };
607
684
  if (colspan > 1) cellData.colspan = colspan;
608
685
  if (rowspan > 1) cellData.rowspan = rowspan;
609
- cells[`${rowIdx}:${colIdx}`] = cellData;
686
+ cellData = promoteAlignFromCellOps(cellData);
687
+ const htmlAlign = extractCellAlign(cell);
688
+ const effectiveAlign = htmlAlign ?? cellData.align ?? "left";
689
+ if (cellData.align !== void 0) {
690
+ const withoutAlign = { ...cellData };
691
+ delete withoutAlign.align;
692
+ cellData = withoutAlign;
693
+ }
694
+ const cellKey = `${rowIdx}:${colIdx}`;
695
+ cells[cellKey] = cellData;
696
+ rawAligns[cellKey] = effectiveAlign;
610
697
  for (let dr = 0; dr < rowspan; dr++) {
611
698
  for (let dc = 0; dc < colspan; dc++) {
612
699
  if (dr === 0 && dc === 0) continue;
@@ -620,8 +707,9 @@ function parseTableElement(table, context) {
620
707
  }
621
708
  if (!firstRowProcessed) {
622
709
  const align = extractCellAlign(cell);
710
+ const colAlign = align === "center" || align === "right" ? align : null;
623
711
  for (let dc = 0; dc < colspan; dc++) {
624
- colAligns.push(align);
712
+ colAligns.push(colAlign);
625
713
  }
626
714
  }
627
715
  const cellEndCol = colIdx + colspan - 1;
@@ -662,6 +750,18 @@ function parseTableElement(table, context) {
662
750
  if (colAligns.length > totalCols) colAligns.length = totalCols;
663
751
  result.colAligns = colAligns;
664
752
  }
753
+ for (let r = 0; r < totalRows; r++) {
754
+ for (let c = 0; c < totalCols; c++) {
755
+ const key = `${r}:${c}`;
756
+ const cell = result.cells[key];
757
+ if (cell == null) continue;
758
+ const colDefault = result.colAligns?.[c] ?? "left";
759
+ const effective = rawAligns[key] ?? "left";
760
+ if (effective !== colDefault) {
761
+ result.cells[key] = { ...cell, align: effective };
762
+ }
763
+ }
764
+ }
665
765
  return result;
666
766
  }
667
767
  var tableBlockHandler = {
@@ -773,8 +873,11 @@ var tableBlockHandler = {
773
873
  for (const [key, cell] of Object.entries(data.cells)) {
774
874
  if (cell !== null) {
775
875
  const normalized = normalizeDelta(new Delta2(cell.ops), registry);
776
- if (normalized.ops !== cell.ops) {
777
- newCells[key] = { ...cell, ops: normalized.ops };
876
+ const promoted = promoteAlignFromCellOps(
877
+ normalized.ops !== cell.ops ? { ...cell, ops: normalized.ops } : cell
878
+ );
879
+ if (promoted.ops !== cell.ops || promoted.align !== cell.align) {
880
+ newCells[key] = promoted;
778
881
  changed = true;
779
882
  } else {
780
883
  newCells[key] = cell;
@@ -810,7 +913,7 @@ var tableBlockHandler = {
810
913
  };
811
914
 
812
915
  // src/schema/blocks/footnotes.ts
813
- import { isTextInsert, Delta as Delta3 } from "@scrider/delta";
916
+ import { isTextInsert as isTextInsert2, Delta as Delta3 } from "@scrider/delta";
814
917
  function isValidNoteData(note) {
815
918
  return typeof note === "object" && note !== null && Array.isArray(note.ops) && note.ops.length > 0;
816
919
  }
@@ -895,11 +998,11 @@ var footnotesBlockHandler = {
895
998
  if (context.parseElement) {
896
999
  ops = context.parseElement(li);
897
1000
  ops = ops.map((op) => {
898
- if (isTextInsert(op) && op.insert.includes("\u21A9")) {
1001
+ if (isTextInsert2(op) && op.insert.includes("\u21A9")) {
899
1002
  return { ...op, insert: op.insert.replace(/\u21a9/g, "") };
900
1003
  }
901
1004
  return op;
902
- }).filter((op) => !isTextInsert(op) || op.insert !== "");
1005
+ }).filter((op) => !isTextInsert2(op) || op.insert !== "");
903
1006
  if (ops.length === 0) {
904
1007
  ops = [{ insert: "\n" }];
905
1008
  }
@@ -2652,7 +2755,7 @@ function isAdapterAvailable() {
2652
2755
  }
2653
2756
 
2654
2757
  // src/conversion/html/delta-to-html.ts
2655
- import { Delta as Delta7, isInsert as isInsert3, isEmbedInsert as isEmbedInsert2 } from "@scrider/delta";
2758
+ import { Delta as Delta7, isInsert as isInsert4, isEmbedInsert as isEmbedInsert2 } from "@scrider/delta";
2656
2759
 
2657
2760
  // src/conversion/utils/slugify.ts
2658
2761
  function slugify(text) {
@@ -2876,9 +2979,9 @@ function buildTableCellStyleAttr(params) {
2876
2979
  }
2877
2980
 
2878
2981
  // src/conversion/markdown/table-region.ts
2879
- import { isInsert as isInsert2, isTextInsert as isTextInsert2 } from "@scrider/delta";
2982
+ import { isInsert as isInsert3, isTextInsert as isTextInsert3 } from "@scrider/delta";
2880
2983
  function isTableNewlineOp(op) {
2881
- if (!op || !isInsert2(op) || !isTextInsert2(op)) return false;
2984
+ if (!op || !isInsert3(op) || !isTextInsert3(op)) return false;
2882
2985
  if (!op.insert.includes("\n")) return false;
2883
2986
  return !!op.attributes && "table-row" in op.attributes;
2884
2987
  }
@@ -2889,7 +2992,7 @@ function tableCellCoordsFromAttributes(attrs) {
2889
2992
  return { row: attrs["table-row"], col: attrs["table-col"] };
2890
2993
  }
2891
2994
  function tableCellCoordsFromOp(op) {
2892
- if (!isTableNewlineOp(op) || !isTextInsert2(op)) return null;
2995
+ if (!isTableNewlineOp(op) || !isTextInsert3(op)) return null;
2893
2996
  return tableCellCoordsFromAttributes(op.attributes);
2894
2997
  }
2895
2998
  function isAdjacentSimpleTableGridBoundary(prev, next) {
@@ -2916,8 +3019,8 @@ function extractTableRegion(ops, hintOpIdx) {
2916
3019
  let probeIdx = -1;
2917
3020
  for (let i = hintOpIdx; i < ops.length; i++) {
2918
3021
  const op = ops[i];
2919
- if (!op || !isInsert2(op)) continue;
2920
- if (isTextInsert2(op) && op.insert.includes("\n")) {
3022
+ if (!op || !isInsert3(op)) continue;
3023
+ if (isTextInsert3(op) && op.insert.includes("\n")) {
2921
3024
  probeIdx = i;
2922
3025
  break;
2923
3026
  }
@@ -2930,8 +3033,8 @@ function extractTableRegion(ops, hintOpIdx) {
2930
3033
  let prevCoords = probeCoords;
2931
3034
  for (let i = probeIdx + 1; i < ops.length; i++) {
2932
3035
  const op = ops[i];
2933
- if (!op || !isInsert2(op)) break;
2934
- if (!isTextInsert2(op) || !op.insert.includes("\n")) continue;
3036
+ if (!op || !isInsert3(op)) break;
3037
+ if (!isTextInsert3(op) || !op.insert.includes("\n")) continue;
2935
3038
  if (isTableNewlineOp(op)) {
2936
3039
  const coords = tableCellCoordsFromOp(op);
2937
3040
  if (isAdjacentSimpleTableGridBoundary(prevCoords, coords)) break;
@@ -2945,11 +3048,11 @@ function extractTableRegion(ops, hintOpIdx) {
2945
3048
  let nextCoords = probeCoords;
2946
3049
  for (let i = probeIdx - 1; i >= 0; i--) {
2947
3050
  const op = ops[i];
2948
- if (!op || !isInsert2(op)) {
3051
+ if (!op || !isInsert3(op)) {
2949
3052
  startOpIdx = i + 1;
2950
3053
  break;
2951
3054
  }
2952
- if (!isTextInsert2(op) || !op.insert.includes("\n")) continue;
3055
+ if (!isTextInsert3(op) || !op.insert.includes("\n")) continue;
2953
3056
  if (isTableNewlineOp(op)) {
2954
3057
  const coords = tableCellCoordsFromOp(op);
2955
3058
  if (isAdjacentSimpleTableGridBoundary(coords, nextCoords)) {
@@ -3095,7 +3198,7 @@ function splitIntoLines(delta) {
3095
3198
  const lines = [];
3096
3199
  let currentOps = [];
3097
3200
  for (const op of delta.ops) {
3098
- if (!isInsert3(op)) continue;
3201
+ if (!isInsert4(op)) continue;
3099
3202
  if (isEmbedInsert2(op)) {
3100
3203
  currentOps.push(op);
3101
3204
  continue;
@@ -3414,7 +3517,7 @@ function getBlockStyleAttribute(tag, attributes, resolvedDocumentPresentation) {
3414
3517
  function extractPlainText(ops) {
3415
3518
  let text = "";
3416
3519
  for (const op of ops) {
3417
- if (isInsert3(op) && typeof op.insert === "string") {
3520
+ if (isInsert4(op) && typeof op.insert === "string") {
3418
3521
  text += op.insert;
3419
3522
  }
3420
3523
  }
@@ -3423,7 +3526,7 @@ function extractPlainText(ops) {
3423
3526
  function renderLineContent(ops, embedRenderers, blockHandlers, options) {
3424
3527
  let html = "";
3425
3528
  for (const op of ops) {
3426
- if (!isInsert3(op)) continue;
3529
+ if (!isInsert4(op)) continue;
3427
3530
  if (isEmbedInsert2(op)) {
3428
3531
  html += renderEmbed(
3429
3532
  op.insert,
@@ -4221,7 +4324,7 @@ var DEFAULT_TAG_HANDLERS = {
4221
4324
  };
4222
4325
 
4223
4326
  // src/conversion/markdown/delta-to-markdown.ts
4224
- import { Delta as Delta9, isInsert as isInsert4, isTextInsert as isTextInsert3, isEmbedInsert as isEmbedInsert3 } from "@scrider/delta";
4327
+ import { Delta as Delta9, isInsert as isInsert5, isTextInsert as isTextInsert4, isEmbedInsert as isEmbedInsert3 } from "@scrider/delta";
4225
4328
 
4226
4329
  // src/conversion/markdown/config.ts
4227
4330
  var MARKDOWN_ESCAPE_CHARS = /[\\`*_[\]<>#]/g;
@@ -4414,9 +4517,9 @@ function splitIntoLines2(ops) {
4414
4517
  const lines = [];
4415
4518
  let currentOps = [];
4416
4519
  for (const op of ops) {
4417
- if (!isInsert4(op)) continue;
4520
+ if (!isInsert5(op)) continue;
4418
4521
  const opAttrs = op.attributes ?? {};
4419
- if (isTextInsert3(op)) {
4522
+ if (isTextInsert4(op)) {
4420
4523
  const text = op.insert;
4421
4524
  const parts = text.split("\n");
4422
4525
  for (let i = 0; i < parts.length; i++) {
@@ -4616,7 +4719,7 @@ function renderLineContent2(ops, embedRenderers, inCodeBlock, useLatexDelimiters
4616
4719
  let result = "";
4617
4720
  for (const op of ops) {
4618
4721
  const attrs = op.attributes;
4619
- if (isTextInsert3(op)) {
4722
+ if (isTextInsert4(op)) {
4620
4723
  const text = op.insert;
4621
4724
  if (inCodeBlock) {
4622
4725
  result += text;
@@ -4845,12 +4948,12 @@ function renderBlockFormat(content, attributes, orderedIndex, _strict) {
4845
4948
  }
4846
4949
 
4847
4950
  // src/conversion/markdown/markdown-to-delta.ts
4848
- import { Delta as Delta10, isInsert as isInsert6 } from "@scrider/delta";
4951
+ import { Delta as Delta10, isInsert as isInsert7 } from "@scrider/delta";
4849
4952
 
4850
4953
  // src/conversion/markdown/table-header-normalize.ts
4851
- import { isInsert as isInsert5 } from "@scrider/delta";
4954
+ import { isInsert as isInsert6 } from "@scrider/delta";
4852
4955
  function isTableCellTerminator(op) {
4853
- return isInsert5(op) && typeof op.insert === "string" && op.insert === "\n" && op.attributes !== void 0 && typeof op.attributes["table-row"] === "number";
4956
+ return isInsert6(op) && typeof op.insert === "string" && op.insert === "\n" && op.attributes !== void 0 && typeof op.attributes["table-row"] === "number";
4854
4957
  }
4855
4958
  function normalizeSyntheticEmptyHeaderRow(ops) {
4856
4959
  const ends = [];
@@ -4859,7 +4962,7 @@ function normalizeSyntheticEmptyHeaderRow(ops) {
4859
4962
  let currentTextOps = [];
4860
4963
  for (let i = 0; i < ops.length; i++) {
4861
4964
  const op = ops[i];
4862
- if (!isInsert5(op)) continue;
4965
+ if (!isInsert6(op)) continue;
4863
4966
  if (typeof op.insert === "string" && op.insert !== "\n") {
4864
4967
  buf += op.insert;
4865
4968
  currentTextOps.push(i);
@@ -4910,7 +5013,7 @@ function normalizeHeaderDashPlaceholders(ops) {
4910
5013
  let currentTextOps = [];
4911
5014
  for (let i = 0; i < ops.length; i++) {
4912
5015
  const op = ops[i];
4913
- if (!isInsert5(op)) continue;
5016
+ if (!isInsert6(op)) continue;
4914
5017
  if (typeof op.insert === "string" && op.insert !== "\n") {
4915
5018
  buf += op.insert;
4916
5019
  currentTextOps.push(i);
@@ -4939,7 +5042,7 @@ function normalizeHeaderDashPlaceholders(ops) {
4939
5042
  out.push(op);
4940
5043
  continue;
4941
5044
  }
4942
- if (!isInsert5(op)) {
5045
+ if (!isInsert6(op)) {
4943
5046
  out.push(op);
4944
5047
  continue;
4945
5048
  }
@@ -4960,7 +5063,7 @@ function normalizeImportedTableOps(ops) {
4960
5063
  const ends = [];
4961
5064
  let buf = "";
4962
5065
  for (const op of ops) {
4963
- if (!isInsert5(op)) continue;
5066
+ if (!isInsert6(op)) continue;
4964
5067
  if (typeof op.insert === "string" && op.insert !== "\n") {
4965
5068
  buf += op.insert;
4966
5069
  continue;
@@ -5496,7 +5599,7 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
5496
5599
  }
5497
5600
  const tableOps = delta.ops.splice(tableStart);
5498
5601
  for (const op of normalizeImportedTableOps(tableOps)) {
5499
- if (!isInsert6(op)) continue;
5602
+ if (!isInsert7(op)) continue;
5500
5603
  if (op.attributes && Object.keys(op.attributes).length > 0) {
5501
5604
  delta.insert(op.insert, op.attributes);
5502
5605
  } else {