mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Merge pull request #17160 from filamentphp/v4-Add-filter-indicator-renderhook
V4 add filter indicator renderhook
This commit is contained in:
@@ -132,6 +132,7 @@ All these render hooks [can be scoped](#scoping-render-hooks) to any table Livew
|
||||
use Filament\Tables\View\TablesRenderHook;
|
||||
```
|
||||
|
||||
- `TablesRenderHook::FILTER_INDICATORS` - Replace the existing filter indicators, receives `filterIndicators` data as `array<Filament\Tables\Filters\Indicator>`
|
||||
- `TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER` - After the "select all" and "deselect all" action buttons in the selection indicator bar
|
||||
- `TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE` - Before the "select all" and "deselect all" action buttons in the selection indicator bar
|
||||
- `TablesRenderHook::HEADER_AFTER` - After the header container
|
||||
@@ -220,6 +221,20 @@ FilamentView::registerRenderHook(
|
||||
);
|
||||
```
|
||||
|
||||
## Passing data to render hooks
|
||||
|
||||
Render hooks can receive "data" from when the hook is rendered. To access data from a render hook, you can inject it using an `array $data` parameter to the hook's rendering function:
|
||||
|
||||
```php
|
||||
use Filament\Support\Facades\FilamentView;
|
||||
use Filament\Tables\View\TablesRenderHook;
|
||||
|
||||
FilamentView::registerRenderHook(
|
||||
TablesRenderHook::FILTER_INDICATORS,
|
||||
fn (array $data): View => view('filter-indicators', ['indicators' => $data['filterIndicators']]),
|
||||
);
|
||||
```
|
||||
|
||||
## Rendering hooks
|
||||
|
||||
Plugin developers might find it useful to expose render hooks to their users. You do not need to register them anywhere, simply output them in Blade like so:
|
||||
@@ -228,7 +243,7 @@ Plugin developers might find it useful to expose render hooks to their users. Yo
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START) }}
|
||||
```
|
||||
|
||||
To provide scope your render hook, you can pass it as the second argument to `renderHook()`. For instance, if your hook is inside a Livewire component, you can pass the class of the component using `static::class`:
|
||||
To provide [scope](#scoping-render-hooks) your render hook, you can pass it as the second argument to `renderHook()`. For instance, if your hook is inside a Livewire component, you can pass the class of the component using `static::class`:
|
||||
|
||||
```blade
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START, scopes: $this->getRenderHookScopes()) }}
|
||||
@@ -239,3 +254,9 @@ You can even pass multiple scopes as an array, and all render hooks that match a
|
||||
```blade
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\View\PanelsRenderHook::PAGE_START, scopes: [static::class, \App\Filament\Resources\Users\UserResource::class]) }}
|
||||
```
|
||||
|
||||
You can pass [data](#passing-data-to-render-hooks) to a render hook using a `data` argument to the `renderHook()` function:
|
||||
|
||||
```blade
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::FILTER_INDICATORS, data: ['filterIndicators' => $filterIndicators]) }}
|
||||
```
|
||||
|
||||
@@ -41,14 +41,15 @@ class ViewManager
|
||||
|
||||
/**
|
||||
* @param string | array<string> | null $scopes
|
||||
* @param array<string, mixed> $data
|
||||
*/
|
||||
public function renderHook(string $name, string | array | null $scopes = null): Htmlable
|
||||
public function renderHook(string $name, string | array | null $scopes = null, array $data = []): Htmlable
|
||||
{
|
||||
$renderedHooks = [];
|
||||
|
||||
$scopes = Arr::wrap($scopes);
|
||||
|
||||
$renderHook = function (callable $hook) use (&$renderedHooks, $scopes): ?string {
|
||||
$renderHook = function (callable $hook) use (&$renderedHooks, $scopes, $data): ?string {
|
||||
$hookId = spl_object_id($hook);
|
||||
|
||||
if (in_array($hookId, $renderedHooks)) {
|
||||
@@ -57,7 +58,9 @@ class ViewManager
|
||||
|
||||
$renderedHooks[] = $hookId;
|
||||
|
||||
return (string) app()->call($hook, ['scopes' => $scopes]);
|
||||
$result = app()->call($hook, ['data' => $data, 'scopes' => $scopes]);
|
||||
|
||||
return (string) $result;
|
||||
};
|
||||
|
||||
$hooks = array_map(
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
use Filament\Support\Enums\Alignment;
|
||||
use Filament\Support\Enums\VerticalAlignment;
|
||||
use Filament\Support\Enums\Width;
|
||||
use Filament\Support\Facades\FilamentView;
|
||||
use Filament\Tables\Actions\HeaderActionsPosition;
|
||||
use Filament\Tables\Columns\Column;
|
||||
use Filament\Tables\Columns\ColumnGroup;
|
||||
use Filament\Tables\Enums\FiltersLayout;
|
||||
use Filament\Tables\Enums\RecordActionsPosition;
|
||||
use Filament\Tables\Enums\RecordCheckboxPosition;
|
||||
use Filament\Tables\View\TablesRenderHook;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\View\ComponentAttributeBag;
|
||||
|
||||
@@ -163,7 +165,7 @@
|
||||
x-show="@js($hasHeader) || @js($hasNonBulkToolbarAction) || (getSelectedRecordsCount() && @js(count($toolbarActions)))"
|
||||
class="fi-ta-header-ctn"
|
||||
>
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::HEADER_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::HEADER_BEFORE, scopes: static::class) }}
|
||||
|
||||
@if ($header)
|
||||
{{ $header }}
|
||||
@@ -202,7 +204,7 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::HEADER_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::HEADER_AFTER, scopes: static::class) }}
|
||||
|
||||
@if ($hasFiltersAboveContent)
|
||||
<div
|
||||
@@ -231,23 +233,23 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_BEFORE, scopes: static::class) }}
|
||||
|
||||
<div
|
||||
@if (! $hasHeaderToolbar) x-cloak @endif
|
||||
x-show="@js($hasHeaderToolbar) || @js($hasNonBulkToolbarAction) || (getSelectedRecordsCount() && @js(count($toolbarActions)))"
|
||||
class="fi-ta-header-toolbar"
|
||||
>
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_START, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_START, scopes: static::class) }}
|
||||
|
||||
<div class="fi-ta-actions fi-align-start fi-wrapped">
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_REORDER_TRIGGER_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_BEFORE, scopes: static::class) }}
|
||||
|
||||
@if ($isReorderable)
|
||||
{{ $reorderRecordsTriggerAction }}
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_REORDER_TRIGGER_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_REORDER_TRIGGER_AFTER, scopes: static::class) }}
|
||||
|
||||
@if ((! $isReordering) && count($toolbarActions))
|
||||
@foreach ($toolbarActions as $action)
|
||||
@@ -255,7 +257,7 @@
|
||||
@endforeach
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_BEFORE, scopes: static::class) }}
|
||||
|
||||
@if ($areGroupingSettingsVisible)
|
||||
<div
|
||||
@@ -398,12 +400,12 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_GROUPING_SELECTOR_AFTER, scopes: static::class) }}
|
||||
</div>
|
||||
|
||||
@if ($isGlobalSearchVisible || $hasFiltersDialog || $hasColumnManagerDropdown)
|
||||
<div>
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_SEARCH_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_BEFORE, scopes: static::class) }}
|
||||
|
||||
@if ($isGlobalSearchVisible)
|
||||
@php
|
||||
@@ -417,7 +419,7 @@
|
||||
/>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_SEARCH_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_SEARCH_AFTER, scopes: static::class) }}
|
||||
|
||||
@if ($hasFiltersDialog || $hasColumnManagerDropdown)
|
||||
@if ($hasFiltersDialog)
|
||||
@@ -494,7 +496,7 @@
|
||||
@endif
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_BEFORE, scopes: static::class) }}
|
||||
|
||||
@if ($hasColumnManagerDropdown)
|
||||
@php
|
||||
@@ -526,15 +528,15 @@
|
||||
</x-filament::dropdown>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER, scopes: static::class) }}
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_END) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_END) }}
|
||||
</div>
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::TOOLBAR_AFTER) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::TOOLBAR_AFTER) }}
|
||||
</div>
|
||||
|
||||
@if ($isReordering)
|
||||
@@ -578,7 +580,7 @@
|
||||
|
||||
@if (! $isSelectionDisabled)
|
||||
<div>
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_BEFORE, scopes: static::class) }}
|
||||
|
||||
<div class="fi-ta-selection-indicator-actions-ctn">
|
||||
<x-filament::link
|
||||
@@ -601,62 +603,66 @@
|
||||
</x-filament::link>
|
||||
</div>
|
||||
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook(\Filament\Tables\View\TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER, scopes: static::class) }}
|
||||
{{ FilamentView::renderHook(TablesRenderHook::SELECTION_INDICATOR_ACTIONS_AFTER, scopes: static::class) }}
|
||||
</div>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
|
||||
@if ($filterIndicators)
|
||||
<div class="fi-ta-filter-indicators">
|
||||
<div>
|
||||
<span class="fi-ta-filter-indicators-label">
|
||||
{{ __('filament-tables::table.filters.indicator') }}
|
||||
</span>
|
||||
@if ($filterIndicatorsView = FilamentView::renderHook(TablesRenderHook::FILTER_INDICATORS, scopes: static::class, data: ['filterIndicators' => $filterIndicators]))
|
||||
{{ $filterIndicatorsView }}
|
||||
@else
|
||||
<div class="fi-ta-filter-indicators">
|
||||
<div>
|
||||
<span class="fi-ta-filter-indicators-label">
|
||||
{{ __('filament-tables::table.filters.indicator') }}
|
||||
</span>
|
||||
|
||||
<div class="fi-ta-filter-indicators-badges-ctn">
|
||||
@foreach ($filterIndicators as $indicator)
|
||||
@php
|
||||
$indicatorColor = $indicator->getColor();
|
||||
@endphp
|
||||
<div class="fi-ta-filter-indicators-badges-ctn">
|
||||
@foreach ($filterIndicators as $indicator)
|
||||
@php
|
||||
$indicatorColor = $indicator->getColor();
|
||||
@endphp
|
||||
|
||||
<x-filament::badge :color="$indicatorColor">
|
||||
{{ $indicator->getLabel() }}
|
||||
<x-filament::badge :color="$indicatorColor">
|
||||
{{ $indicator->getLabel() }}
|
||||
|
||||
@if ($indicator->isRemovable())
|
||||
@php
|
||||
$indicatorRemoveLivewireClickHandler = $indicator->getRemoveLivewireClickHandler();
|
||||
@endphp
|
||||
@if ($indicator->isRemovable())
|
||||
@php
|
||||
$indicatorRemoveLivewireClickHandler = $indicator->getRemoveLivewireClickHandler();
|
||||
@endphp
|
||||
|
||||
<x-slot
|
||||
name="deleteButton"
|
||||
:label="__('filament-tables::table.filters.actions.remove.label')"
|
||||
:wire:click="$indicatorRemoveLivewireClickHandler"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="removeTableFilter"
|
||||
></x-slot>
|
||||
@endif
|
||||
</x-filament::badge>
|
||||
@endforeach
|
||||
<x-slot
|
||||
name="deleteButton"
|
||||
:label="__('filament-tables::table.filters.actions.remove.label')"
|
||||
:wire:click="$indicatorRemoveLivewireClickHandler"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="removeTableFilter"
|
||||
></x-slot>
|
||||
@endif
|
||||
</x-filament::badge>
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@if (collect($filterIndicators)->contains(fn (\Filament\Tables\Filters\Indicator $indicator): bool => $indicator->isRemovable()))
|
||||
<button
|
||||
type="button"
|
||||
x-tooltip="{
|
||||
content: @js(__('filament-tables::table.filters.actions.remove_all.tooltip')),
|
||||
theme: $store.theme,
|
||||
}"
|
||||
wire:click="removeTableFilters"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="removeTableFilters,removeTableFilter"
|
||||
class="fi-icon-btn fi-size-sm"
|
||||
>
|
||||
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Tables\View\TablesIconAlias::FILTERS_REMOVE_ALL_BUTTON, size: \Filament\Support\Enums\IconSize::Small) }}
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
@if (collect($filterIndicators)->contains(fn (\Filament\Tables\Filters\Indicator $indicator): bool => $indicator->isRemovable()))
|
||||
<button
|
||||
type="button"
|
||||
x-tooltip="{
|
||||
content: @js(__('filament-tables::table.filters.actions.remove_all.tooltip')),
|
||||
theme: $store.theme,
|
||||
}"
|
||||
wire:click="removeTableFilters"
|
||||
wire:loading.attr="disabled"
|
||||
wire:target="removeTableFilters,removeTableFilter"
|
||||
class="fi-icon-btn fi-size-sm"
|
||||
>
|
||||
{{ \Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Tables\View\TablesIconAlias::FILTERS_REMOVE_ALL_BUTTON, size: \Filament\Support\Enums\IconSize::Small) }}
|
||||
</button>
|
||||
@endif
|
||||
</div>
|
||||
@endif
|
||||
@endif
|
||||
|
||||
@if (((! $content) && (! $hasColumnsLayout)) || ($records === null) || count($records))
|
||||
|
||||
@@ -36,6 +36,8 @@ class TablesRenderHook
|
||||
|
||||
const TOOLBAR_START = 'tables::toolbar.start';
|
||||
|
||||
const FILTER_INDICATORS = 'tables::filter.indicators';
|
||||
|
||||
/**
|
||||
* @deprecated Use `TOOLBAR_COLUMN_MANAGER_TRIGGER_AFTER` instead.
|
||||
*/
|
||||
|
||||
@@ -28,7 +28,7 @@ test('render hooks can render view files', function (): void {
|
||||
->toHtml()->toContain('bar');
|
||||
});
|
||||
|
||||
test('render hooks can be scopes:d', function (): void {
|
||||
test('render hooks can be scoped', function (): void {
|
||||
FilamentView::registerRenderHook('foo', function (): string {
|
||||
return Blade::render('bar');
|
||||
});
|
||||
@@ -42,7 +42,7 @@ test('render hooks can be scopes:d', function (): void {
|
||||
->toHtml()->toBe('barbar');
|
||||
});
|
||||
|
||||
test('render hooks can be scopes:d to multiple scopes:s', function (): void {
|
||||
test('render hooks can be scoped to multiple scoped', function (): void {
|
||||
FilamentView::registerRenderHook('foo', function (): string {
|
||||
return Blade::render('bar');
|
||||
});
|
||||
@@ -60,7 +60,7 @@ test('render hooks can be scopes:d to multiple scopes:s', function (): void {
|
||||
->toHtml()->toBe('barbar');
|
||||
});
|
||||
|
||||
test('render hooks can be scopes:d to multiple scopes:s but only ever output once', function (): void {
|
||||
test('render hooks can be scoped to multiple scoped but only ever output once', function (): void {
|
||||
FilamentView::registerRenderHook('foo', function (): string {
|
||||
return Blade::render('bar');
|
||||
});
|
||||
@@ -73,3 +73,13 @@ test('render hooks can be scopes:d to multiple scopes:s but only ever output onc
|
||||
->toBeInstanceOf(HtmlString::class)
|
||||
->toHtml()->toBe('barbar');
|
||||
});
|
||||
|
||||
test('render hooks can be passed data', function (): void {
|
||||
FilamentView::registerRenderHook('foo', function ($data): string {
|
||||
return $data['foo'];
|
||||
});
|
||||
|
||||
expect(FilamentView::renderHook('foo', data: ['foo' => 'bar']))
|
||||
->toBeInstanceOf(HtmlString::class)
|
||||
->toHtml()->toBe('bar');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user