diff --git a/docs/search/available-methods.md b/docs/search/available-methods.md index 1d8397a5f..422757c37 100644 --- a/docs/search/available-methods.md +++ b/docs/search/available-methods.md @@ -192,3 +192,39 @@ public function configure(): void $this->setTrimSearchStringDisabled(); } ``` + +## Search Icon + +To help customise, a "Search Input Icon" has been added, allowing for the addition of an icon to the search input field. + +At present, the Search Icon is only available as a "left aligned" icon. + +This is presently only available for Tailwind implementations + +### setSearchIcon + +This adds an Icon to the Search Input Field, which expects an icon path (e.g. heroicon-m-magnifying-glass) + +```php +public function configure(): void +{ + $this->setSearchIcon('heroicon-m-magnifying-glass'); +} +``` + +### setSearchIconAttributes + +This allows you to specify attributes for the Search Icon for the Input Field. + +Note that classes will be injected prior to styles, due to the behaviour of icons. + +```php +public function configure(): void +{ + $this->setSearchIconAttributes([ + 'class' => 'h-4 w-4', + 'style' => 'color: #000000', + ]); +} + +``` \ No newline at end of file diff --git a/resources/views/components/tools/toolbar/items/search-field.blade.php b/resources/views/components/tools/toolbar/items/search-field.blade.php index 6bc8bb9c5..a52f06427 100644 --- a/resources/views/components/tools/toolbar/items/search-field.blade.php +++ b/resources/views/components/tools/toolbar/items/search-field.blade.php @@ -3,8 +3,21 @@
$this->isBootstrap, - 'flex rounded-md shadow-sm' => $this->isTailwind, + 'rounded-md shadow-sm' => $this->isTailwind, + 'flex' => !$this->hasSearchIcon, + 'relative inline-flex flex-row' => $this->hasSearchIcon, ])> + + @if($this->hasSearchIcon) +
+ + @svg($this->getSearchIcon, $this->getSearchIconClasses, $this->getSearchIconOtherAttributes()) + +
+ @endif + getSearchOptions() }}="search" placeholder="{{ $this->getSearchPlaceholder() }}" @@ -12,11 +25,12 @@ {{ $attributes->merge($this->getSearchFieldAttributes()) ->class([ - 'block w-full rounded-md shadow-sm transition duration-150 ease-in-out sm:text-sm sm:leading-5 rounded-none rounded-l-md focus:ring-0 focus:border-gray-300' => $this->isTailwind && $this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-styling'] ?? true)), - 'block w-full rounded-md shadow-sm transition duration-150 ease-in-out sm:text-sm sm:leading-5 rounded-md focus:ring focus:ring-opacity-50' => $this->isTailwind && !$this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-styling'] ?? true)), + 'rounded-md shadow-sm transition duration-150 ease-in-out sm:text-sm sm:leading-5 rounded-none rounded-l-md focus:ring-0 focus:border-gray-300' => $this->isTailwind && $this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-styling'] ?? true)), + 'rounded-md shadow-sm transition duration-150 ease-in-out sm:text-sm sm:leading-5 rounded-md focus:ring focus:ring-opacity-50' => $this->isTailwind && !$this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-styling'] ?? true)), 'border-gray-300 dark:bg-gray-700 dark:text-white dark:border-gray-600 focus:border-gray-300' => $this->isTailwind && $this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-colors'] ?? true)), 'border-gray-300 dark:bg-gray-700 dark:text-white dark:border-gray-600 focus:border-indigo-300 focus:ring-indigo-200' => $this->isTailwind && !$this->hasSearch() && (($this->getSearchFieldAttributes()['default'] ?? true) || ($this->getSearchFieldAttributes()['default-colors'] ?? true)), - + 'block w-full' => !$this->hasSearchIcon, + 'pl-8 pr-4' => $this->hasSearchIcon, 'form-control' => $this->isBootstrap && $this->getSearchFieldAttributes()['default'] ?? true, ]) ->except(['default','default-styling','default-colors']) diff --git a/src/Traits/Configuration/SearchConfiguration.php b/src/Traits/Configuration/SearchConfiguration.php index 77590071f..2a1c6e926 100644 --- a/src/Traits/Configuration/SearchConfiguration.php +++ b/src/Traits/Configuration/SearchConfiguration.php @@ -147,20 +147,6 @@ public function setSearchLazy(): self return $this; } - public function setSearchPlaceholder(string $placeholder): self - { - $this->searchPlaceholder = $placeholder; - - return $this; - } - - public function setSearchFieldAttributes(array $attributes = []): self - { - $this->setCustomAttributes('searchFieldAttributes', array_merge(['default' => false, 'default-colors' => false, 'default-styling' => false], $attributes)); - - return $this; - } - public function setTrimSearchString(bool $status): self { $this->trimSearchString = $status; diff --git a/src/Traits/Helpers/SearchHelpers.php b/src/Traits/Helpers/SearchHelpers.php index b9637b13c..387155271 100644 --- a/src/Traits/Helpers/SearchHelpers.php +++ b/src/Traits/Helpers/SearchHelpers.php @@ -121,25 +121,6 @@ public function getSearchOptions(): string return '.live'; } - public function getSearchPlaceholder(): string - { - if ($this->hasSearchPlaceholder()) { - return $this->searchPlaceholder; - } - - return __($this->getLocalisationPath().'Search'); - } - - public function hasSearchPlaceholder(): bool - { - return $this->searchPlaceholder !== null; - } - - public function getSearchFieldAttributes(): array - { - return $this->getCustomAttributes('searchFieldAttributes', true); - } - public function shouldTrimSearchString(): bool { return $this->trimSearchString ?? false; diff --git a/src/Traits/Styling/HasSearchFieldStyling.php b/src/Traits/Styling/HasSearchFieldStyling.php new file mode 100644 index 000000000..01283773e --- /dev/null +++ b/src/Traits/Styling/HasSearchFieldStyling.php @@ -0,0 +1,11 @@ + 'h-4 w-4', 'style' => 'color: #000000']; + + #[Computed] + public function hasSearchIcon(): bool + { + return $this->searchIconSet; + } + + #[Computed] + public function getSearchIcon(): string + { + return $this->hasSearchIcon() ? $this->searchIcon : 'heroicon-m-magnifying-glass'; + } + + #[Computed] + public function getSearchIconClasses(): string + { + return $this->getSearchIconAttributes()['class']; + + } + + #[Computed] + public function getSearchIconAttributes(): array + { + return $this->searchIconAttributes; + } + + #[Computed] + public function getSearchIconOtherAttributes(): array + { + return collect($this->getSearchIconAttributes())->except('class')->toArray(); + } + + protected function setSearchIconStatus(bool $searchIconStatus): self + { + $this->searchIconSet = $searchIconStatus; + + return $this; + } + + protected function searchIconEnabled(): self + { + return $this->setSearchIconStatus(true); + } + + protected function searchIconDisabled(): self + { + return $this->setSearchIconStatus(false); + } + + protected function setSearchIcon(string $searchIcon): self + { + $this->searchIcon = $searchIcon; + + return $this->searchIconEnabled(); + } + + protected function setSearchIconAttributes(array $searchIconAttributes): self + { + $this->searchIconAttributes = array_merge($this->searchIconAttributes, $searchIconAttributes); + + return $this->searchIconEnabled(); + } +} diff --git a/src/Traits/Styling/Search/HasSearchInput.php b/src/Traits/Styling/Search/HasSearchInput.php new file mode 100644 index 000000000..f937f5ef5 --- /dev/null +++ b/src/Traits/Styling/Search/HasSearchInput.php @@ -0,0 +1,45 @@ +setCustomAttributes('searchFieldAttributes', array_merge(['default' => false, 'default-colors' => false, 'default-styling' => false], $attributes)); + + return $this; + } + + public function getSearchFieldAttributes(): array + { + return $this->getCustomAttributes('searchFieldAttributes', true); + } + + public function setSearchPlaceholder(string $placeholder): self + { + $this->searchPlaceholder = $placeholder; + + return $this; + } + + public function getSearchPlaceholder(): string + { + if ($this->hasSearchPlaceholder()) { + return $this->searchPlaceholder; + } + + return __($this->getLocalisationPath().'Search'); + } + + public function hasSearchPlaceholder(): bool + { + return $this->searchPlaceholder !== null; + } +} diff --git a/src/Traits/WithSearch.php b/src/Traits/WithSearch.php index ddfe98553..f4befabf9 100644 --- a/src/Traits/WithSearch.php +++ b/src/Traits/WithSearch.php @@ -8,20 +8,20 @@ use Rappasoft\LaravelLivewireTables\Traits\Configuration\SearchConfiguration; use Rappasoft\LaravelLivewireTables\Traits\Core\QueryStrings\HasQueryStringForSearch; use Rappasoft\LaravelLivewireTables\Traits\Helpers\SearchHelpers; +use Rappasoft\LaravelLivewireTables\Traits\Styling\HasSearchFieldStyling; trait WithSearch { use SearchConfiguration, SearchHelpers; use HasQueryStringForSearch; + use HasSearchFieldStyling; public string $search = ''; #[Locked] public bool $searchStatus = true; - protected ?string $searchPlaceholder = null; - protected bool $searchVisibilityStatus = true; protected ?bool $searchFilterBlur = null; @@ -36,8 +36,6 @@ trait WithSearch protected ?int $searchFilterThrottle = null; - protected array $searchFieldAttributes = []; - protected bool $trimSearchString = false; // TODO diff --git a/tests/Unit/Traits/Configuration/SearchConfigurationTest.php b/tests/Unit/Traits/Configuration/SearchConfigurationTest.php index 9daec3aeb..cc55f8362 100644 --- a/tests/Unit/Traits/Configuration/SearchConfigurationTest.php +++ b/tests/Unit/Traits/Configuration/SearchConfigurationTest.php @@ -3,6 +3,7 @@ namespace Rappasoft\LaravelLivewireTables\Tests\Unit\Traits\Configuration; use Rappasoft\LaravelLivewireTables\Exceptions\DataTableConfigurationException; +use Rappasoft\LaravelLivewireTables\Tests\Http\Livewire\PetsTable; use Rappasoft\LaravelLivewireTables\Tests\TestCase; final class SearchConfigurationTest extends TestCase @@ -180,11 +181,159 @@ public function test_can_set_search_placeholder(): void public function test_can_set_search_field_attributes(): void { - $this->assertSame(['default' => true, 'default-colors' => true, 'default-styling' => true], $this->basicTable->getSearchFieldAttributes()); + $mock = new class extends PetsTable + { + public ?array $testAttributesArray; - $this->basicTable->setSearchFieldAttributes(['class' => 'bg-blue', 'style' => 'font-size: 3em;']); + public function configure(): void + { + $this->setDataTableFingerprint('test'); + } - $this->assertSame(['class' => 'bg-blue', 'default' => false, 'default-colors' => false, 'default-styling' => false, 'style' => 'font-size: 3em;'], $this->basicTable->getSearchFieldAttributes()); + public function pubSetSearchFieldAttributes(array $attributes) + { + $this->setSearchFieldAttributes($attributes); + } + }; + + $mock->configure(); + $mock->boot(); + + $this->assertSame(['default' => true, 'default-colors' => true, 'default-styling' => true], $mock->getSearchFieldAttributes()); + + $mock->pubSetSearchFieldAttributes(['class' => 'bg-blue', 'style' => 'font-size: 3em;']); + + $this->assertSame(['class' => 'bg-blue', 'default' => false, 'default-colors' => false, 'default-styling' => false, 'style' => 'font-size: 3em;'], $mock->getSearchFieldAttributes()); + + } + + public function test_can_set_search_icon(): void + { + $mock = new class extends PetsTable + { + public ?array $testAttributesArray; + + public function configure(): void + { + $this->setDataTableFingerprint('test'); + } + + public function pubSetSearchFieldAttributes(array $attributes) + { + $this->setSearchFieldAttributes($attributes); + } + + public function pubSetSearchIcon(string $searchIcon) + { + $this->setSearchIcon($searchIcon); + } + + public function pubSetSearchIconAttributes(array $attributes) + { + $this->setSearchIconAttributes($attributes); + } + }; + + $mock->configure(); + $mock->boot(); + + $this->assertFalse($mock->hasSearchIcon()); + $mock->pubSetSearchIcon('heroicon-m-magnifying-glass-2'); + $this->assertTrue($mock->hasSearchIcon()); + + $this->assertSame($mock->getSearchIcon(), 'heroicon-m-magnifying-glass-2'); + + } + + public function test_can_set_search_icon_status(): void + { + $mock = new class extends PetsTable + { + public ?array $testAttributesArray; + + public function configure(): void + { + $this->setDataTableFingerprint('test'); + } + + public function pubSetSearchFieldAttributes(array $attributes) + { + $this->setSearchFieldAttributes($attributes); + } + + public function pubSetSearchIconEnabled() + { + $this->searchIconEnabled(); + } + + public function pubSetSearchIconDisabled() + { + $this->searchIconDisabled(); + } + }; + + $mock->configure(); + $mock->boot(); + + $this->assertFalse($mock->hasSearchIcon()); + $mock->pubSetSearchIconEnabled(); + + $this->assertTrue($mock->hasSearchIcon()); + $mock->pubSetSearchIconDisabled(); + $this->assertFalse($mock->hasSearchIcon()); + + } + + public function test_can_set_search_icon_attributes(): void + { + $mock = new class extends PetsTable + { + public ?array $testAttributesArray; + + public function configure(): void + { + $this->setDataTableFingerprint('test'); + + } + + public function pubSetSearchFieldAttributes(array $attributes) + { + $this->setSearchFieldAttributes($attributes); + } + + public function pubSetSearchIcon(string $searchIcon) + { + $this->setSearchIcon($searchIcon); + } + + public function pubSetSearchIconAttributes(array $attributes) + { + $this->setSearchIconAttributes($attributes); + } + }; + + $mock->configure(); + $mock->boot(); + + $this->assertSame('h-4 w-4', $mock->getSearchIconClasses()); + $this->assertSame([ + 'style' => 'color: #000000', + ], $mock->getSearchIconOtherAttributes()); + + $mock->pubSetSearchIconAttributes([ + 'style' => 'color: #FF0000', + 'class' => 'h-6 w-6', + ]); + + $this->assertSame('h-6 w-6', $mock->getSearchIconClasses()); + $this->assertSame([ + 'style' => 'color: #FF0000', + ], $mock->getSearchIconOtherAttributes()); + + $this->assertSame([ + 'class' => 'h-6 w-6', + 'style' => 'color: #FF0000', + ], $mock->getSearchIconAttributes()); } }