Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🎉 React Functions Version #268

Open
i0 opened this issue Jan 6, 2024 · 1 comment
Open

🎉 React Functions Version #268

i0 opened this issue Jan 6, 2024 · 1 comment

Comments

@i0
Copy link

i0 commented Jan 6, 2024

Apparently this repo is no longer compatible with the new version of Ink since it is a class component.
I wrote the following (almost) equivalent react function version:

// Table.tsx
import React from 'react';
import {Box, Text} from 'ink';

type Scalar = string | number | boolean | null | undefined;

type ScalarDict = {
	[key: string]: Scalar;
};

type Column = {
	key: string;
	width: number;
};

type TableProps = {
	data: ScalarDict[];
	showHeaders?: boolean;
	headerStyles?: {
		color?: string;
		backgroundColor?: string;
		bold?: boolean;
		italic?: boolean;
		underline?: boolean;
		inverse?: boolean;
		strikethrough?: boolean;
		dimColor?: boolean;
	};
};

// Helper function to generate headers from data
function generateHeaders(data: ScalarDict[]): ScalarDict {
	let headers: ScalarDict = {};

	data.forEach(row => {
		Object.keys(row).forEach(key => {
			headers[key] = key;
		});
	});

	return headers;
}

const Table = ({data, showHeaders = true, headerStyles}: TableProps) => {
	// Determine columns and their widths
	const columns: Column[] = getColumns(data);

	return (
		<Box flexDirection="column">
			{renderHeaderSeparators(columns)}

			{showHeaders && (
				<>
					{renderRow(generateHeaders(data), columns, {
						color: 'blue',
						bold: true,
						...headerStyles,
					})}
					{renderRowSeparators(columns)}
				</>
			)}

			{data.map((row, index) => (
				<React.Fragment key={`row-${index}`}>
					{index !== 0 && renderRowSeparators(columns)}
					{renderRow(row, columns)}
				</React.Fragment>
			))}
			{renderFooterSeparators(columns)}
		</Box>
	);
};

// Helper function to determine columns and their widths
function getColumns(data: ScalarDict[]): Column[] {
	let columnWidths: {[key: string]: number} = {};

	data.forEach(row => {
		Object.keys(row).forEach(key => {
			const valueLength = row[key]?.toString().length || 0;
			columnWidths[key] = Math.max(
				columnWidths[key] || key.length,
				valueLength,
			);
		});
	});

	return Object.keys(columnWidths).map(key => ({
		key: key,
		width: (columnWidths[key] ?? 0) + 2, // adding padding
	}));
}

// Helper function to render a row with separators
function renderRow(row: ScalarDict, columns: Column[], textStyles?: any) {
	return (
		<Box flexDirection="row">
			<Text></Text>
			{columns.map((column, index) => (
				<React.Fragment key={column.key}>
					{index !== 0 && <Text></Text>}
					{/* Add separator before each cell except the first one */}
					<Box width={column.width} justifyContent="center">
						<Text {...textStyles}>{row[column.key]?.toString() || ''}</Text>
					</Box>
				</React.Fragment>
			))}
			<Text></Text>
		</Box>
	);
}

function renderHeaderSeparators(columns: Column[]) {
	return renderRowSeparators(columns, '┌', '┬', '┐');
}

function renderFooterSeparators(columns: Column[]) {
	return renderRowSeparators(columns, '└', '┴', '┘');
}

function renderRowSeparators(
	columns: Column[],
	leftChar = '├',
	midChar = '┼',
	rightChar = '┤',
) {
	return (
		<Box flexDirection="row">
			<Text>{leftChar}</Text>
			{columns.map((column, index) => (
				<React.Fragment key={column.key}>
					<Text>{'─'.repeat(column.width)}</Text>
					{index < columns.length - 1 ? (
						<Text>{midChar}</Text>
					) : (
						<Text>{rightChar}</Text>
					)}
				</React.Fragment>
			))}
		</Box>
	);
}

export default Table;

Usage:

<Table data={data} showHeaders={true} headerStyles={{color: "blue"}} />

Feel free to use it in your codes. 💫

@i0 i0 changed the title React Functions Version ⭐️ React Functions Version Jan 6, 2024
@i0 i0 changed the title ⭐️ React Functions Version 🎉 React Functions Version Jan 6, 2024
@pridyok
Copy link

pridyok commented Feb 2, 2024

This is awesome, thanks @i0!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants