Table renderer
butschster opened this issue · 1 comments
butschster commented
It would be great to render tables from HTML
Something like this
<table style="box">
<thead>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</thead>
<tbody>
<tr>
<td><div class="width-5 px-4">4</div></td>
<td rowspan="2">9</td>
<td>6</td>
</tr>
<tr>
<td class="width-10">7</td>
<td colspan="2"><div>4</div></td>
</tr>
</tbody>
</table>
To this
┌───────────────┬───┬───┐
│ 1 │ 2 │ 3 │
├───────────────┼───┼───┤
│ 4 │ 9 │ 6 │
│ 7 │ │ 4 │
└───────────────┴───┴───┘
I scetched a concept of TableRenderer
<?php
declare(strict_types=1);
namespace Termwind\Html;
use DOMNode;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Helper\TableCell;
use Symfony\Component\Console\Output\BufferedOutput;
use Termwind\Components\Element;
use Termwind\HtmlRenderer;
use function Termwind\div;
final class TableRenderer
{
private Table $table;
private BufferedOutput $output;
private string $styles;
public function __construct(DOMNode $node)
{
$this->output = new BufferedOutput();
$this->table = new Table($this->output);
$style = $node->getAttribute('style');
$this->styles = $node->getAttribute('class');
if (!empty($style)) {
$this->table->setStyle($style);
}
$this->convert($node);
}
private function convert(DOMNode $node)
{
foreach ($node->childNodes as $child) {
if ($child->nodeName === 'thead') {
$this->parseHeader($child);
}
if ($child->nodeName === 'tbody') {
$this->parseBody($child);
}
if ($child->nodeName === 'tr') {
foreach ($this->parseRow($child) as $row) {
$this->table->addRow($row);
}
}
}
}
private function parseHeader(DOMNode $node)
{
foreach ($node->childNodes as $child) {
if ($child->nodeName === 'tr') {
foreach ($this->parseRow($child) as $row) {
$this->table->setHeaders($row);
}
}
}
}
private function parseBody(DOMNode $node)
{
foreach ($node->childNodes as $child) {
if ($child->nodeName === 'tr') {
foreach ($this->parseRow($child) as $row) {
$this->table->addRow($row);
}
}
}
}
private function parseRow(DOMNode $node): \Iterator
{
$row = [];
foreach ($node->childNodes as $child) {
if ($child->nodeName === 'th' || $child->nodeName === 'td') {
$row[] = new TableCell(
(string)(new HtmlRenderer())->parse($child->ownerDocument->saveXML($child)),
[
'colspan' => max((int)$child->getAttribute('colspan'), 1),
'rowspan' => max((int)$child->getAttribute('rowspan'), 1),
]
);
}
}
if ($row !== []) {
yield $row;
}
}
public function render(): Element
{
$this->table->render();
return div($this->output->fetch(), $this->styles);
}
}
And changes for HtmlRenderer
...
/**
* Convert a tree of DOM nodes to a tree of termwind elements.
*/
private function convert(DOMNode $node): Components\Element|string
{
...
if ($node->nodeName === 'table') {
return (new TableRenderer($node))->render();
}
...
}
...
I hope my sketch will be a good starting point for better solution with ability to use background colors and text colors in a table cell.
Thank you for an amazing package. I want to use it in my project, but I need tables as well.
nunomaduro commented
Feel free to make a pull request with your proposal, and a screenshot of what's the "actual" render on the console.