@tooee/renderers 0.1.11 → 0.1.14

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.
Files changed (43) hide show
  1. package/dist/CodeView.d.ts +3 -7
  2. package/dist/CodeView.d.ts.map +1 -1
  3. package/dist/CodeView.js +5 -31
  4. package/dist/CodeView.js.map +1 -1
  5. package/dist/CommandPalette.d.ts.map +1 -1
  6. package/dist/CommandPalette.js +1 -23
  7. package/dist/CommandPalette.js.map +1 -1
  8. package/dist/DecorationLayer.d.ts +14 -0
  9. package/dist/DecorationLayer.d.ts.map +1 -0
  10. package/dist/DecorationLayer.js +2 -0
  11. package/dist/DecorationLayer.js.map +1 -0
  12. package/dist/MarkdownView.d.ts +16 -9
  13. package/dist/MarkdownView.d.ts.map +1 -1
  14. package/dist/MarkdownView.js +256 -107
  15. package/dist/MarkdownView.js.map +1 -1
  16. package/dist/RowDocumentRenderable.d.ts +14 -26
  17. package/dist/RowDocumentRenderable.d.ts.map +1 -1
  18. package/dist/RowDocumentRenderable.js +74 -78
  19. package/dist/RowDocumentRenderable.js.map +1 -1
  20. package/dist/Table.d.ts +5 -9
  21. package/dist/Table.d.ts.map +1 -1
  22. package/dist/Table.js +17 -46
  23. package/dist/Table.js.map +1 -1
  24. package/dist/index.d.ts +7 -3
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +4 -2
  27. package/dist/index.js.map +1 -1
  28. package/dist/parsers.d.ts.map +1 -1
  29. package/dist/parsers.js.map +1 -1
  30. package/dist/useGutterPalette.d.ts +3 -0
  31. package/dist/useGutterPalette.d.ts.map +1 -0
  32. package/dist/useGutterPalette.js +10 -0
  33. package/dist/useGutterPalette.js.map +1 -0
  34. package/package.json +18 -16
  35. package/src/CodeView.tsx +11 -54
  36. package/src/CommandPalette.tsx +1 -25
  37. package/src/DecorationLayer.ts +11 -0
  38. package/src/MarkdownView.tsx +382 -164
  39. package/src/RowDocumentRenderable.ts +91 -135
  40. package/src/Table.tsx +35 -71
  41. package/src/index.ts +6 -8
  42. package/src/parsers.ts +4 -1
  43. package/src/useGutterPalette.ts +15 -0
@@ -8,6 +8,7 @@ import {
8
8
  RGBA,
9
9
  } from "@opentui/core"
10
10
  import type { OptimizedBuffer } from "@opentui/core"
11
+ import type { DecorationLayer, RowDecoration } from "./DecorationLayer.js"
11
12
 
12
13
  // ---------------------------------------------------------------------------
13
14
  // Types
@@ -16,25 +17,6 @@ import type { OptimizedBuffer } from "@opentui/core"
16
17
  export interface RowDocumentPalette {
17
18
  gutterFg?: string
18
19
  gutterBg?: string
19
- cursorBg?: string
20
- selectionBg?: string
21
- matchBg?: string
22
- currentMatchBg?: string
23
- toggledBg?: string
24
- cursorSign?: string
25
- cursorSignFg?: string
26
- matchSign?: string
27
- matchSignFg?: string
28
- currentMatchSignFg?: string
29
- }
30
-
31
- export interface RowDocumentDecorations {
32
- cursorRow?: number
33
- selection?: { start: number; end: number } | null
34
- matchingRows?: Set<number>
35
- currentMatchRow?: number
36
- toggledRows?: Set<number>
37
- signs?: Map<number, { text: string; fg?: string }>
38
20
  }
39
21
 
