@scrider/formatter 1.7.2 → 1.8.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/dist/index.d.cts CHANGED
@@ -1992,11 +1992,34 @@ interface TableRegion {
1992
1992
  /** Slice of the original ops array covering the region. */
1993
1993
  ops: InsertOp[];
1994
1994
  }
1995
+ /** Coordinates carried on a simple-table cell terminator `\n`. */
1996
+ interface TableCellCoords {
1997
+ row: number;
1998
+ col: number;
1999
+ }
1995
2000
  /**
1996
2001
  * Predicate: this op is a `\n`-op that terminates a simple-table cell
1997
2002
  * (i.e. it carries a `table-row` attribute).
1998
2003
  */
1999
2004
  declare function isTableNewlineOp(op: Op | undefined): boolean;
2005
+ declare function tableCellCoordsFromAttributes(attrs: AttributeMap | undefined): TableCellCoords | null;
2006
+ declare function tableCellCoordsFromOp(op: Op): TableCellCoords | null;
2007
+ /**
2008
+ * True when `next` begins a new simple-table grid immediately after `prev`
2009
+ * with no plain paragraph `\n` between them.
2010
+ *
2011
+ * Patterns:
2012
+ * • row decreases (e.g. 1 → 0) — new grid after a multi-row table
2013
+ * • both on row 0 but col resets to 0 — two single-row tables stacked
2014
+ */
2015
+ declare function isAdjacentSimpleTableGridBoundary(prev: TableCellCoords, next: TableCellCoords): boolean;
2016
+ /**
2017
+ * Collect consecutive table lines for one simple-table grid.
2018
+ * Stops at the first non-table line or at an adjacent-grid boundary.
2019
+ */
2020
+ declare function collectAdjacentTableLines<T extends {
2021
+ attributes?: AttributeMap | undefined;
2022
+ }>(lines: readonly T[], startIndex: number): T[];
2000
2023
  /**
2001
2024
  * Find the boundaries of the simple-table region containing the given hint
2002
2025
  * op index. The hint may be:
@@ -2007,8 +2030,9 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
2007
2030
  * The function walks **forward** from the hint to find the nearest `\n`-op:
2008
2031
  * if it does not carry a `table-row` attribute, the hint is not inside a
2009
2032
  * table and `null` is returned. Otherwise the algorithm extends the region
2010
- * forward through contiguous table newlines and backward to the op just
2011
- * after the previous non-table `\n`-op (or the start of the array).
2033
+ * forward through contiguous table newlines (stopping at adjacent-grid
2034
+ * boundaries) and backward to the op just after the previous non-table
2035
+ * `\n`-op or adjacent-grid boundary (or the start of the array).
2012
2036
  *
2013
2037
  * @param ops - The full ops array (e.g. `delta.ops`).
2014
2038
  * @param hintOpIdx - Any op index known or guessed to be within a table.
@@ -2028,4 +2052,4 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
2028
2052
  */
2029
2053
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
2030
2054
 
2031
- 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 TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, 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, 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, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
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 };
package/dist/index.d.ts CHANGED
@@ -1992,11 +1992,34 @@ interface TableRegion {
1992
1992
  /** Slice of the original ops array covering the region. */
1993
1993
  ops: InsertOp[];
1994
1994
  }
1995
+ /** Coordinates carried on a simple-table cell terminator `\n`. */
1996
+ interface TableCellCoords {
1997
+ row: number;
1998
+ col: number;
1999
+ }
1995
2000
  /**
1996
2001
  * Predicate: this op is a `\n`-op that terminates a simple-table cell
1997
2002
  * (i.e. it carries a `table-row` attribute).
1998
2003
  */
1999
2004
  declare function isTableNewlineOp(op: Op | undefined): boolean;
