Skip to content

Commit 0d12e3f

Browse files
feat: add controls slot to callout component (#19263)
* Add support for callout control actions. * Update documentation * chore: fix code style * cleanup * screenshots * better example --------- Co-authored-by: gehrisandro <gehrisandro@users.noreply.github.com> Co-authored-by: Dan Harrin <git@danharrin.com>
1 parent 3a3db66 commit 0d12e3f

File tree

13 files changed

+231
-3
lines changed

13 files changed

+231
-3
lines changed

CLAUDE.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,12 @@ Screenshots are in `docs-assets/screenshots/`. To add new screenshots:
242242
},
243243
```
244244

245-
3. **Generate screenshots**:
245+
3. **Build assets** if you changed any CSS or JS files (the docs app uses the compiled output):
246+
```bash
247+
npm run build
248+
```
249+
250+
4. **Generate screenshots**:
246251
```bash
247252
# Terminal 1: Start the app server (must use default port 8000)
248253
cd docs-assets/app && php artisan serve
@@ -256,6 +261,6 @@ Screenshots are in `docs-assets/screenshots/`. To add new screenshots:
256261

257262
**Important:** The script expects `http://127.0.0.1:8000`. Don't use a custom port.
258263

259-
4. **Use in docs** with `<AutoScreenshot name="schemas/layout/my-component/simple" alt="Description" version="4.x" />`
264+
5. **Use in docs** with `<AutoScreenshot name="schemas/layout/my-component/simple" alt="Description" version="4.x" />`
260265

261266
Screenshots are generated in `images/light/` and `images/dark/`. Use natural, realistic content - not test-like examples.

docs-assets/app/app/Livewire/Schemas/LayoutDemo.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,22 @@ public function form(Schema $form): Schema
854854
->button(),
855855
]),
856856
]),
857+
Group::make()
858+
->id('calloutControlActions')
859+
->extraAttributes([
860+
'class' => 'p-16 max-w-2xl',
861+
])
862+
->schema([
863+
Callout::make('New version available')
864+
->description('Filament v4 has been released with exciting new features and improvements.')
865+
->info()
866+
->controlActions([
867+
Action::make('dismiss')
868+
->icon(Heroicon::XMark)
869+
->iconButton()
870+
->color('gray'),
871+
]),
872+
]),
857873
Group::make()
858874
->id('calloutActionsAlignedEnd')
859875
->extraAttributes([
39.7 KB
Loading
40 KB
Loading

docs-assets/screenshots/schema.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1808,6 +1808,15 @@ export default {
18081808
deviceScaleFactor: 3,
18091809
},
18101810
},
1811+
'schemas/layout/callout/control-actions': {
1812+
url: 'schemas/layout',
1813+
selector: '#calloutControlActions',
1814+
viewport: {
1815+
width: 1920,
1816+
height: 320,
1817+
deviceScaleFactor: 3,
1818+
},
1819+
},
18111820
'schemas/layout/callout/actions-aligned-end': {
18121821
url: 'schemas/layout',
18131822
selector: '#calloutActionsAlignedEnd',

docs/12-components/03-callout.md

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,33 @@ You can also include buttons or other interactive elements in the footer:
213213
</x-filament::callout>
214214
```
215215

216+
## Adding content to the controls
217+
218+
You can add custom content to the callout controls (top-right corner) using the `controls` slot:
219+
220+
```blade
221+
<x-filament::callout
222+
icon="heroicon-o-information-circle"
223+
color="info"
224+
>
225+
<x-slot name="heading">
226+
Dismissible Callout
227+
</x-slot>
228+
229+
<x-slot name="description">
230+
This callout can be dismissed using the control in the top-right corner.
231+
</x-slot>
232+
233+
<x-slot name="controls">
234+
<x-filament::icon-button
235+
icon="heroicon-m-x-mark"
236+
color="gray"
237+
label="Dismiss"
238+
/>
239+
</x-slot>
240+
</x-filament::callout>
241+
```
242+
216243
## Callouts without an icon
217244

218245
Callouts can be rendered without an icon if needed:

packages/panels/dist/theme.css

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/schemas/docs/06-callouts.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,3 +198,48 @@ Callout::make('Backup complete')
198198
<UtilityInjection set="schemaComponents" version="4.x">As well as allowing a static value, the `footer()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
199199

200200
<AutoScreenshot name="schemas/layout/callout/footer" alt="Callout with custom footer content" version="4.x" />
201+
202+
## Adding custom control content
203+
204+
You can add custom content to the controls (top-right corner) using the `controls()` method. This accepts an array of schema components:
205+
206+
```php
207+
use Filament\Actions\Action;
208+
use Filament\Schemas\Components\Callout;
209+
210+
Callout::make('Backup complete')
211+
->description('Your data has been successfully backed up to the cloud.')
212+
->success()
213+
->controls([
214+
Action::make('dismiss')
215+
->icon('heroicon-m-x-mark')
216+
->iconButton()
217+
->color('gray'),
218+
])
219+
```
220+
221+
<UtilityInjection set="schemaComponents" version="4.x">As well as allowing a static value, the `controls()` method also accepts a function to dynamically calculate it. You can inject various utilities into the function as parameters.</UtilityInjection>
222+
223+
## Adding control actions to the callout
224+
225+
You can add control [actions](../actions) to the top-right corner of the callout using the `controlActions()` method. For example, you could add a dismiss button that hides the callout for the duration of the user's session:
226+
227+
```php
228+
use Filament\Actions\Action;
229+
use Filament\Schemas\Components\Callout;
230+
use Filament\Support\Icons\Heroicon;
231+
232+
Callout::make('New version available')
233+
->description('Filament v4 has been released with exciting new features and improvements.')
234+
->info()
235+
->controlActions([
236+
Action::make('dismiss')
237+
->icon(Heroicon::XMark)
238+
->iconButton()
239+
->color('gray')
240+
->action(fn () => session()->put('new-version-callout-dismissed', true)),
241+
])
242+
->visible(fn (): bool => ! session()->get('new-version-callout-dismissed'))
243+
```
244+
245+
<AutoScreenshot name="schemas/layout/callout/control-actions" alt="Callout with control actions" version="4.x" />

packages/schemas/resources/views/components/callout.blade.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@php
22
use Filament\Support\Enums\IconSize;
33
4+
$controls = $getChildSchema($schemaComponent::CONTROLS_SCHEMA_KEY)?->toHtmlString();
45
$extraAttributeBag = $getExtraAttributeBag();
56
$footer = $getChildSchema($schemaComponent::FOOTER_SCHEMA_KEY)?->toHtmlString();
67
$color = $getColor();
@@ -26,4 +27,8 @@
2627
<x-slot name="footer">
2728
{{ $footer }}
2829
</x-slot>
30+
31+
<x-slot name="controls">
32+
{{ $controls }}
33+
</x-slot>
2934
</x-filament::callout>

packages/schemas/src/Components/Callout.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
use Filament\Support\Facades\FilamentIcon;
2121
use Filament\Support\Icons\Heroicon;
2222
use Illuminate\Contracts\Support\Htmlable;
23+
use Illuminate\Support\Arr;
2324

2425
class Callout extends Component
2526
{
@@ -45,10 +46,17 @@ class Callout extends Component
4546

4647
public const FOOTER_SCHEMA_KEY = 'footer';
4748

49+
public const CONTROLS_SCHEMA_KEY = 'controls';
50+
4851
protected bool $hasColor = false;
4952

5053
protected string | Closure | null $status = null;
5154

55+
/**
56+
* @var array<Action | Closure>
57+
*/
58+
protected array $controlActions = [];
59+
5260
final public function __construct(string | Htmlable | Closure | null $heading = null)
5361
{
5462
$this->heading($heading);
@@ -74,6 +82,10 @@ protected function setUp(): void
7482
default => Schema::start($component->getFooterActions()),
7583
};
7684
});
85+
86+
$this->controls(function (Callout $component): Schema {
87+
return Schema::start($component->getControlActions());
88+
});
7789
}
7890

