@scrider/formatter 1.3.3 → 1.3.4

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
@@ -77,6 +77,23 @@ deltaToHtml(delta, { registry }) // Delta → HTML string
77
77
  htmlToDelta(html, { registry }) // HTML string → Delta
78
78
  ```
79
79
 
80
+ **Simple Table presentation (v1.3.4+)** — inline borders/shades for clipboard and Office paste (Delta structure unchanged):
81
+
82
+ ```typescript
83
+ import { deltaToHtml, type TablePresentation } from '@scrider/formatter';
84
+
85
+ const tablePresentation: TablePresentation = {
86
+ grid: true,
87
+ borderColor: '#e7e7e7',
88
+ headerBold: true,
89
+ headerCenter: true,
90
+ };
91
+
92
+ deltaToHtml(delta, { tablePresentation });
93
+ ```
94
+
95
+ See scrider-editor `docs/simple-tables.md` §8 for the full contract (`grid` / `line`, `headerShade`, `zebraRows`, `defaultCellAlign`, …).
96
+
80
97
  ### Markdown Conversion
81
98
 
82
99
  ```typescript
package/dist/index.cjs CHANGED
@@ -82,6 +82,7 @@ __export(index_exports, {
82
82
  isTextNode: () => isTextNode,
83
83
  isValidColor: () => isValidColor,
84
84
  isValidHexColor: () => isValidHexColor,
85
+ isZebraBodyRow: () => isZebraBodyRow,
85
86
  italicFormat: () => italicFormat,
86
87
  kbdFormat: () => kbdFormat,
87
88
  linkFormat: () => linkFormat,
@@ -92,6 +93,7 @@ __export(index_exports, {
92
93
  nodeAdapter: () => nodeAdapter,
93
94
  normalizeDelta: () => normalizeDelta,
94
95
  preloadRemark: () => preloadRemark,
96
+ resolveTablePresentation: () => resolveTablePresentation,
95
97
  sanitizeDelta: () => sanitizeDelta,
96
98
  sizeFormat: () => sizeFormat,
97
99
  slugify: () => slugify,
@@ -2599,6 +2601,68 @@ function slugifyWithDedup(text, usedSlugs) {
2599
2601
  return `${base}-${count}`;
2600
2602
  }
2601
2603
 
2604
+ // src/conversion/html/table-presentation.ts
2605
+ var DEFAULT_BORDER_COLOR = "#e7e7e7";
2606
+ var DEFAULT_HEADER_BG = "#f5f5f5";
2607
+ var DEFAULT_ZEBRA_BG = "#fafafa";
2608
+ var CELL_PADDING = "6px 13px";
2609
+ function resolveTablePresentation(presentation) {
2610
+ return {
2611
+ grid: presentation?.grid === true,
2612
+ line: presentation?.line === true && presentation?.grid !== true,
2613
+ borderColor: presentation?.borderColor ?? DEFAULT_BORDER_COLOR,
2614
+ headerShade: presentation?.headerShade === true,
2615
+ zebraRows: presentation?.zebraRows === true,
2616
+ headerBold: presentation?.headerBold === true,
2617
+ headerCenter: presentation?.headerCenter === true,
2618
+ defaultCellAlign: presentation?.defaultCellAlign ?? "left"
2619
+ };
2620
+ }
2621
+ function isZebraBodyRow(headerRowCount, bodyRowIndex) {
2622
+ return (headerRowCount + bodyRowIndex + 1) % 2 === 0;
2623
+ }
2624
+ function isTableCellAlign(value) {
2625
+ return value === "left" || value === "center" || value === "right";
2626
+ }
2627
+ function tableOpenTag(presentation) {
2628
+ if (!presentation.grid && !presentation.line) {
2629
+ return "<table>";
2630
+ }
2631
+ return `<table style="border-collapse: collapse">`;
2632
+ }
2633
+ function buildTableCellStyleAttr(params) {
2634
+ const { presentation, cellTag, colAlign, headerRowCount, bodyRowIndex } = params;
2635
+ const parts = [];
2636
+ parts.push(`padding: ${CELL_PADDING}`);
2637
+ const color = presentation.borderColor;
2638
+ if (presentation.grid) {
2639
+ parts.push(`border: 1px solid ${color}`);
2640
+ } else if (presentation.line) {
2641
+ const width = cellTag === "th" ? "1px" : "0.5px";
2642
+ parts.push(`border-bottom: ${width} solid ${color}`);
2643
+ }
2644
+ let textAlign;
2645
+ if (cellTag === "th" && presentation.headerCenter) {
2646
+ textAlign = "center";
2647
+ } else if (isTableCellAlign(colAlign)) {
2648
+ textAlign = colAlign;
2649
+ } else if (colAlign == null || colAlign === "left") {
2650
+ textAlign = presentation.defaultCellAlign;
2651
+ }
2652
+ if (textAlign && textAlign !== "left") {
2653
+ parts.push(`text-align: ${textAlign}`);
2654
+ }
2655
+ if (cellTag === "th" && presentation.headerBold) {
2656
+ parts.push("font-weight: bold");
2657
+ }
2658
+ if (cellTag === "th" && presentation.headerShade) {
2659
+ parts.push(`background-color: ${DEFAULT_HEADER_BG}`);
2660
+ } else if (cellTag === "td" && presentation.zebraRows && bodyRowIndex !== void 0 && isZebraBodyRow(headerRowCount, bodyRowIndex)) {
2661
+ parts.push(`background-color: ${DEFAULT_ZEBRA_BG}`);
2662
+ }
2663
+ return ` style="${parts.join("; ")}"`;
2664
+ }
2665
+
2602
2666
  // src/conversion/html/delta-to-html.ts
2603
2667
  function deltaToHtml(delta, options = {}) {
2604
2668
  const lines = splitIntoLines(delta);
@@ -2782,7 +2846,10 @@ function renderTable(tableLines, embedRenderers, pretty, blockHandlers, options)
2782
2846
  const bodyRows = sortedRows.filter(([, r]) => !r.isHeader);
2783
2847
  const indent = pretty ? " " : "";
2784
2848
  const nl = pretty ? "\n" : "";
2785
- let html = `<table>${nl}`;
2849
+ const usePresentation = options?.tablePresentation !== void 0;
2850
+ const presentation = usePresentation ? resolveTablePresentation(options.tablePresentation) : null;
2851
+ const headerRowCount = headerRows.length;
2852
+ let html = usePresentation && presentation ? `${tableOpenTag(presentation)}${nl}` : `<table>${nl}`;
2786
2853
  if (headerRows.length > 0) {
2787
2854
  html += `${indent}<thead>${nl}`;
2788
2855
  for (const [, row] of headerRows) {
@@ -2794,13 +2861,16 @@ function renderTable(tableLines, embedRenderers, pretty, blockHandlers, options)
2794
2861
  pretty,
2795
2862
  2,
2796
2863
  blockHandlers,
2797
- options
2864
+ options,
2865
+ presentation,
2866
+ headerRowCount
2798
2867
  );
2799
2868
  }
2800
2869
  html += `${indent}</thead>${nl}`;
2801
2870
  }
2802
2871
  if (bodyRows.length > 0) {
2803
2872
  html += `${indent}<tbody>${nl}`;
2873
+ let bodyRowIndex = 0;
2804
2874
  for (const [, row] of bodyRows) {
2805
2875
  html += renderTableRow(
2806
2876
  row.cells,
@@ -2810,8 +2880,12 @@ function renderTable(tableLines, embedRenderers, pretty, blockHandlers, options)
2810
2880
  pretty,
2811
2881
  2,
2812
2882
  blockHandlers,
2813
- options
2883
+ options,
2884
+ presentation,
2885
+ headerRowCount,
2886
+ bodyRowIndex
2814
2887
  );
2888
+ bodyRowIndex += 1;
2815
2889
  }
2816
2890
  html += `${indent}</tbody>${nl}`;
2817
2891
  }
@@ -2819,7 +2893,7 @@ function renderTable(tableLines, embedRenderers, pretty, blockHandlers, options)
2819
2893
  if (pretty) html += "\n";
2820
2894
  return html;
2821
2895
  }
2822
- function renderTableRow(cells, maxCol, cellTag, embedRenderers, pretty, depth, blockHandlers, options) {
2896
+ function renderTableRow(cells, maxCol, cellTag, embedRenderers, pretty, depth, blockHandlers, options, presentation, headerRowCount = 0, bodyRowIndex) {
2823
2897
  const indent = pretty ? " ".repeat(depth) : "";
2824
2898
  const cellIndent = pretty ? " ".repeat(depth + 1) : "";
2825
2899
  const nl = pretty ? "\n" : "";
@@ -2827,8 +2901,19 @@ function renderTableRow(cells, maxCol, cellTag, embedRenderers, pretty, depth, b
2827
2901
  for (let col = 0; col <= maxCol; col++) {
2828
2902
  const cell = cells.get(col);
2829
2903
  const content = cell ? renderLineContent(cell.ops, embedRenderers, blockHandlers, options) : "";
2830
- const alignStyle = cell?.colAlign && cell.colAlign !== "left" ? ` style="text-align: ${cell.colAlign}"` : "";
2831
- html += `${cellIndent}<${cellTag}${alignStyle}>${content}</${cellTag}>${nl}`;
2904
+ let styleAttr = "";
2905
+ if (presentation) {
2906
+ styleAttr = buildTableCellStyleAttr({
2907
+ presentation,
2908
+ cellTag,
2909
+ colAlign: cell?.colAlign,
2910
+ headerRowCount,
2911
+ bodyRowIndex: cellTag === "td" ? bodyRowIndex : void 0
2912
+ });
2913
+ } else {
2914
+ styleAttr = cell?.colAlign && cell.colAlign !== "left" ? ` style="text-align: ${cell.colAlign}"` : "";
2915
+ }
2916
+ html += `${cellIndent}<${cellTag}${styleAttr}>${content}</${cellTag}>${nl}`;
2832
2917
  }
2833
2918
  html += `${indent}</tr>${nl}`;
2834
2919
  return html;
@@ -5155,6 +5240,7 @@ function extractTableRegion(ops, hintOpIdx) {
5155
5240
  isTextNode,
5156
5241
  isValidColor,
5157
5242
  isValidHexColor,
5243
+ isZebraBodyRow,
5158
5244
  italicFormat,
5159
5245
  kbdFormat,
5160
5246
  linkFormat,
@@ -5165,6 +5251,7 @@ function extractTableRegion(ops, hintOpIdx) {
5165
5251
  nodeAdapter,
5166
5252
  normalizeDelta,
5167
5253
  preloadRemark,
5254
+ resolveTablePresentation,
5168
5255
  sanitizeDelta,
5169
5256
  sizeFormat,
5170
5257
  slugify,