2005
+ declare function tableCellCoordsFromAttributes(attrs: AttributeMap | undefined): TableCellCoords | null;
2006
+ declare function tableCellCoordsFromOp(op: Op): TableCellCoords | null;
2007
+ /**
2008
+ * True when `next` begins a new simple-table grid immediately after `prev`
2009
+ * with no plain paragraph `\n` between them.
2010
+ *
2011
+ * Patterns:
2012
+ * • row decreases (e.g. 1 → 0) — new grid after a multi-row table
2013
+ * • both on row 0 but col resets to 0 — two single-row tables stacked
2014
+ */
2015
+ declare function isAdjacentSimpleTableGridBoundary(prev: TableCellCoords, next: TableCellCoords): boolean;
2016
+ /**
2017
+ * Collect consecutive table lines for one simple-table grid.
2018
+ * Stops at the first non-table line or at an adjacent-grid boundary.
2019
+ */
2020
+ declare function collectAdjacentTableLines<T extends {
2021
+ attributes?: AttributeMap | undefined;
2022
+ }>(lines: readonly T[], startIndex: number): T[];
2000
2023
  /**
2001
2024
  * Find the boundaries of the simple-table region containing the given hint
2002
2025
  * op index. The hint may be:
@@ -2007,8 +2030,9 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
2007
2030
  * The function walks **forward** from the hint to find the nearest `\n`-op:
2008
2031
  * if it does not carry a `table-row` attribute, the hint is not inside a
2009
2032
  * table and `null` is returned. Otherwise the algorithm extends the region
2010
- * forward through contiguous table newlines and backward to the op just
2011
- * after the previous non-table `\n`-op (or the start of the array).
2033
+ * forward through contiguous table newlines (stopping at adjacent-grid
2034
+ * boundaries) and backward to the op just after the previous non-table
2035
+ * `\n`-op or adjacent-grid boundary (or the start of the array).
2012
2036
  *
2013
2037
  * @param ops - The full ops array (e.g. `delta.ops`).
2014
2038
  * @param hintOpIdx - Any op index known or guessed to be within a table.
@@ -2028,4 +2052,4 @@ declare function isTableNewlineOp(op: Op | undefined): boolean;
2028
2052
  */
2029
2053
  declare function extractTableRegion(ops: readonly Op[], hintOpIdx: number): TableRegion | null;
2030
2054
 
2031
- 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 TableColAlignType, type TablePresentation, type TableRegion, alertBlockHandler, alignFormat, backgroundFormat, blockFormat, blockLineHeightStyleParts, blockMarginAfterStyleParts, blockMarginBeforeStyleParts, blockParagraphMarginStyleParts, blockPresentationStyleParts, blockquoteFormat, boldFormat, boxBlockHandler, browserAdapter, cloneDelta, codeBlockFormat, codeFormat, codeWidgetFormat, 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, 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, tableColAlignFormat, tableColFormat, tableHeaderFormat, tableRowFormat, toCodeWidgetEmbedUrl, toHexColor, underlineFormat, unescapeHtml, validateDelta, videoFormat };
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 };
package/dist/index.js CHANGED
@@ -333,6 +333,20 @@ function cloneDelta(delta) {
333
333
  return new Delta(deepClone(delta.ops));
334
334
  }
335
335
 
336
+ // src/conversion/markdown/table-header-markdown.ts
337
+ function isHeaderDashPlaceholder(text) {
338
+ const t = text.trim();
339
+ return t === "-" && t.length === 1;
340
+ }
341
+ function normalizeHeaderCellForParse(text, isHeaderRow) {
342
+ if (isHeaderRow && isHeaderDashPlaceholder(text)) return "";
343
+ return text;
344
+ }
345
+ function serializeHeaderCell(text) {
346
+ if (text.trim() === "") return "-";
347
+ return text;
348
+ }
349
+
336
350
  // src/conversion/adapters/types.ts