7991
/**
@@ -179,6 +191,45 @@ public function getDefaultActions(): array
179191
return $this->getFooterActions();
180192
}
181193

194+
/**
195+
* @param array<Action | Closure> $actions
196+
*/
197+
public function controlActions(array $actions): static
198+
{
199+
$this->controlActions = [
200+
...$this->controlActions,
201+
...$actions,
202+
];
203+
204+
return $this;
205+
}
206+
207+
/**
208+
* @return array<Action>
209+
*/
210+
public function getControlActions(): array
211+
{
212+
$actions = [];
213+
214+
foreach ($this->controlActions as $controlAction) {
215+
foreach (Arr::wrap($this->evaluate($controlAction)) as $action) {
216+
$actions[] = $this->prepareAction($action);
217+
}
218+
}
219+
220+
return $actions;
221+
}
222+
223+
/**
224+
* @param array<Component | Action | ActionGroup | string | Htmlable> | Schema | Component | Action | ActionGroup | string | Htmlable | Closure | null $components
225+
*/
226+
public function controls(array | Schema | Component | Action | ActionGroup | string | Htmlable | Closure | null $components): static
227+
{
228+
$this->childComponents($components, static::CONTROLS_SCHEMA_KEY);
229+
230+
return $this;
231+
}
232+
182233
protected function configureChildSchema(Schema $schema, string $key): Schema
183234
{
184235
$schema = parent::configureChildSchema($schema, $key);
@@ -193,6 +244,15 @@ protected function configureChildSchema(Schema $schema, string $key): Schema
193244
->modifyActionGroupsUsing(fn (ActionGroup $actionGroup) => $actionGroup->defaultSize(Size::Small));
194245
}
195246

247+
if ($key === static::CONTROLS_SCHEMA_KEY) {
248+
$schema
249+
->inline()
250+
->embeddedInParentComponent()
251+
->modifyActionsUsing(fn (Action $action) => $action
252+
->defaultSize(Size::Small))
253+
->modifyActionGroupsUsing(fn (ActionGroup $actionGroup) => $actionGroup->defaultSize(Size::Small));
254+
}
255+
196256
return $schema;
197257
}
198258
}

0 commit comments

Comments
 (0)