@zenodinh/pi-render 0.1.9 → 0.1.10
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/package.json +1 -1
- package/src/core/paint.ts +3 -2
- package/src/core/types/paint.ts +4 -3
- package/src/renderers/content/table.ts +24 -20
package/package.json
CHANGED
package/src/core/paint.ts
CHANGED
|
@@ -75,7 +75,8 @@ export function createRowPaint(theme: HostTheme): RowPaint {
|
|
|
75
75
|
* Region 2 — the content factory. `rule` degrades hr → quoteBorder → plain; every role ends in plain.
|
|
76
76
|
*
|
|
77
77
|
* The markdown theme's own closures supply the ink: `code` (`mdCode`) under `bold` for the table header,
|
|
78
|
-
* `heading` (`mdHeading`, the accent purple) for
|
|
78
|
+
* `heading` (`mdHeading`, the accent purple) for a body cell's code-span highlight, `bold`/`italic` for
|
|
79
|
+
* spans.
|
|
79
80
|
*/
|
|
80
81
|
// shape: closure returning an object literal — trigger #4, eight stateless content roles over the
|
|
81
82
|
// captured markdown theme.
|
|
@@ -94,6 +95,6 @@ export function createContentPaint(mdTheme: MarkdownTheme): ContentPaint {
|
|
|
94
95
|
strong: (text) => tryStyle(mdTheme.bold, text) ?? text,
|
|
95
96
|
em: (text) => tryStyle(mdTheme.italic, text) ?? text,
|
|
96
97
|
header,
|
|
97
|
-
|
|
98
|
+
cellHighlight: (text) => tryStyle(mdTheme.heading, text) ?? text,
|
|
98
99
|
};
|
|
99
100
|
}
|
package/src/core/types/paint.ts
CHANGED
|
@@ -69,8 +69,9 @@ export interface ContentPaint {
|
|
|
69
69
|
*/
|
|
70
70
|
header(text: string): string;
|
|
71
71
|
/**
|
|
72
|
-
* One table
|
|
73
|
-
*
|
|
72
|
+
* One highlighted span inside a table BODY cell — a code span today: the theme's `heading` closure
|
|
73
|
+
* (`mdHeading`, purple in `dracula-soft`). The cell's regular text stays the default ink (#64).
|
|
74
|
+
* Degrades to plain text without the closure. Required.
|
|
74
75
|
*/
|
|
75
|
-
|
|
76
|
+
cellHighlight(text: string): string;
|
|
76
77
|
}
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
/**
|
|
8
8
|
* table.ts — the table surface: a markdown table becomes a boxed box with inked text.
|
|
9
9
|
*
|
|
10
|
-
* The header row's cells take the header ink — bold over `mdCode
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
* separator are dropped and the first column's labels
|
|
15
|
-
* `*em*` cells route through their own roles.
|
|
10
|
+
* The header row's cells take the header ink — bold over `mdCode`, over the whole cell, so a code span
|
|
11
|
+
* inside a header cell adds no ink of its own. A body cell's own text keeps the default ink; only a
|
|
12
|
+
* code span inside it takes the cell highlight — the theme's `mdHeading` purple (owner look-check,
|
|
13
|
+
* 2026-10-09, #64). Nothing paints a background: the band was removed the same day (#62). When the
|
|
14
|
+
* header row is empty (`| | |`), that row and its separator are dropped and the first column's labels
|
|
15
|
+
* take the header ink instead. `**strong**` and `*em*` cells route through their own roles.
|
|
16
16
|
*
|
|
17
17
|
* Boundary: lane-local. The transformer passes markdown in and splices the returned markdown back
|
|
18
18
|
* out, so every escape in the output originates in the injected ContentPaint (T-08) — the #22 fix.
|
|
@@ -87,15 +87,15 @@ function inlineText(token: InlineToken, paint: ContentPaint): string {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* The cell's text with its inline spans composed
|
|
91
|
-
* identity
|
|
90
|
+
* The cell's text with its inline spans composed, `codeSpanInk` drawing each code span. The caller picks
|
|
91
|
+
* it per region: the identity where the cell's own role inks the whole text (header cells, key-column
|
|
92
|
+
* labels), the highlight role where the text stays default and only the code span is inked (#64).
|
|
92
93
|
*/
|
|
93
|
-
function cellText(cell: CellLike | undefined, paint: ContentPaint): string {
|
|
94
|
+
function cellText(cell: CellLike | undefined, paint: ContentPaint, codeSpanInk: (text: string) => string): string {
|
|
94
95
|
const tokens = cell?.tokens;
|
|
95
|
-
const uninked: ContentPaint = { ...paint, code: (text) => text };
|
|
96
96
|
const text =
|
|
97
97
|
Array.isArray(tokens) && tokens.length > 0
|
|
98
|
-
? tokens.map((token) => inlineText(token,
|
|
98
|
+
? tokens.map((token) => inlineText(token, { ...paint, code: codeSpanInk })).join("")
|
|
99
99
|
: (cell?.text ?? "");
|
|
100
100
|
// Soft wraps inside a cell are one logical line before the width solve.
|
|
101
101
|
return text.replace(/\s+/g, " ").trim();
|
|
@@ -108,8 +108,16 @@ function padCell(content: string, width: number): string {
|
|
|
108
108
|
|
|
109
109
|
/** shape: none — one greedy width solve plus a largest-remainder fill; a table is small and the rule is exact. */
|
|
110
110
|
function renderTable(token: TableToken, width: number, paint: ContentPaint): string[] {
|
|
111
|
-
|
|
112
|
-
const
|
|
111
|
+
/** A label cell (the header row, or a key-column table's first column): the whole text takes the header ink. */
|
|
112
|
+
const label = (cell: CellLike | undefined): string => cellText(cell, paint, (text) => text);
|
|
113
|
+
/** A body cell: its text stays default, and a code span inside it takes the highlight ink. */
|
|
114
|
+
const body = (cell: CellLike | undefined): string => cellText(cell, paint, (text) => paint.cellHighlight(text));
|
|
115
|
+
|
|
116
|
+
const header = token.header.map(label);
|
|
117
|
+
// An all-empty header (`| | |`) means the table carries its labels in the first column: the blank
|
|
118
|
+
// header row and its separator are dropped, and those labels take the header ink instead.
|
|
119
|
+
const keyColumn = header.every((cell) => cell === "");
|
|
120
|
+
const rows = token.rows.map((row) => row.map((cell, index) => (keyColumn && index === 0 ? label(cell) : body(cell))));
|
|
113
121
|
const columns = Math.max(1, header.length);
|
|
114
122
|
const natural: number[] = [];
|
|
115
123
|
for (let index = 0; index < columns; index++) {
|
|
@@ -147,10 +155,6 @@ function renderTable(token: TableToken, width: number, paint: ContentPaint): str
|
|
|
147
155
|
}
|
|
148
156
|
}
|
|
149
157
|
|
|
150
|
-
// An all-empty header (`| | |`) means the table carries its labels in the first column: the blank
|
|
151
|
-
// header row and its separator are dropped, and those labels take the header ink instead.
|
|
152
|
-
const keyColumn = header.every((cell) => cell === "");
|
|
153
|
-
|
|
154
158
|
// A light box around and between everything: the frame is what keeps a wrapped cell visually
|
|
155
159
|
// inside the table instead of trailing off its right edge.
|
|
156
160
|
const ruleLine = (left: string, middle: string, right: string): string =>
|
|
@@ -158,7 +162,7 @@ function renderTable(token: TableToken, width: number, paint: ContentPaint): str
|
|
|
158
162
|
const bar = paint.rule("│");
|
|
159
163
|
const physical: string[] = [];
|
|
160
164
|
|
|
161
|
-
/** One logical row, wrapped into physical lines; `ink`
|
|
165
|
+
/** One logical row, wrapped into physical lines; `ink` wraps each cell's text line by line. */
|
|
162
166
|
const renderRow = (cells: string[], ink: (text: string, index: number) => string): void => {
|
|
163
167
|
const wrapped = cells.map((cell, index) => wrapTextWithAnsi(cell, widths[index] ?? MIN_COLUMN));
|
|
164
168
|
const height = Math.max(1, ...wrapped.map((lines) => lines.length));
|
|
@@ -174,14 +178,14 @@ function renderTable(token: TableToken, width: number, paint: ContentPaint): str
|
|
|
174
178
|
if (keyColumn) {
|
|
175
179
|
rows.forEach((row, index) => {
|
|
176
180
|
if (index > 0) physical.push(ruleLine("├", "┼", "┤"));
|
|
177
|
-
renderRow(row, (text, column) => (column === 0 ? paint.header(text) :
|
|
181
|
+
renderRow(row, (text, column) => (column === 0 ? paint.header(text) : text));
|
|
178
182
|
});
|
|
179
183
|
} else {
|
|
180
184
|
renderRow(header, (text) => paint.header(text));
|
|
181
185
|
physical.push(ruleLine("├", "┼", "┤"));
|
|
182
186
|
rows.forEach((row, index) => {
|
|
183
187
|
if (index > 0) physical.push(ruleLine("├", "┼", "┤"));
|
|
184
|
-
renderRow(row, (text) =>
|
|
188
|
+
renderRow(row, (text) => text);
|
|
185
189
|
});
|
|
186
190
|
}
|
|
187
191
|
physical.push(ruleLine("└", "┴", "┘"));
|