337
351
  var NODE_TYPE = {
338
352
  ELEMENT_NODE: 1,
@@ -454,19 +468,21 @@ function renderGfmTable(data, context) {
454
468
  if (headerRows === 0) {
455
469
  const emptyParts = [];
456
470
  for (let c = 0; c < cols; c++) {
457
- emptyParts.push(" ");
471
+ emptyParts.push("");
458
472
  }
459
473
  lines.push("| " + emptyParts.join(" | ") + " |");
460
474
  lines.push(renderGfmSeparator(cols, data.colAligns));
461
475
  }
462
476
  for (let r = 0; r < rows; r++) {
463
477
  const parts = [];
478
+ const isHeaderRow = headerRows > 0 && r < headerRows;
464
479
  for (let c = 0; c < cols; c++) {
465
480
  const cell = data.cells[`${r}:${c}`];
466
481
  let text = "";
467
482
  if (cell && context.renderDelta) {
468
483
  text = stripCellContent(context.renderDelta(cell.ops));
469
484
  }
485
+ if (isHeaderRow) text = serializeHeaderCell(text);
470
486
  parts.push(text.replace(/\|/g, "\\|"));
471
487
  }
472
488
  lines.push("| " + parts.join(" | ") + " |");
@@ -2636,7 +2652,7 @@ function isAdapterAvailable() {
2636
2652
  }
2637
2653
 
2638
2654
  // src/conversion/html/delta-to-html.ts
2639
- import { Delta as Delta7, isInsert as isInsert2, isEmbedInsert as isEmbedInsert2 } from "@scrider/delta";
2655
+ import { Delta as Delta7, isInsert as isInsert3, isEmbedInsert as isEmbedInsert2 } from "@scrider/delta";
2640
2656
 
2641
2657
  // src/conversion/utils/slugify.ts
2642
2658
  function slugify(text) {
@@ -2859,6 +2875,97 @@ function buildTableCellStyleAttr(params) {
2859
2875
  return ` style="${parts.join("; ")}"`;
2860
2876
  }
2861
2877
 
2878
+ // src/conversion/markdown/table-region.ts
2879
+ import { isInsert as isInsert2, isTextInsert as isTextInsert2 } from "@scrider/delta";
2880
+ function isTableNewlineOp(op) {
2881
+ if (!op || !isInsert2(op) || !isTextInsert2(op)) return false;
2882
+ if (!op.insert.includes("\n")) return false;
2883
+ return !!op.attributes && "table-row" in op.attributes;
2884
+ }
2885
+ function tableCellCoordsFromAttributes(attrs) {
2886
+ if (!attrs || typeof attrs["table-row"] !== "number" || typeof attrs["table-col"] !== "number") {
2887
+ return null;
2888
+ }
2889
+ return { row: attrs["table-row"], col: attrs["table-col"] };
2890
+ }
2891
+ function tableCellCoordsFromOp(op) {
2892
+ if (!isTableNewlineOp(op) || !isTextInsert2(op)) return null;
2893
+ return tableCellCoordsFromAttributes(op.attributes);
2894
+ }
2895
+ function isAdjacentSimpleTableGridBoundary(prev, next) {
2896
+ if (next.row < prev.row) return true;
2897
+ if (next.row === 0 && prev.row === 0 && next.col === 0 && prev.col > 0) return true;
2898
+ return false;
2899
+ }
2900
+ function collectAdjacentTableLines(lines, startIndex) {
2901
+ const result = [];
2902
+ let prevCoords = null;
2903
+ for (let i = startIndex; i < lines.length; i++) {
2904
+ const line = lines[i];
2905
+ if (line === void 0) break;
2906
+ const coords = tableCellCoordsFromAttributes(line.attributes);
2907
+ if (!coords) break;
2908
+ if (prevCoords && isAdjacentSimpleTableGridBoundary(prevCoords, coords)) break;
2909
+ result.push(line);
2910
+ prevCoords = coords;
2911
+ }
2912
+ return result;
2913
+ }
2914
+ function extractTableRegion(ops, hintOpIdx) {
2915
+ if (hintOpIdx < 0 || hintOpIdx >= ops.length) return null;
2916
+ let probeIdx = -1;
2917
+ for (let i = hintOpIdx; i < ops.length; i++) {
2918
+ const op = ops[i];
2919
+ if (!op || !isInsert2(op)) continue;
2920
+ if (isTextInsert2(op) && op.insert.includes("\n")) {
2921
+ probeIdx = i;
2922
+ break;
2923
+ }
2924
+ }
2925
+ if (probeIdx < 0) return null;
2926
+ if (!isTableNewlineOp(ops[probeIdx])) return null;
2927
+ const probeCoords = tableCellCoordsFromOp(ops[probeIdx]);
2928
+ if (!probeCoords) return null;
2929
+ let endOpIdx = probeIdx;
2930
+ let prevCoords = probeCoords;
2931
+ for (let i = probeIdx + 1; i < ops.length; i++) {
2932
+ const op = ops[i];
2933
+ if (!op || !isInsert2(op)) break;
2934
+ if (!isTextInsert2(op) || !op.insert.includes("\n")) continue;
2935
+ if (isTableNewlineOp(op)) {
2936
+ const coords = tableCellCoordsFromOp(op);
2937
+ if (isAdjacentSimpleTableGridBoundary(prevCoords, coords)) break;
2938
+ prevCoords = coords;
2939
+ endOpIdx = i;
2940
+ } else {
2941
+ break;
2942
+ }
2943
+ }
2944
+ let startOpIdx = 0;
2945
+ let nextCoords = probeCoords;
2946
+ for (let i = probeIdx - 1; i >= 0; i--) {
2947
+ const op = ops[i];
2948
+ if (!op || !isInsert2(op)) {
2949
+ startOpIdx = i + 1;
2950
+ break;
2951
+ }
2952
+ if (!isTextInsert2(op) || !op.insert.includes("\n")) continue;
2953
+ if (isTableNewlineOp(op)) {
2954
+ const coords = tableCellCoordsFromOp(op);
2955
+ if (isAdjacentSimpleTableGridBoundary(coords, nextCoords)) {
2956
+ startOpIdx = i + 1;
2957
+ break;
2958
+ }
2959
+ nextCoords = coords;
2960
+ } else {
2961
+ startOpIdx = i + 1;
2962
+ break;
2963
+ }
2964
+ }
2965
+ const regionOps = ops.slice(startOpIdx, endOpIdx + 1);
2966
+ return { startOpIdx, endOpIdx, ops: regionOps };
2967
+ }
2968
+
2862
2969
  // src/conversion/html/delta-to-html.ts
2863
2970
  function deltaToHtml(delta, options = {}) {
2864
2971
  const lines = splitIntoLines(delta);
@@ -2879,7 +2986,7 @@ function deltaToHtml(delta, options = {}) {
2879
2986
  html += closeAllLists(listStack, pretty);
2880
2987
  listStack = [];
2881
2988
  counters = [];
2882
- const tableLines = collectTableLines(lines, i);
2989
+ const tableLines = collectAdjacentTableLines(lines, i);
2883
2990
  html += renderTable(tableLines, embedRenderers, pretty, blockHandlers, options);
2884
2991
  i += tableLines.length - 1;
2885
2992
  continue;
@@ -2988,7 +3095,7 @@ function splitIntoLines(delta) {
2988
3095
  const lines = [];
2989
3096
  let currentOps = [];
2990
3097
  for (const op of delta.ops) {
2991
- if (!isInsert2(op)) continue;
3098
+ if (!isInsert3(op)) continue;
2992
3099
  if (isEmbedInsert2(op)) {
2993
3100
  currentOps.push(op);
2994
3101
  continue;
@@ -3037,15 +3144,6 @@ function isBlockLevelEmbedLine(line) {
3037
3144
  function isTableLine(line) {
3038
3145
  return line.attributes != null && typeof line.attributes["table-row"] === "number" && typeof line.attributes["table-col"] === "number";
3039
3146
  }
3040
- function collectTableLines(lines, startIndex) {
3041
- const result = [];
3042
- for (let i = startIndex; i < lines.length; i++) {
3043
- const line = lines[i];
3044
- if (!line || !isTableLine(line)) break;
3045
- result.push(line);
3046
- }
3047
- return result;
3048
- }
3049
3147
  function renderTable(tableLines, embedRenderers, pretty, blockHandlers, options) {
3050
3148
  const rows = /* @__PURE__ */ new Map();
3051
3149
  for (const line of tableLines) {
@@ -3316,7 +3414,7 @@ function getBlockStyleAttribute(tag, attributes, resolvedDocumentPresentation) {
3316
3414
  function extractPlainText(ops) {
3317
3415
  let text = "";
3318
3416
  for (const op of ops) {
3319
- if (isInsert2(op) && typeof op.insert === "string") {
3417
+ if (isInsert3(op) && typeof op.insert === "string") {
3320
3418
  text += op.insert;
3321
3419
  }
3322
3420
  }
@@ -3325,7 +3423,7 @@ function extractPlainText(ops) {
3325
3423
  function renderLineContent(ops, embedRenderers, blockHandlers, options) {
3326
3424
  let html = "";
3327
3425
  for (const op of ops) {
3328
- if (!isInsert2(op)) continue;
3426
+ if (!isInsert3(op)) continue;
3329
3427
  if (isEmbedInsert2(op)) {
3330
3428
  html += renderEmbed(
3331
3429
  op.insert,
@@ -4123,7 +4221,7 @@ var DEFAULT_TAG_HANDLERS = {
4123
4221
  };
4124
4222
 
4125
4223
  // src/conversion/markdown/delta-to-markdown.ts
4126
- import { Delta as Delta9, isInsert as isInsert3, isTextInsert as isTextInsert2, isEmbedInsert as isEmbedInsert3 } from "@scrider/delta";
4224
+ import { Delta as Delta9, isInsert as isInsert4, isTextInsert as isTextInsert3, isEmbedInsert as isEmbedInsert3 } from "@scrider/delta";
4127
4225
 
4128
4226
  // src/conversion/markdown/config.ts
4129
4227
  var MARKDOWN_ESCAPE_CHARS = /[\\`*_[\]<>#]/g;
@@ -4211,7 +4309,7 @@ function deltaToMarkdown(delta, options = {}) {
4211
4309
  const attrs = line.attributes;
4212
4310
  const isBlockquote = !!attrs.blockquote;
4213
4311
  if (typeof attrs["table-row"] === "number" && typeof attrs["table-col"] === "number") {
4214
- const tableLines = collectTableLines2(lines, i);
4312
+ const tableLines = collectAdjacentTableLines(lines, i);
4215
4313
  result.push(
4216
4314
  renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4217
4315
  );
@@ -4316,9 +4414,9 @@ function splitIntoLines2(ops) {
4316
4414
  const lines = [];
4317
4415
  let currentOps = [];
4318
4416
  for (const op of ops) {
4319
- if (!isInsert3(op)) continue;
4417
+ if (!isInsert4(op)) continue;
4320
4418
  const opAttrs = op.attributes ?? {};
4321
- if (isTextInsert2(op)) {
4419
+ if (isTextInsert3(op)) {
4322
4420
  const text = op.insert;
4323
4421
  const parts = text.split("\n");
4324
4422
  for (let i = 0; i < parts.length; i++) {
@@ -4383,17 +4481,6 @@ function collectCodeBlock(lines, startIndex) {
4383
4481
  }
4384
4482
  return codeLines;
4385
4483
  }
4386
- function collectTableLines2(lines, startIndex) {
4387
- const result = [];
4388
- for (let i = startIndex; i < lines.length; i++) {
4389
- const line = lines[i];
4390
- if (!line || typeof line.attributes["table-row"] !== "number" || typeof line.attributes["table-col"] !== "number") {
4391
- break;
4392
- }
4393
- result.push(line);
4394
- }
4395
- return result;
4396
- }
4397
4484
  function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = false, registry, softBreakStyle = "spaces") {
4398
4485
  const rows = /* @__PURE__ */ new Map();
4399
4486
  for (const line of tableLines) {
@@ -4432,7 +4519,15 @@ function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = fa
4432
4519
  if (headerRows.length > 0) {
4433
4520
  for (const [, row] of headerRows) {
4434
4521
  mdLines.push(
4435
- renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4522
+ renderMdRow(
4523
+ row.cells,
4524
+ maxCol,
4525
+ embedRenderers,
4526
+ useLatexDelimiters,
4527
+ registry,
4528
+ softBreakStyle,
4529
+ true
4530
+ )
4436
4531
  );
4437
4532
  }
4438
4533
  mdLines.push(renderMdSeparator(maxCol, colAligns));
@@ -4442,22 +4537,38 @@ function renderMarkdownTable(tableLines, embedRenderers, useLatexDelimiters = fa
4442
4537
  emptyRow.set(col, { ops: [] });
4443
4538
  }
4444
4539
  mdLines.push(
4445
- renderMdRow(emptyRow, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4540
+ renderMdRow(
4541
+ emptyRow,
4542
+ maxCol,
4543
+ embedRenderers,
4544
+ useLatexDelimiters,
4545
+ registry,
4546
+ softBreakStyle,
4547
+ false
4548
+ )
4446
4549
  );
4447
4550
  mdLines.push(renderMdSeparator(maxCol, colAligns));
4448
4551
  }
4449
4552
  for (const [, row] of bodyRows) {
4450
4553
  mdLines.push(
4451
- renderMdRow(row.cells, maxCol, embedRenderers, useLatexDelimiters, registry, softBreakStyle)
4554
+ renderMdRow(
4555
+ row.cells,
4556
+ maxCol,
4557
+ embedRenderers,
4558
+ useLatexDelimiters,
4559
+ registry,
4560
+ softBreakStyle,
4561
+ false
4562
+ )
4452
4563
  );
4453
4564
  }
4454
4565
  return mdLines.join("\n");
4455
4566
  }
4456
- function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false, registry, softBreakStyle = "spaces") {
4567
+ function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false, registry, softBreakStyle = "spaces", isHeaderRow = false) {
4457
4568
  const parts = [];
4458
4569
  for (let col = 0; col <= maxCol; col++) {
4459
4570
  const cell = cells.get(col);
4460
- const content = cell ? renderLineContent2(
4571
+ let content = cell ? renderLineContent2(
4461
4572
  cell.ops,
4462
4573
  embedRenderers,
4463
4574
  false,
@@ -4469,6 +4580,7 @@ function renderMdRow(cells, maxCol, embedRenderers, useLatexDelimiters = false,
4469
4580
  true
4470
4581
  // inTableCell — softBreak must use <br>, never " \n"
4471
4582
  ) : "";
4583
+ if (isHeaderRow) content = serializeHeaderCell(content);
4472
4584
  parts.push(content.replace(/\|/g, "\\|"));
4473
4585
  }
4474
4586
  return "| " + parts.join(" | ") + " |";
@@ -4504,7 +4616,7 @@ function renderLineContent2(ops, embedRenderers, inCodeBlock, useLatexDelimiters
4504
4616
  let result = "";
4505
4617
  for (const op of ops) {
4506
4618
  const attrs = op.attributes;
4507
- if (isTextInsert2(op)) {
4619
+ if (isTextInsert3(op)) {
4508
4620
  const text = op.insert;
4509
4621
  if (inCodeBlock) {
4510
4622
  result += text;
@@ -4733,7 +4845,138 @@ function renderBlockFormat(content, attributes, orderedIndex, _strict) {
4733
4845
  }
4734
4846
 
4735
4847
  // src/conversion/markdown/markdown-to-delta.ts
4736
- import { Delta as Delta10 } from "@scrider/delta";
4848
+ import { Delta as Delta10, isInsert as isInsert6 } from "@scrider/delta";
4849
+
4850
+ // src/conversion/markdown/table-header-normalize.ts
4851
+ import { isInsert as isInsert5 } from "@scrider/delta";
4852
+ function isTableCellTerminator(op) {
4853
+ return isInsert5(op) && typeof op.insert === "string" && op.insert === "\n" && op.attributes !== void 0 && typeof op.attributes["table-row"] === "number";
4854
+ }
4855
+ function normalizeSyntheticEmptyHeaderRow(ops) {
4856
+ const ends = [];
4857
+ let buf = "";
4858
+ const textOpIndicesByCell = [];
4859
+ let currentTextOps = [];
4860
+ for (let i = 0; i < ops.length; i++) {
4861
+ const op = ops[i];
4862
+ if (!isInsert5(op)) continue;
4863
+ if (typeof op.insert === "string" && op.insert !== "\n") {
4864
+ buf += op.insert;
4865
+ currentTextOps.push(i);
4866
+ continue;
4867
+ }
4868
+ if (isTableCellTerminator(op)) {
4869
+ const row = op.attributes["table-row"];
4870
+ const col = op.attributes["table-col"];
4871
+ ends.push({ row, col, newlineIdx: i, text: buf });
4872
+ textOpIndicesByCell.push([...currentTextOps]);
4873
+ buf = "";
4874
+ currentTextOps = [];
4875
+ }
4876
+ }
4877
+ const row0 = ends.filter((e) => e.row === 0);
4878
+ if (row0.length === 0) return [...ops];
4879
+ if (!row0.every((e) => e.text.trim() === "")) return [...ops];
4880
+ if (row0.some((e) => isHeaderDashPlaceholder(e.text))) return [...ops];
4881
+ const remove = /* @__PURE__ */ new Set();
4882
+ for (let j = 0; j < ends.length; j++) {
4883
+ const end = ends[j];
4884
+ if (end.row !== 0) continue;
4885
+ remove.add(end.newlineIdx);
4886
+ for (const ti of textOpIndicesByCell[j] ?? []) remove.add(ti);
4887
+ }
4888
+ const out = [];
4889
+ for (let i = 0; i < ops.length; i++) {
4890
+ if (remove.has(i)) continue;
4891
+ const op = ops[i];
4892
+ if (!isTableCellTerminator(op)) {
4893
+ out.push(op);
4894
+ continue;
4895
+ }
4896
+ const row = op.attributes["table-row"];
4897
+ if (row === 0) continue;
4898
+ const attrs = { ...op.attributes };
4899
+ delete attrs["table-header"];
4900
+ out.push({
4901
+ insert: "\n",
4902
+ attributes: { ...attrs, "table-row": row - 1 }
4903
+ });
4904
+ }
4905
+ return out;
4906
+ }
4907
+ function normalizeHeaderDashPlaceholders(ops) {
4908
+ const ends = [];
4909
+ let buf = "";
4910
+ let currentTextOps = [];
4911
+ for (let i = 0; i < ops.length; i++) {
4912
+ const op = ops[i];
4913
+ if (!isInsert5(op)) continue;
4914
+ if (typeof op.insert === "string" && op.insert !== "\n") {
4915
+ buf += op.insert;
4916
+ currentTextOps.push(i);
4917
+ continue;
4918
+ }
4919
+ if (isTableCellTerminator(op)) {
4920
+ const row = op.attributes["table-row"];
4921
+ const isHeader = row === 0 && op.attributes["table-header"] === true;
4922
+ ends.push({ isHeader, textOpIndices: [...currentTextOps], text: buf });
4923
+ buf = "";
4924
+ currentTextOps = [];
4925
+ }
4926
+ }
4927
+ const dashHeaderCells = ends.filter(
4928
+ (e) => e.isHeader && e.textOpIndices.length > 0 && isHeaderDashPlaceholder(e.text)
4929
+ );
4930
+ if (dashHeaderCells.length === 0) return [...ops];
4931
+ const replaceIndices = /* @__PURE__ */ new Set();
4932
+ for (const end of dashHeaderCells) {
4933
+ for (const ti of end.textOpIndices) replaceIndices.add(ti);
4934
+ }
4935
+ const out = [];
4936
+ for (let i = 0; i < ops.length; i++) {
4937
+ const op = ops[i];
4938
+ if (!replaceIndices.has(i)) {
4939
+ out.push(op);
4940
+ continue;
4941
+ }
4942
+ if (!isInsert5(op)) {
4943
+ out.push(op);
4944
+ continue;
4945
+ }
4946
+ if (typeof op.insert === "string" && op.insert !== "\n") {
4947
+ const normalized = normalizeHeaderCellForParse(op.insert, true);
4948
+ if (normalized.length === 0) continue;
4949
+ out.push(
4950
+ op.attributes ? { insert: normalized, attributes: op.attributes } : { insert: normalized }
4951
+ );
4952
+ } else {
4953
+ out.push(op);
4954
+ }
4955
+ }
4956
+ return out;
4957
+ }
4958
+ function normalizeImportedTableOps(ops) {
4959
+ if (ops.length === 0) return [...ops];
4960
+ const ends = [];
4961
+ let buf = "";
4962
+ for (const op of ops) {
4963
+ if (!isInsert5(op)) continue;
4964
+ if (typeof op.insert === "string" && op.insert !== "\n") {
4965
+ buf += op.insert;
4966
+ continue;
4967
+ }
4968
+ if (isTableCellTerminator(op)) {
4969
+ ends.push({ row: op.attributes["table-row"], text: buf });
4970
+ buf = "";
4971
+ }
4972
+ }
4973
+ const row0 = ends.filter((e) => e.row === 0);
4974
+ const headerless = row0.length > 0 && row0.every((e) => e.text.trim() === "") && !row0.some((e) => isHeaderDashPlaceholder(e.text));
4975
+ if (headerless) return normalizeSyntheticEmptyHeaderRow(ops);
4976
+ return normalizeHeaderDashPlaceholders(ops);
4977
+ }
4978
+
4979
+ // src/conversion/markdown/markdown-to-delta.ts
4737
4980
  var remarkParse = null;
4738
4981
  var remarkGfm = null;
4739
4982
  var remarkMath = null;
@@ -5222,6 +5465,7 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
5222
5465
  }
5223
5466
  function processTable(node) {
5224
5467
  if (!node.children) return;
5468
+ const tableStart = delta.ops.length;
5225
5469
  const aligns = node.align || [];
5226
5470
  for (let rowIdx = 0; rowIdx < node.children.length; rowIdx++) {
5227
5471
  const rowNode = node.children[rowIdx];
@@ -5250,6 +5494,15 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
5250
5494
  context.pushNewline(cellBlockAttrs);
5251
5495
  }
5252
5496
  }
5497
+ const tableOps = delta.ops.splice(tableStart);
5498
+ for (const op of normalizeImportedTableOps(tableOps)) {
5499
+ if (!isInsert6(op)) continue;
5500
+ if (op.attributes && Object.keys(op.attributes).length > 0) {
5501
+ delta.insert(op.insert, op.attributes);
5502
+ } else {
5503
+ delta.insert(op.insert);
5504
+ }
5505
+ }
5253
5506
  }
5254
5507
  function isBlockLevelHtml(html) {
5255
5508
  return /^\s*<(div|table|section|article|aside|nav|header|footer|figure|pre|hr|ol|ul|dl|details|iframe|video)\b/i.test(
@@ -5429,54 +5682,6 @@ function astToDelta(tree, customHandlers, mathBlock, mermaidBlock, plantumlBlock
5429
5682
  }
5430
5683
  return delta;
5431
5684
  }
5432
-
5433
- // src/conversion/markdown/table-region.ts
5434
- import { isInsert as isInsert4, isTextInsert as isTextInsert3 } from "@scrider/delta";
5435
- function isTableNewlineOp(op) {
5436
- if (!op || !isInsert4(op) || !isTextInsert3(op)) return false;
5437
- if (!op.insert.includes("\n")) return false;
5438
- return !!op.attributes && "table-row" in op.attributes;
5439
- }
5440
- function extractTableRegion(ops, hintOpIdx) {
5441
- if (hintOpIdx < 0 || hintOpIdx >= ops.length) return null;
5442
- let probeIdx = -1;
5443
- for (let i = hintOpIdx; i < ops.length; i++) {
5444
- const op = ops[i];
5445
- if (!op || !isInsert4(op)) continue;
5446
- if (isTextInsert3(op) && op.insert.includes("\n")) {
5447
- probeIdx = i;
5448
- break;
5449
- }
5450
- }
5451
- if (probeIdx < 0) return null;
5452
- if (!isTableNewlineOp(ops[probeIdx])) return null;
5453
- let endOpIdx = probeIdx;
5454
- for (let i = probeIdx + 1; i < ops.length; i++) {
5455
- const op = ops[i];
5456
- if (!op || !isInsert4(op)) break;
5457
- if (isTextInsert3(op) && op.insert.includes("\n")) {
5458
- if (isTableNewlineOp(op)) {
5459
- endOpIdx = i;
5460
- } else {
5461
- break;
5462
- }
5463
- }
5464
- }
5465
- let startOpIdx = 0;
5466
- for (let i = probeIdx - 1; i >= 0; i--) {
5467
- const op = ops[i];
5468
- if (!op || !isInsert4(op)) {
5469
- startOpIdx = i + 1;
5470
- break;
5471
- }
5472
- if (isTextInsert3(op) && op.insert.includes("\n") && !isTableNewlineOp(op)) {
5473
- startOpIdx = i + 1;
5474
- break;
5475
- }
5476
- }
5477
- const regionOps = ops.slice(startOpIdx, endOpIdx + 1);
5478
- return { startOpIdx, endOpIdx, ops: regionOps };
5479
- }
5480
5685
  export {
5481
5686
  ALERT_TYPES,
5482
5687
  BOX_FLOAT_VALUES,
@@ -5508,6 +5713,7 @@ export {
5508
5713
  codeBlockFormat,
5509
5714
  codeFormat,
5510
5715
  codeWidgetFormat,
5716
+ collectAdjacentTableLines,
5511
5717
  colorFormat,
5512
5718
  columnsBlockHandler,
5513
5719
  createDefaultBlockHandlers,
@@ -5535,6 +5741,7 @@ export {
5535
5741
  imageFormat,
5536
5742
  indentFormat,
5537
5743
  isAdapterAvailable,
5744
+ isAdjacentSimpleTableGridBoundary,
5538
5745
  isElement,
5539
5746
  isRemarkAvailable,
5540
5747
  isTableNewlineOp,
@@ -5567,6 +5774,8 @@ export {
5567
5774
  subscriptFormat,
5568
5775
  superscriptFormat,
5569
5776
  tableBlockHandler,
5777
+ tableCellCoordsFromAttributes,
5778
+ tableCellCoordsFromOp,
5570
5779
  tableColAlignFormat,
5571
5780
  tableColFormat,
5572
5781
  tableHeaderFormat,