40
22
  export interface RowDocumentOptions extends ScrollBoxOptions {
@@ -52,6 +34,7 @@ export interface RowDocumentOptions extends ScrollBoxOptions {
52
34
 
53
35
  // Colors
54
36
  palette?: RowDocumentPalette
37
+ decorations?: readonly DecorationLayer[]
55
38
  }
56
39
 
57
40
  // ---------------------------------------------------------------------------
@@ -60,11 +43,7 @@ export interface RowDocumentOptions extends ScrollBoxOptions {
60
43
 
61
44
  function isRowContentProvider(x: unknown): x is LineInfoProvider {
62
45
  return (
63
- !!x &&
64
- typeof x === "object" &&
65
- "lineInfo" in x &&
66
- "lineCount" in x &&
67
- "virtualLineCount" in x
46
+ !!x && typeof x === "object" && "lineInfo" in x && "lineCount" in x && "virtualLineCount" in x
68
47
  )
69
48
  }
70
49
 
@@ -83,6 +62,37 @@ function cachedColor(hex: string): RGBA {
83
62
  return c
84
63
  }
85
64
 
65
+ function normalizePalette(palette: RowDocumentPalette = {}): Required<RowDocumentPalette> {
66
+ return {
67
+ gutterFg: palette.gutterFg ?? "#6e7681",
68
+ gutterBg: palette.gutterBg ?? "#0d1117",
69
+ }
70
+ }
71
+
72
+ function normalizeDecorationLayers(
73
+ layers: readonly DecorationLayer[] | undefined,
74
+ ): readonly DecorationLayer[] {
75
+ if (!layers || layers.length === 0) return []
76
+ return [...layers].sort((a, b) => a.priority - b.priority)
77
+ }
78
+
79
+ export function computeRowDocumentGutterWidth(opts: {
80
+ showLineNumbers: boolean
81
+ rowCount: number
82
+ lineNumberStart?: number
83
+ signColumnWidth?: number
84
+ gutterPaddingRight?: number
85
+ }): number {
86
+ let width = 0
87
+ if (opts.showLineNumbers) {
88
+ const maxLineNum = (opts.lineNumberStart ?? 1) + opts.rowCount - 1
89
+ width += Math.max(String(maxLineNum).length, 1)
90
+ }
91
+ width += opts.signColumnWidth ?? 0
92
+ width += opts.gutterPaddingRight ?? 1
93
+ return width
94
+ }
95
+
86
96
  // ---------------------------------------------------------------------------
87
97
  // RowDocumentRenderable
88
98
  // ---------------------------------------------------------------------------
@@ -97,9 +107,9 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
97
107
  private _gutterPaddingRight: number
98
108
  private _rowChildOffset: number
99
109
  private _palette: Required<RowDocumentPalette>
100
-
101
- // -- Decorations --
102
- private _deco: RowDocumentDecorations = {}
110
+ private _layers: readonly DecorationLayer[] = []
111
+ private _layerGutterBgs = new Map<number, string>()
112
+ private _layerSigns = new Map<number, NonNullable<RowDecoration["sign"]>>()
103
113
 
104
114
  // -- Geometry arrays --
105
115
  private _rowVirtualStarts: number[] = []
@@ -120,29 +130,21 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
120
130
  this._gutterPaddingRight = options.gutterPaddingRight ?? 1
121
131
  this._rowChildOffset = options.rowChildOffset ?? 0
122
132
 
123
- const p = options.palette ?? {}
124
- this._palette = {
125
- gutterFg: p.gutterFg ?? "#6e7681",
126
- gutterBg: p.gutterBg ?? "#0d1117",
127
- cursorBg: p.cursorBg ?? "#1c2128",
128
- selectionBg: p.selectionBg ?? "#1f3a5f",
129
- matchBg: p.matchBg ?? "#3b2e00",
130
- currentMatchBg: p.currentMatchBg ?? "#5a4a00",
131
- toggledBg: p.toggledBg ?? "#1c2128",
132
- cursorSign: p.cursorSign ?? "▸",
133
- cursorSignFg: p.cursorSignFg ?? "#58a6ff",
134
- matchSign: p.matchSign ?? "●",
135
- matchSignFg: p.matchSignFg ?? "#d29922",
136
- currentMatchSignFg: p.currentMatchSignFg ?? "#f0c000",
137
- }
133
+ this._palette = normalizePalette(options.palette)
134
+ this._layers = normalizeDecorationLayers(options.decorations)
138
135
  }
139
136
 
140
137
  // -----------------------------------------------------------------------
141
138
  // Decorations
142
139
  // -----------------------------------------------------------------------
143
140
 
144
- setDecorations(decorations: RowDocumentDecorations): void {
145
- this._deco = decorations
141
+ set decorations(layers: readonly DecorationLayer[] | undefined) {
142
+ this._layers = normalizeDecorationLayers(layers)
143
+ this.requestRender()
144
+ }
145
+
146
+ set palette(palette: RowDocumentPalette | undefined) {
147
+ this._palette = normalizePalette(palette)
146
148
  this.requestRender()
147
149
  }
148
150
 
@@ -178,9 +180,7 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
178
180
  return this._virtualRowToRow.length
179
181
  }
180
182
 
181
- getRowMetrics(
182
- row: number,
183
- ): { row: number; virtualTop: number; virtualHeight: number } | null {
183
+ getRowMetrics(row: number): { row: number; virtualTop: number; virtualHeight: number } | null {
184
184
  if (row < 0 || row >= this._rowCount) return null
185
185
  return {
186
186
  row,
@@ -221,10 +221,7 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
221
221
  // scrollToRow
222
222
  // -----------------------------------------------------------------------
223
223
 
224
- scrollToRow(
225
- row: number,
226
- align: "nearest" | "start" | "center" | "end" = "nearest",
227
- ): void {
224
+ scrollToRow(row: number, align: "nearest" | "start" | "center" | "end" = "nearest"): void {
228
225
  const metrics = this.getRowMetrics(row)
229
226
  if (!metrics) return
230
227
 
@@ -399,8 +396,7 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
399
396
 
400
397
  // Finalize last row
401
398
  if (currentRow >= 0) {
402
- rowVirtualHeights[currentRow] =
403
- lineSources.length - rowVirtualStarts[currentRow]
399
+ rowVirtualHeights[currentRow] = lineSources.length - rowVirtualStarts[currentRow]
404
400
  }
405
401
 
406
402
  this._finishGeometry(
@@ -439,17 +435,13 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
439
435
  private _computeGutterWidth(): number {
440
436
  if (!this._showGutter) return 0
441
437
 
442
- let width = 0
443
-
444
- if (this._showLineNumbers) {
445
- const maxLineNum = this._lineNumberStart + this._rowCount - 1
446
- width += Math.max(String(maxLineNum).length, 1)
447
- }
448
-
449
- width += this._signColumnWidth
450
- width += this._gutterPaddingRight
451
-
452
- return width
438
+ return computeRowDocumentGutterWidth({
439
+ showLineNumbers: this._showLineNumbers,
440
+ rowCount: this._rowCount,
441
+ lineNumberStart: this._lineNumberStart,
442
+ signColumnWidth: this._signColumnWidth,
443
+ gutterPaddingRight: this._gutterPaddingRight,
444
+ })
453
445
  }
454
446
 
455
447
  private _applyGutterPadding(): void {
@@ -462,22 +454,10 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
462
454
  // -----------------------------------------------------------------------
463
455
 
464
456
  private _paintDecorations(buffer: OptimizedBuffer): void {
465
- const {
466
- cursorRow,
467
- selection,
468
- matchingRows,
469
- currentMatchRow,
470
- toggledRows,
471
- } = this._deco
472
-
473
- const hasDecorations =
474
- cursorRow != null ||
475
- selection != null ||
476
- (matchingRows && matchingRows.size > 0) ||
477
- currentMatchRow != null ||
478
- (toggledRows && toggledRows.size > 0)
479
-
480
- if (!hasDecorations) return
457
+ this._layerGutterBgs = new Map()
458
+ this._layerSigns = new Map()
459
+
460
+ if (this._layers.length === 0) return
481
461
 
482
462
  const vpX = this.viewport.x
483
463
  const vpY = this.viewport.y
@@ -485,35 +465,32 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
485
465
  const vpWidth = this.viewport.width
486
466
  const top = Math.floor(this.scrollTop)
487
467
 
468
+ const { firstRow, lastRow } = this.getVisibleRange()
469
+ const rowBgs = new Map<number, string>()
470
+ const rowGutterBgs = new Map<number, string>()
471
+ const rowSigns = new Map<number, NonNullable<RowDecoration["sign"]>>()
472
+
473
+ for (const layer of this._layers) {
474
+ for (const deco of layer.forVisibleRows(firstRow, lastRow)) {
475
+ if (deco.background) rowBgs.set(deco.row, deco.background)
476
+ if (deco.gutterBackground) rowGutterBgs.set(deco.row, deco.gutterBackground)
477
+ if (deco.sign) rowSigns.set(deco.row, deco.sign)
478
+ }
479
+ }
480
+
488
481
  for (let screenY = 0; screenY < vpHeight; screenY++) {
489
482
  const vRow = top + screenY
490
483
  if (vRow >= this._virtualRowToRow.length) break
491
484
 
492
485
  const row = this._virtualRowToRow[vRow]
493
486
  if (row < 0) continue // Skip gap rows (margins)
494
- let bg: RGBA | null = null
495
-
496
- // Priority order: currentMatch > match > selection > toggled > cursor
497
- if (cursorRow != null && row === cursorRow) {
498
- bg = cachedColor(this._palette.cursorBg)
499
- }
500
- if (toggledRows && toggledRows.has(row)) {
501
- bg = cachedColor(this._palette.toggledBg)
502
- }
503
- if (selection && row >= selection.start && row <= selection.end) {
504
- bg = cachedColor(this._palette.selectionBg)
505
- }
506
- if (matchingRows && matchingRows.has(row)) {
507
- bg = cachedColor(this._palette.matchBg)
508
- }
509
- if (currentMatchRow != null && row === currentMatchRow) {
510
- bg = cachedColor(this._palette.currentMatchBg)
511
- }
512
-
513
- if (bg) {
514
- buffer.fillRect(vpX, vpY + screenY, vpWidth, 1, bg)
515
- }
487
+ const bg = rowBgs.get(row)
488
+ if (!bg) continue
489
+ buffer.fillRect(vpX, vpY + screenY, vpWidth, 1, cachedColor(bg))
516
490
  }
491
+
492
+ this._layerGutterBgs = rowGutterBgs
493
+ this._layerSigns = rowSigns
517
494
  }
518
495
 
519
496
  // -----------------------------------------------------------------------
@@ -552,53 +529,32 @@ export class RowDocumentRenderable extends ScrollBoxRenderable {
552
529
  const drawX = vpX
553
530
  let col = 0
554
531
 
532
+ const rowGutterHex = this._layerGutterBgs.get(row)
533
+ const effectiveGutterBg = rowGutterHex ? cachedColor(rowGutterHex) : gutterBg
534
+ if (rowGutterHex) {
535
+ buffer.fillRect(drawX, vpY + screenY, gutterWidth, 1, effectiveGutterBg)
536
+ }
537
+
555
538
  // Line number
556
539
  if (this._showLineNumbers) {
557
540
  const lineNum = String(this._lineNumberStart + row)
558
541
  const padded = lineNum.padStart(lineNumWidth, " ")
559
- buffer.drawText(padded, drawX + col, vpY + screenY, gutterFg, gutterBg)
542
+ buffer.drawText(padded, drawX + col, vpY + screenY, gutterFg, effectiveGutterBg)
560
543
  col += lineNumWidth
561
544
  }
562
545
 
563
546
  // Sign column
564
547
  if (this._signColumnWidth > 0) {
565
- const { cursorRow, matchingRows, currentMatchRow } = this._deco
566
- const customSign = this._deco.signs?.get(row)
548
+ const sign = this._layerSigns.get(row)
567
549
 
568
- if (customSign) {
569
- const signFg = customSign.fg
570
- ? cachedColor(customSign.fg)
571
- : gutterFg
550
+ if (sign) {
551
+ const signFg = sign.fg ? cachedColor(sign.fg) : gutterFg
572
552
  buffer.drawText(
573
- customSign.text.slice(0, this._signColumnWidth),
553
+ sign.text.slice(0, this._signColumnWidth),
574
554
  drawX + col,
575
555
  vpY + screenY,
576
556
  signFg,
577
- gutterBg,
578
- )
579
- } else if (cursorRow != null && row === cursorRow) {
580
- buffer.drawText(
581
- this._palette.cursorSign,
582
- drawX + col,
583
- vpY + screenY,
584
- cachedColor(this._palette.cursorSignFg),
585
- gutterBg,
586
- )
587
- } else if (currentMatchRow != null && row === currentMatchRow) {
588
- buffer.drawText(
589
- this._palette.matchSign,
590
- drawX + col,
591
- vpY + screenY,
592
- cachedColor(this._palette.currentMatchSignFg),
593
- gutterBg,
594
- )
595
- } else if (matchingRows && matchingRows.has(row)) {
596
- buffer.drawText(
597
- this._palette.matchSign,
598
- drawX + col,
599
- vpY + screenY,
600
- cachedColor(this._palette.matchSignFg),
601
- gutterBg,
557
+ effectiveGutterBg,
602
558
  )
603
559
  }
604
560
  }
package/src/Table.tsx CHANGED
@@ -1,8 +1,13 @@
1
1
  import { useTerminalDimensions } from "@opentui/react"
2
2
  import { useTheme } from "@tooee/themes"
3
- import { useEffect, useRef, type RefObject } from "react"
3
+ import { type RefObject } from "react"
4
+ import type { MarkState } from "@tooee/marks"
4
5
  import type { ColumnDef, TableRow } from "./table-types.js"
5
- import type { RowDocumentRenderable, RowDocumentPalette, RowDocumentDecorations } from "./RowDocumentRenderable.js"
6
+ import {
7
+ computeRowDocumentGutterWidth,
8
+ type RowDocumentRenderable,
9
+ } from "./RowDocumentRenderable.js"
10
+ import { useGutterPalette } from "./useGutterPalette.js"
6
11
  import "./row-document.js"
7
12
 
8
13
  export interface TableProps {
@@ -18,12 +23,7 @@ export interface TableProps {
18
23
  sampleSize?: number
19
24
  /** Show line numbers in the gutter (default: true) */
20
25
  showLineNumbers?: boolean
21
- cursor?: number
22
- selectionStart?: number
23
- selectionEnd?: number
24
- matchingRows?: Set<number>
25
- currentMatchRow?: number
26
- toggledRows?: Set<number>
26
+ marks?: MarkState
27
27
  docRef?: RefObject<RowDocumentRenderable | null>
28
28
  /** Column width mode: "content" sizes to content (default), "fill" expands to fill available width */
29
29
  columnWidthMode?: "content" | "fill"
@@ -73,7 +73,10 @@ function computeColumnWidths(
73
73
  // Use Bun.stringWidth for correct display width with CJK/emoji
74
74
  const naturalWidths = headers.map((header, col) => {
75
75
  const headerLen = Bun.stringWidth(header)
76
- const maxRowLen = sampledRows.reduce((max, row) => Math.max(max, Bun.stringWidth(row[col] ?? "")), 0)
76
+ const maxRowLen = sampledRows.reduce(
77
+ (max, row) => Math.max(max, Bun.stringWidth(row[col] ?? "")),
78
+ 0,
79
+ )
77
80
  const contentWidth = Math.max(headerLen, maxRowLen)
78
81
  // Apply min/max constraints before adding padding
79
82
  const constrainedWidth = Math.min(maxColumnWidth, Math.max(minColumnWidth, contentWidth))
@@ -124,22 +127,6 @@ function computeColumnWidths(
124
127
  })
125
128
  }
126
129
 
127
- /**
128
- * Pre-compute gutter width to subtract from available column space.
129
- * Mirrors RowDocumentRenderable._computeGutterWidth logic.
130
- */
131
- function computeGutterWidth(rowCount: number, showLineNumbers: boolean): number {
132
- let width = 0
133
- if (showLineNumbers) {
134
- // lineNumberStart defaults to 1, so max line number = rowCount
135
- const maxLineNum = rowCount
136
- width += Math.max(String(maxLineNum).length, 1)
137
- }
138
- width += 1 // signColumnWidth
139
- width += 1 // gutterPaddingRight (default)
140
- return width
141
- }
142
-
143
130
  function formatCellValue(value: unknown): string {
144
131
  if (value == null) return ""
145
132
  if (typeof value === "string") return value
@@ -160,20 +147,20 @@ export function Table({
160
147
  maxColumnWidth = DEFAULT_MAX_COL_WIDTH,
161
148
  sampleSize = DEFAULT_SAMPLE_SIZE,
162
149
  showLineNumbers = true,
163
- cursor,
164
- selectionStart,
165
- selectionEnd,
166
- matchingRows,
167
- currentMatchRow,
168
- toggledRows,
150
+ marks,
169
151
  docRef,
170
152
  columnWidthMode = "content",
171
153
  }: TableProps) {
172
154
  const { theme } = useTheme()
155
+ const palette = useGutterPalette()
173
156
  const { width: terminalWidth } = useTerminalDimensions()
174
157
 
175
158
  // Compute available content width: start with total space, subtract margins and gutter
176
- const gutterWidth = computeGutterWidth(rows.length, showLineNumbers)
159
+ const gutterWidth = computeRowDocumentGutterWidth({
160
+ showLineNumbers,
161
+ rowCount: rows.length,
162
+ signColumnWidth: 1,
163
+ })
177
164
  const effectiveMaxWidth = Math.max(0, (maxWidth ?? terminalWidth) - MARGIN * 2 - gutterWidth)
178
165
 
179
166
  const headers = columns.map((column) => column.header ?? column.key)
@@ -197,37 +184,16 @@ export function Table({
197
184
  return numericCount > sampleValues.length / 2
198
185
  })
199
186
 
200
- const internalRef = useRef<RowDocumentRenderable>(null)
201
- const effectiveRef = docRef ?? internalRef
202
-
203
- const palette: RowDocumentPalette = {
204
- gutterFg: theme.textMuted,
205
- gutterBg: theme.backgroundElement,
206
- cursorSignFg: theme.primary,
207
- matchSignFg: theme.warning,
208
- currentMatchSignFg: theme.primary,
209
- cursorBg: theme.cursorLine,
210
- selectionBg: theme.selection,
211
- matchBg: theme.warning,
212
- currentMatchBg: theme.primary,
213
- toggledBg: theme.backgroundPanel,
214
- }
215
-
216
- useEffect(() => {
217
- const decorations: RowDocumentDecorations = {
218
- cursorRow: cursor,
219
- selection: selectionStart != null && selectionEnd != null
220
- ? { start: selectionStart, end: selectionEnd }
221
- : null,
222
- matchingRows: matchingRows,
223
- currentMatchRow: currentMatchRow,
224
- toggledRows: toggledRows,
225
- }
226
- effectiveRef.current?.setDecorations(decorations)
227
- }, [cursor, selectionStart, selectionEnd, matchingRows, currentMatchRow, toggledRows])
228
-
229
187
  return (
230
- <box style={{ flexDirection: "column", flexGrow: 1, marginLeft: MARGIN, marginRight: MARGIN, marginBottom: MARGIN }}>
188
+ <box
189
+ style={{
190
+ flexDirection: "column",
191
+ flexGrow: 1,
192
+ marginLeft: MARGIN,
193
+ marginRight: MARGIN,
194
+ marginBottom: MARGIN,
195
+ }}
196
+ >
231
197
  {/* Fixed header row — outside row-document so it stays visible */}
232
198
  <box style={{ flexDirection: "row", flexShrink: 0, paddingLeft: gutterWidth }}>
233
199
  {headers.map((h, i) => (
@@ -254,13 +220,14 @@ export function Table({
254
220
 
255
221
  {/* Scrollable data rows */}
256
222
  <row-document
257
- ref={effectiveRef}
223
+ ref={docRef}
258
224
  mode="multi"
259
225
  rowChildOffset={0}
260
226
  showGutter={true}
261
227
  showLineNumbers={showLineNumbers}
262
228
  signColumnWidth={1}
263
229
  palette={palette}
230
+ decorations={marks?.sets}
264
231
  style={{ flexGrow: 1 }}
265
232
  >
266
233
  {normalizedRows.map((row, i) => (
@@ -268,9 +235,10 @@ export function Table({
268
235
  {row.map((cell, j) => {
269
236
  const contentWidth = colWidths[j] - PADDING * 2
270
237
  const cellWidth = Bun.stringWidth(cell)
271
- const displayCell = alignments[j] && cellWidth <= contentWidth
272
- ? " ".repeat(contentWidth - cellWidth) + cell
273
- : cell
238
+ const displayCell =
239
+ alignments[j] && cellWidth <= contentWidth
240
+ ? " ".repeat(contentWidth - cellWidth) + cell
241
+ : cell
274
242
  return (
275
243
  <text
276
244
  key={j}
@@ -293,9 +261,5 @@ export function Table({
293
261
  }
294
262
 
295
263
  // Exported for testing and MarkdownView
296
- export {
297
- computeColumnWidths,
298
- isNumeric,
299
- sampleRows,
300
- }
264
+ export { computeColumnWidths, isNumeric, sampleRows }
301
265
  export type { ColumnWidthOptions }
package/src/index.ts CHANGED
@@ -1,12 +1,8 @@
1
- export { MarkdownView } from "./MarkdownView.js"
1
+ export { MarkdownView, flattenTokens } from "./MarkdownView.js"
2
+ export type { FlatBlock } from "./MarkdownView.js"
2
3
  export { CodeView } from "./CodeView.js"
3
4
  export { ImageView } from "./ImageView.js"
4
- export {
5
- Table,
6
- computeColumnWidths,
7
- isNumeric,
8
- sampleRows,
9
- } from "./Table.js"
5
+ export { Table, computeColumnWidths, isNumeric, sampleRows } from "./Table.js"
10
6
  export type { TableProps, ColumnWidthOptions } from "./Table.js"
11
7
  export type { ColumnDef, TableRow } from "./table-types.js"
12
8
  export { CommandPalette } from "./CommandPalette.js"
@@ -14,8 +10,10 @@ export type { CommandPaletteEntry } from "./CommandPalette.js"
14
10
  export { parseCSV, parseTSV, parseJSON, parseAuto, detectFormat } from "./parsers.js"
15
11
  export type { Format, ParsedTable } from "./parsers.js"
16
12
  export { RowDocumentRenderable } from "./RowDocumentRenderable.js"
13
+ export { computeRowDocumentGutterWidth } from "./RowDocumentRenderable.js"
17
14
  export type {
18
15
  RowDocumentOptions,
19
16
  RowDocumentPalette,
20
- RowDocumentDecorations,
21
17
  } from "./RowDocumentRenderable.js"
18
+ export type { DecorationLayer, RowDecoration } from "./DecorationLayer.js"
19
+ export { useGutterPalette } from "./useGutterPalette.js"
package/src/parsers.ts CHANGED
@@ -56,7 +56,10 @@ export function parseTSV(input: string): { columns: ColumnDef[]; rows: TableRow[
56
56
  const lines = splitLines(input)
57
57
  if (lines.length === 0) return { columns: [], rows: [] }
58
58
  const columns = createColumnDefs(lines[0].split("\t"))
59
- const rows = buildRows(columns, lines.slice(1).map((line) => line.split("\t")))
59
+ const rows = buildRows(
60
+ columns,
61
+ lines.slice(1).map((line) => line.split("\t")),
62
+ )
60
63
  return { columns, rows }
61
64
  }
62
65
 
@@ -0,0 +1,15 @@
1
+ import { useMemo } from "react"
2
+ import { useTheme } from "@tooee/themes"
3
+ import type { RowDocumentPalette } from "./RowDocumentRenderable.js"
4
+
5
+ export function useGutterPalette(): RowDocumentPalette {
6
+ const { theme } = useTheme()
7
+
8
+ return useMemo(
9
+ () => ({
10
+ gutterFg: theme.textMuted,
11
+ gutterBg: theme.backgroundElement,
12
+ }),
13
+ [theme.textMuted, theme.backgroundElement],
14
+ )
15
+ }