From 1f81ce361cb454b1655d6e2a7ac031bc1e3b2ede Mon Sep 17 00:00:00 2001
From: Sam Light <samlight1994@gmail.com>
Date: Thu, 27 Mar 2025 10:53:34 +0000
Subject: Seperating toolbar into its own class and views

---
 src/Columns/Column.php       | 19 +++++-----
 src/TableComponent.php       | 78 ++++++++++++++++++++++++---------------
 src/Toolbar.php              | 88 ++++++++++++++++++++++++++++++++++++++++++++
 src/Toolbar/ColumnSelect.php | 17 +++++++++
 src/Toolbar/Filter.php       |  8 ++++
 src/Toolbar/Item.php         | 32 ++++++++++++++++
 src/Toolbar/PageSize.php     | 19 ++++++++++
 src/Toolbar/Search.php       | 25 +++++++++++++
 8 files changed, 248 insertions(+), 38 deletions(-)
 create mode 100644 src/Toolbar.php
 create mode 100644 src/Toolbar/ColumnSelect.php
 create mode 100644 src/Toolbar/Filter.php
 create mode 100644 src/Toolbar/Item.php
 create mode 100644 src/Toolbar/PageSize.php
 create mode 100644 src/Toolbar/Search.php

(limited to 'src')

diff --git a/src/Columns/Column.php b/src/Columns/Column.php
index 94e386f..895708f 100644
--- a/src/Columns/Column.php
+++ b/src/Columns/Column.php
@@ -28,24 +28,24 @@ class Column {
         $this->showInSelect = $this->title !== null;
     }
 
-    public static function make(string $name, ?string $title = null) : static
+    public static function make(string $name, ?string $title = null): static
     {
         return new static($name, $title);
     }
 
-    public function setTable(TableComponent $table) : void
+    public function setTable(TableComponent $table): void
     {
         $this->table = $table;
     }
 
-    public function getTitle()
+    public function getTitle(): string
     {
         return $this->title;
     }
 
-    private function defaultSlot(Model $row)
+    private function defaultSlot(Model $row): string
     {
-        return $row->{$this->name};
+        return (string) $row->{$this->name};
     }
 
     public function slot(callable $fn) : static
@@ -77,22 +77,23 @@ class Column {
         return $this;
     }
 
-    public function showInSelect($show = true)
+    public function showInSelect($show = true): static
     {
         $this->showInSelect = $show;
+        return $this;
     }
 
-    public function getShowInSelect()
+    public function getShowInSelect(): bool
     {
         return $this->showInSelect;
     }
 
-    protected function getContent(Model $row)
+    protected function getContent(Model $row): string
     {
         return $this->slotFn?->call($this, $row, $this) ?? $this->defaultSlot($row);
     }
 
