Skip to content

Commit fb3dade

Browse files
authored
Add Wrapper Options to ArrayColumn (#2255)
* Add Wrapper Options to FlexCol * Fix styling * Moving getContents Back * Fix styling * Add Docs * Add Wrapper Manual Tests * Fix styling * Update to test separator * Fix styling
1 parent c6dc6d8 commit fb3dade

File tree

5 files changed

+196
-3
lines changed

5 files changed

+196
-3
lines changed

docs/column-types/array_column.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,64 @@ ArrayColumn::make('notes', 'name')
1313
->sortable(),
1414
```
1515

16-
### Empty Value
16+
## Empty Value
1717
You may define the default/empty value using the "emptyValue" method
1818

1919
```php
2020
ArrayColumn::make('notes', 'name')
2121
->emptyValue('Unknown'),
2222
```
2323

24+
## Wrapping the Output
25+
26+
As the ArrayColumn is designed to handle multiple related records, you can choose to wrap these for improved UX.
27+
28+
It is recommended that you utilise the built-in flexCol or flexRow approaches, which will also disable the separator
29+
30+
### flexCol
31+
This adds either:
32+
- Tailwind: 'flex flex-col'
33+
- Bootstrap: 'd-flex d-flex-col'
34+
35+
And merges any attributes specified in the sole parameter (as an array)
36+
```php
37+
ArrayColumn::make('notes', 'name')
38+
->data(fn($value, $row) => ($row->notes))
39+
->outputFormat(fn($index, $value) => "<a href='".$value->id."'>".$value->name."</a>")
40+
->flexCol(['class' => 'bg-red-500'])
41+
->sortable(),
42+
```
43+
44+
### flexRow
45+
46+
This adds either:
47+
- Tailwind: 'flex flex-row'
48+
- Bootstrap: 'd-flex d-flex-row'
49+
50+
And merges any attributes specified in the sole parameter (as an array)
51+
```php
52+
ArrayColumn::make('notes', 'name')
53+
->data(fn($value, $row) => ($row->notes))
54+
->outputFormat(fn($index, $value) => "<a href='".$value->id."'>".$value->name."</a>")
55+
->flexRow(['class' => 'bg-red-500'])
56+
->sortable(),
57+
```
58+
59+
### Manually
60+
61+
You can also specify a wrapperStart and wrapperEnd, for example, for an unordered list:
62+
63+
```php
64+
ArrayColumn::make('notes', 'name')
65+
->data(fn($value, $row) => ($row->notes))
66+
->outputFormat(fn($index, $value) => "<li><a href='".$value->id."'>".$value->name."</a></li>")
67+
->wrapperStart("<ul class='bg-blue'>")
68+
->wrapperEnd("</ul>")
69+
->sortable(),
70+
```
71+
72+
## See Also
73+
2474
Please also see the following for other available methods:
2575
<ul>
2676
<li>

src/Views/Columns/ArrayColumn.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class ArrayColumn extends Column
2424

2525
protected mixed $outputFormat = null;
2626

27+
public ?string $outputWrapperStart = null;
28+
29+
public ?string $outputWrapperEnd = null;
30+
2731
public function __construct(string $title, ?string $from = null)
2832
{
2933
parent::__construct($title, $from);
@@ -49,6 +53,12 @@ public function getContents(Model $row): null|string|\BackedEnum|HtmlString|Data
4953
$outputValues[] = call_user_func($this->getOutputFormatCallback(), $i, $v);
5054
}
5155

52-
return new HtmlString((! empty($outputValues) ? implode($this->getSeparator(), $outputValues) : $this->getEmptyValue()));
56+
$returnedValue = (! empty($outputValues) ? implode($this->getSeparator(), $outputValues) : $this->getEmptyValue());
57+
58+
if ($this->hasOutputWrapperStart() && $this->hasOutputWrapperEnd()) {
59+
$returnedValue = $this->getOutputWrapperStart().$returnedValue.$this->getOutputWrapperEnd();
60+
}
61+
62+
return new HtmlString($returnedValue);
5363
}
5464
}

src/Views/Columns/Traits/Configuration/ArrayColumnConfiguration.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace Rappasoft\LaravelLivewireTables\Views\Columns\Traits\Configuration;
44

5+
use Illuminate\View\ComponentAttributeBag;
6+
57
trait ArrayColumnConfiguration
68
{
79
public function separator(string $value): self
@@ -34,4 +36,46 @@ public function emptyValue(string $emptyValue): self
3436

3537
return $this;
3638
}
39+
40+
public function wrapperStart(string $value): self
41+
{
42+
$this->outputWrapperStart = $value;
43+
44+
return $this;
45+
}
46+
47+
public function wrapperEnd(string $value): self
48+
{
49+
$this->outputWrapperEnd = $value;
50+
51+
return $this;
52+
}
53+
54+
/**
55+
* Setup Flex Col Behaviour
56+
*
57+
* @param array<mixed> $attribs
58+
*/
59+
public function flexCol(array $attribs = []): self
60+
{
61+
$bag = new ComponentAttributeBag(['class' => $this->isTailwind() ? 'flex flex-col' : 'd-flex d-flex-col']);
62+
63+
return $this->wrapperStart('<div '.$bag->merge($attribs).'>')
64+
->wrapperEnd('</div>')
65+
->separator('');
66+
}
67+
68+
/**
69+
* Setup Flex Row Behaviour
70+
*
71+
* @param array<mixed> $attribs
72+
*/
73+
public function flexRow(array $attribs = []): self
74+
{
75+
$bag = new ComponentAttributeBag(['class' => $this->isTailwind() ? 'flex flex-row' : 'd-flex d-flex-row']);
76+
77+
return $this->wrapperStart('<div '.$bag->merge($attribs).'>')
78+
->wrapperEnd('</div>')
79+
->separator('');
80+
}
3781
}

src/Views/Columns/Traits/Helpers/ArrayColumnHelpers.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,24 @@ public function getOutputFormatCallback(): ?callable
3838
{
3939
return $this->outputFormat;
4040
}
41+
42+
public function hasOutputWrapperStart(): bool
43+
{
44+
return $this->outputWrapperStart !== null && is_string($this->outputWrapperStart);
45+
}
46+
47+
public function getOutputWrapperStart(): string
48+
{
49+
return $this->outputWrapperStart;
50+
}
51+
52+
public function hasOutputWrapperEnd(): bool
53+
{
54+
return $this->outputWrapperEnd !== null && is_string($this->outputWrapperEnd);
55+
}
56+
57+
public function getOutputWrapperEnd(): string
58+
{
59+
return $this->outputWrapperEnd;
60+
}
4161
}

tests/Unit/Views/Columns/ArrayColumnTest.php

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
use PHPUnit\Framework\Attributes\Group;
66
use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException;
7-
use Rappasoft\LaravelLivewireTables\Tests\Models\Pet;
7+
use Rappasoft\LaravelLivewireTables\Tests\Models\{Pet,Veterinary};
88
use Rappasoft\LaravelLivewireTables\Views\Columns\ArrayColumn;
99

1010
#[Group('Columns')]
@@ -80,4 +80,73 @@ public function test_can_get_empty_value(): void
8080
$this->assertSame('Unknown', self::$columnInstance->getEmptyValue());
8181

8282
}
83+
84+
public function test_can_use_wrapper(): void
85+
{
86+
self::$columnInstance
87+
->data(fn ($value, $row) => ($row->pets))
88+
->outputFormat(fn ($index, $value) => '<a href="'.$value->id.'">'.$value->name.'</a>')
89+
->wrapperStart('<div class="start-of-wrapper">')
90+
->wrapperEnd('</div>');
91+
92+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
93+
$this->assertSame('<div class="start-of-wrapper"><a href="1">Cartman</a><br /><a href="2">Tux</a></div>', $contents->toHtml());
94+
}
95+
96+
public function test_can_use_wrapper_ul(): void
97+
{
98+
self::$columnInstance
99+
->data(fn ($value, $row) => ($row->pets))
100+
->outputFormat(fn ($index, $value) => '<li><a href="'.$value->id.'">'.$value->name.'</a></li>')
101+
->separator('')
102+
->wrapperStart('<ul class="start-of-wrapper">')
103+
->wrapperEnd('</ul>');
104+
105+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
106+
$this->assertSame('<ul class="start-of-wrapper"><li><a href="1">Cartman</a></li><li><a href="2">Tux</a></li></ul>', $contents->toHtml());
107+
}
108+
109+
public function test_can_use_flexcol(): void
110+
{
111+
self::$columnInstance
112+
->data(fn ($value, $row) => ($row->pets))
113+
->outputFormat(fn ($index, $value) => '<a href="'.$value->id.'">'.$value->name.'</a>')
114+
->flexCol();
115+
116+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
117+
$this->assertSame('<div class="flex flex-col"><a href="1">Cartman</a><a href="2">Tux</a></div>', $contents->toHtml());
118+
}
119+
120+
public function test_can_use_flexcol_with_attributes(): void
121+
{
122+
self::$columnInstance
123+
->data(fn ($value, $row) => ($row->pets))
124+
->outputFormat(fn ($index, $value) => '<a href="'.$value->id.'">'.$value->name.'</a>')
125+
->flexCol(['class' => 'bg-red-500']);
126+
127+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
128+
$this->assertSame('<div class="bg-red-500 flex flex-col"><a href="1">Cartman</a><a href="2">Tux</a></div>', $contents->toHtml());
129+
}
130+
131+
public function test_can_use_flexrow(): void
132+
{
133+
self::$columnInstance
134+
->data(fn ($value, $row) => ($row->pets))
135+
->outputFormat(fn ($index, $value) => '<a href="'.$value->id.'">'.$value->name.'</a>')
136+
->flexRow();
137+
138+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
139+
$this->assertSame('<div class="flex flex-row"><a href="1">Cartman</a><a href="2">Tux</a></div>', $contents->toHtml());
140+
}
141+
142+
public function test_can_use_flexrow_with_attributes(): void
143+
{
144+
self::$columnInstance
145+
->data(fn ($value, $row) => ($row->pets))
146+
->outputFormat(fn ($index, $value) => '<a href="'.$value->id.'">'.$value->name.'</a>')
147+
->flexRow(['class' => 'bg-blue-500']);
148+
149+
$contents = self::$columnInstance->getContents(Veterinary::find(1));
150+
$this->assertSame('<div class="bg-blue-500 flex flex-row"><a href="1">Cartman</a><a href="2">Tux</a></div>', $contents->toHtml());
151+
}
83152
}

0 commit comments

Comments
 (0)