11// via https://github.com/maticzav/ink-table
2- // inlined here because of https://github.com/maticzav/ink-table/issues/258
2+ // patched: max column width 20 + auto-wrap long values
33
44import React from "react" ;
55import { Box , Text } from "ink" ;
@@ -40,6 +40,7 @@ export type TableProps<T extends ScalarDict> = {
4040 * Component used to render the skeleton of the table.
4141 */
4242 skeleton : ( props : React . PropsWithChildren < unknown > ) => React . JSX . Element ;
43+ maxCellWidth : number ;
4344} ;
4445
4546/* Table */
@@ -60,6 +61,7 @@ export default class Table<T extends ScalarDict> extends React.Component<
6061 header : this . props . header || Header ,
6162 cell : this . props . cell || Cell ,
6263 skeleton : this . props . skeleton || Skeleton ,
64+ maxCellWidth : this . props . maxCellWidth || 40 ,
6365 } ;
6466 }
6567
@@ -86,19 +88,21 @@ export default class Table<T extends ScalarDict> extends React.Component<
8688 * Returns a list of column names and their widths.
8789 */
8890 getColumns ( ) : Column < T > [ ] {
89- const { columns, padding } = this . getConfig ( ) ;
91+ const { columns, padding, maxCellWidth } = this . getConfig ( ) ;
9092
9193 const widths : Column < T > [ ] = columns . map ( ( key ) => {
9294 const header = String ( key ) . length ;
9395 /* Get the width of each cell in the column */
9496 const data = this . props . data . map ( ( data ) => {
9597 const value = data [ key ] ;
96-
9798 if ( value == undefined || value == null ) return 0 ;
9899 return String ( value ) . length ;
99100 } ) ;
100101
101- const width = Math . max ( ...data , header ) + padding * 2 ;
102+ let width = Math . max ( ...data , header ) + padding * 2 ;
103+
104+ // enforce max width
105+ width = Math . min ( width , maxCellWidth ) ;
102106
103107 /* Construct a cell */
104108 return {
@@ -272,65 +276,81 @@ type Column<T> = {
272276 width : number ;
273277} ;
274278
279+ /**
280+ * Word-wrap utility: splits text into chunks of max length
281+ */
282+ function wrapText ( str : string , max : number ) : string [ ] {
283+ const result : string [ ] = [ ] ;
284+ let i = 0 ;
285+ while ( i < str . length ) {
286+ result . push ( str . slice ( i , i + max ) ) ;
287+ i += max ;
288+ }
289+ return result . length ? result : [ "" ] ;
290+ }
291+
275292/**
276293 * Constructs a Row element from the configuration.
277294 */
278295function row < T extends ScalarDict > (
279296 config : RowConfig ,
280297) : ( props : RowProps < T > ) => React . JSX . Element {
281298 /* This is a component builder. We return a function. */
282-
283299 const skeleton = config . skeleton ;
284300
285301 /* Row */
286- return ( props ) => (
287- < Box flexDirection = "row" >
288- { /* Left */ }
289- < skeleton . component > { skeleton . left } </ skeleton . component >
290- { /* Data */ }
291- { ...intersperse (
292- ( i ) => {
293- const key = `${ props . key } -hseparator-${ i } ` ;
294-
295- // The horizontal separator.
296- return (
297- < skeleton . component key = { key } > { skeleton . cross } </ skeleton . component >
298- ) ;
299- } ,
300-
301- // Values.
302- props . columns . map ( ( column , colI ) => {
303- // content
304- const value = props . data [ column . column ] ;
305-
306- if ( value == undefined || value == null ) {
307- const key = `${ props . key } -empty-${ column . key } ` ;
308-
309- return (
310- < config . cell key = { key } column = { colI } >
311- { skeleton . line . repeat ( column . width ) }
312- </ config . cell >
313- ) ;
314- } else {
315- const key = `${ props . key } -cell-${ column . key } ` ;
316-
317- // margins
318- const ml = config . padding ;
319- const mr = column . width - String ( value ) . length - config . padding ;
320-
321- return (
322- /* prettier-ignore */
323- < config . cell key = { key } column = { colI } >
324- { `${ skeleton . line . repeat ( ml ) } ${ String ( value ) } ${ skeleton . line . repeat ( mr ) } ` }
325- </ config . cell >
326- ) ;
327- }
328- } ) ,
329- ) }
330- { /* Right */ }
331- < skeleton . component > { skeleton . right } </ skeleton . component >
332- </ Box >
333- ) ;
302+ return ( props ) => {
303+ // compute wrapped values for each column
304+ const wrappedColumns = props . columns . map ( ( column ) => {
305+ const rawValue = props . data [ column . column ] ;
306+ const contentMax = column . width - config . padding * 2 ;
307+ const displayValue = rawValue == null ? "" : String ( rawValue ) ;
308+ return wrapText ( displayValue , Math . max ( contentMax , 1 ) ) ;
309+ } ) ;
310+
311+ // figure out max number of lines for this row
312+ const maxLines = Math . max ( ...wrappedColumns . map ( ( c ) => c . length ) , 1 ) ;
313+
314+ return (
315+ < Box flexDirection = "column" >
316+ { Array . from ( { length : maxLines } ) . map ( ( _ , lineIndex ) => (
317+ < Box key = { `${ props . key } -line-${ lineIndex } ` } flexDirection = "row" >
318+ { /* Left */ }
319+ < skeleton . component > { skeleton . left } </ skeleton . component >
320+ { /* Data */ }
321+ { intersperse (
322+ ( i ) => (
323+ < skeleton . component
324+ key = { `${ props . key } -hseparator-${ i } -line-${ lineIndex } ` }
325+ >
326+ { skeleton . cross }
327+ </ skeleton . component >
328+ ) ,
329+ props . columns . map ( ( column , colI ) => {
330+ const lines = wrappedColumns [ colI ] || [ ] ;
331+ const content = lines [ lineIndex ] ?? "" ; // empty if no line
332+ const ml = config . padding ;
333+ const mr = column . width - content . length - config . padding ;
334+
335+ return (
336+ < config . cell
337+ key = { `${ props . key } -cell-${ column . key } -${ lineIndex } ` }
338+ column = { colI }
339+ >
340+ { `${ skeleton . line . repeat ( ml ) } ${ content } ${ skeleton . line . repeat (
341+ Math . max ( mr , 0 ) ,
342+ ) } `}
343+ </ config . cell >
344+ ) ;
345+ } ) ,
346+ ) }
347+ { /* Right */ }
348+ < skeleton . component > { skeleton . right } </ skeleton . component >
349+ </ Box >
350+ ) ) }
351+ </ Box >
352+ ) ;
353+ } ;
334354}
335355
336356/**
@@ -352,7 +372,7 @@ export function Cell(props: CellProps) {
352372}
353373
354374/**
355- * Redners the scaffold of the table.
375+ * Renders the scaffold of the table.
356376 */
357377export function Skeleton ( props : React . PropsWithChildren < unknown > ) {
358378 return < Text bold > { props . children } </ Text > ;
0 commit comments