-    public function view(Model $row)
+    public function view(Model $row): HtmlString
     {
         $attributes = $this->tdAttributesFn?->call($this, $row) ?? [];
         $attributes = (new ComponentAttributeBag($attributes))->toHtml();
diff --git a/src/TableComponent.php b/src/TableComponent.php
index b8fae6a..0a55d5e 100644
--- a/src/TableComponent.php
+++ b/src/TableComponent.php
@@ -9,6 +9,7 @@ use Livewire\Attributes\Url;
 use Illuminate\Pagination\Paginator;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Support\Str;
+use Illuminate\Support\Collection;
 
 use Exception;
 
@@ -18,35 +19,65 @@ abstract class TableComponent extends Component
 
     // Config
     protected $paginationTheme = 'bootstrap';
-    protected bool $searchable = true;
-    protected int $searchMinLength = 2;
-    protected int $searchDebounce = 250;
-    protected bool $showPageSizeSelect = true;
-    protected bool $showColumnSelect = true;
-
-    protected array $pageSizes = [10, 25, 50];
-
     protected $model = null;
+    protected int $defaultPageSize = 10;
 
     // Properties
+    #[Url]
     public string $search = '';
 
     #[Url]
-    public int $pageSize = 0;
+    public int $pageSize;
     public array $activeColumns = [];
 
-    public function __construct()
+    public function mount()
     {
-        $this->pageSize = $this->pageSizes[0] ?? 0;
+        $this->setDefaultActiveColumns();
+        $this->setDefaultPageSize();
     }
 
-    public function mount()
+    protected function setDefaultPageSize(): void
+    {
+        if (!isset($this->pageSize)) {
+            $this->pageSize = $this->defaultPageSize;
+        }
+    }
+
+    protected function setDefaultActiveColumns(): void
     {
         foreach($this->getColumns() as $column) {
             $this->activeColumns[] = $column->name;
         }
     }
 
+    protected function isSearching(): bool
+    {
+        $search = $this->getToolbar()->getSearch();
+        return $search !== null && Str::length($this->search) >= $search->getMinLength();
+    }
+
+    public function updatedSearch(): void
+    {
+        if ($this->isSearching()) {
+            $this->resetPage();
+        }
+    }
+
+    protected function toolbar(): ?Toolbar
+    {
+        return null;
+    }
+
+    private ?Toolbar $toolbarCache;
+
+    protected function getToolbar(): ?Toolbar
+    {
+        if (!isset($this->_toolbar)) {
+            $this->toolbar = $this->toolbar();
+        }
+        return $this->toolbar;
+    }
+
     protected function query() : Builder
     {
         if($this->model === null) {
@@ -60,25 +91,19 @@ abstract class TableComponent extends Component
 
     protected function search(Builder $builder, string $search) : void {}
 
-    protected function filters() : array
-    {
-        return [];
-    }
-
     protected function buildQuery() : Builder
     {
         $query = $this->query();
 
-        if($this->searchable && (Str::length($this->search) >= $this->searchMinLength)) {
+        if ($this->isSearching()) {
             $this->search($query, $this->search);
         }
 
         return $query;
     }
 
-    private $columnsCache = null;
-
-    protected function getColumns()
+    private ?Collection $columnsCache = null;
+    public function getColumns()
     {
         if($this->columnsCache === null) {
             $this->columnsCache = collect($this->columns())->each(
@@ -94,17 +119,12 @@ abstract class TableComponent extends Component
         $data = $this->buildQuery()->paginate($this->pageSize);
         $allColumns = $this->getColumns();
         $columns = $allColumns->filter(fn($c) => in_array($c->name,$this->activeColumns));
+        $toolbar = $this->toolbar();
 
         Paginator::defaultView('laralight-tables::pagination');
 
-        return view('laralight-tables::table', [
-            'searchable' => $this->searchable,
-            'searchDebounce' => $this->searchDebounce,
-            'showPageSizeSelect' => $this->showPageSizeSelect,
-            'showColumnSelect' => $this->showColumnSelect,
-            'pageSizes' => $this->pageSizes,
-        ] + compact(
-            'data', 'allColumns', 'columns'
+        return view('laralight-tables::table', compact(
+            'data', 'allColumns', 'columns', 'toolbar',
         ));
     }
 }
diff --git a/src/Toolbar.php b/src/Toolbar.php
new file mode 100644
index 0000000..2db39f5
--- /dev/null
+++ b/src/Toolbar.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Lightscale\LaralightTables;
+
+use Lightscale\LaralightTables\Toolbar\Item as ToolbarItem;
+use Lightscale\LaralightTables\Toolbar\Search as SearchItem;
+use Lightscale\LaralightTables\Toolbar\PageSize as PageSizeItem;
+use Lightscale\LaralightTables\Toolbar\Filter as FitlerItem;
+
+use Illuminate\View\View;
+use Illuminate\Support\Collection;
+
+class Toolbar
+{
+    protected ?SearchItem $searchItem = null;
+    protected ?PageSizeItem $pageSizeItem = null;
+
+    protected Collection $startItems;
+    protected Collection $midItems;
+    protected Collection $endItems;
+
+    public function __construct(
+        private TableComponent $table
+    )
+    {
+        $this->startItems = collect();
+        $this->midItems = collect();
+        $this->endItems = collect();
+    }
+
+    private function addItem(Collection $list, ToolbarItem $item): static
+    {
+        $item->setToolbar($this);
+
+        if ($item instanceof FilterItem) {
+            $this->filterItems->push($item);
+        }
+        else if ($item instanceof PageSizeItem) {
+            $this->pageSizeItem = $item;
+        }
+        else if ($item instanceof SearchItem) {
+            $this->searchItem = $item;
+        }
+
+        $list->push($item);
+        return $this;
+    }
+
+    public function addStartItem(ToolbarItem $item): static
+    {
+        return $this->addItem($this->startItems, $item);
+    }
+
+    public function addMidItem(ToolbarItem $item): static
+    {
+        return $this->addItem($this->midItems, $item);
+    }
+
+    public function addEndItem(ToolbarItem $item): static
+    {
+        return $this->addItem($this->endItems, $item);
+    }
+
+    public function getTable(): TableComponent
+    {
+        return $this->table;
+    }
+
+    public function getSearch(): ?SearchItem
+    {
+        return $this->searchItem;
+    }
+
+    public function getPageSize(): ?PageSizeItem
+    {
+        return $this->pageSizeItem;
+    }
+
+    public function render(): View
+    {
+        return view('laralight-tables::toolbar', [
+            'startItems' => $this->startItems,
+            'midItems' => $this->midItems,
+            'endItems' => $this->endItems,
+        ]);
+    }
+
+}
diff --git a/src/Toolbar/ColumnSelect.php b/src/Toolbar/ColumnSelect.php
new file mode 100644
index 0000000..a70c49a
--- /dev/null
+++ b/src/Toolbar/ColumnSelect.php
@@ -0,0 +1,17 @@
+<?php
+
+namespace Lightscale\LaralightTables\Toolbar;
+
+use Illuminate\View\View;
+
+class ColumnSelect extends Item
+{
+    public function __construct() {}
+
+    public function render(): View
+    {
+        return view('laralight-tables::toolbar.column-select', [
+            'allColumns' => $this->getTable()->getColumns()
+        ]);
+    }
+}
diff --git a/src/Toolbar/Filter.php b/src/Toolbar/Filter.php
new file mode 100644
index 0000000..ebda2c6
--- /dev/null
+++ b/src/Toolbar/Filter.php
@@ -0,0 +1,8 @@
+<?php
+
+namespace Lightscale\LaralightTables\Toolbar;
+
+abstract class Filter extends Item
+{
+
+}
diff --git a/src/Toolbar/Item.php b/src/Toolbar/Item.php
new file mode 100644
index 0000000..168f877
--- /dev/null
+++ b/src/Toolbar/Item.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Lightscale\LaralightTables\Toolbar;
+
+use Lightscale\LaralightTables\TableComponent;
+use Lightscale\LaralightTables\Toolbar;
+
+use Illuminate\View\View;
+use Illuminate\Support\HtmlString;
+
+abstract class Item
+{
+    private Toolbar $toolbar;
+
+    public function setToolbar(Toolbar $toolbar): void
+    {
+        $this->toolbar = $toolbar;
+    }
+
+    public function getToolbar(): Toolbar
+    {
+        return $this->toolbar;
+    }
+
+    public function getTable(): TableComponent
+    {
+        return $this->getToolbar()->getTable();
+    }
+
+    abstract public function render(): View|HtmlString|string|null;
+
+}
diff --git a/src/Toolbar/PageSize.php b/src/Toolbar/PageSize.php
new file mode 100644
index 0000000..9c2821a
--- /dev/null
+++ b/src/Toolbar/PageSize.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Lightscale\LaralightTables\Toolbar;
+
+use Illuminate\View\View;
+
+class PageSize extends Item
+{
+    public function __construct(
+        private array $pageSizes = [10, 25, 50],
+    ) {}
+
+    public function render(): View
+    {
+        return view('laralight-tables::toolbar.page-size', [
+            'pageSizes' => $this->pageSizes,
+        ]);
+    }
+}
diff --git a/src/Toolbar/Search.php b/src/Toolbar/Search.php
new file mode 100644
index 0000000..0b0dc37
--- /dev/null
+++ b/src/Toolbar/Search.php
@@ -0,0 +1,25 @@
+<?php
+
+namespace Lightscale\LaralightTables\Toolbar;
+
+use Illuminate\View\View;
+
+class Search extends Item
+{
+    public function __construct(
+        protected int $debounce = 250,
+        protected int $minLength = 2,
+    ) {}
+
+    public function getMinLength(): int
+    {
+        return $this->minLength;
+    }
+
+    public function render(): View
+    {
+        return view('laralight-tables::toolbar.search', [
+            'debounce' => $this->debounce,
+        ]);
+    }
+}
-- 
cgit v1.2.3