Skip to content

Commit 3f5935f

Browse files
authored
feature: Grouped custom rich editor blocks (#19653)
* feature: Grouped custom rich editor blocks * screenshot * Update RichContentAttribute.php
1 parent 3afd12b commit 3f5935f

21 files changed

Lines changed: 1033 additions & 41 deletions

File tree

docs-assets/app/app/Livewire/Forms/Fields/RichEditorSchema.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,13 @@
22

33
namespace App\Livewire\Forms\Fields;
44

5+
use App\RichContentBlocks\AlertBlock;
6+
use App\RichContentBlocks\BannerBlock;
57
use App\RichContentBlocks\CallToActionBlock;
68
use App\RichContentBlocks\HeroBlock;
9+
use App\RichContentBlocks\ImageGalleryBlock;
710
use App\RichContentBlocks\TestimonialBlock;
11+
use App\RichContentBlocks\VideoEmbedBlock;
812
use Filament\Forms\Components\RichEditor;
913
use Filament\Forms\Components\RichEditor\MentionProvider;
1014
use Filament\Forms\Components\RichEditor\TextColor;
@@ -122,6 +126,28 @@ public static function schema(): array
122126
TestimonialBlock::class,
123127
]),
124128
]),
129+
Group::make()
130+
->id('richEditorGroupedCustomBlocks')
131+
->extraAttributes([
132+
'class' => 'p-16 max-w-5xl',
133+
])
134+
->schema([
135+
RichEditor::make('richEditorGroupedCustomBlocks')
136+
->label('Content')
137+
->customBlocks([
138+
AlertBlock::class,
139+
'Marketing' => [
140+
HeroBlock::class,
141+
CallToActionBlock::class,
142+
BannerBlock::class,
143+
TestimonialBlock::class,
144+
],
145+
'Media' => [
146+
ImageGalleryBlock::class,
147+
VideoEmbedBlock::class,
148+
],
149+
]),
150+
]),
125151
Group::make()
126152
->id('richEditorFloatingToolbar')
127153
->extraAttributes([
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\RichContentBlocks;
4+
5+
use Filament\Forms\Components\RichEditor\RichContentCustomBlock;
6+
7+
class AlertBlock extends RichContentCustomBlock
8+
{
9+
public static function getId(): string
10+
{
11+
return 'alert';
12+
}
13+
14+
public static function getLabel(): string
15+
{
16+
return 'Alert';
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\RichContentBlocks;
4+
5+
use Filament\Forms\Components\RichEditor\RichContentCustomBlock;
6+
7+
class BannerBlock extends RichContentCustomBlock
8+
{
9+
public static function getId(): string
10+
{
11+
return 'banner';
12+
}
13+
14+
public static function getLabel(): string
15+
{
16+
return 'Banner';
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\RichContentBlocks;
4+
5+
use Filament\Forms\Components\RichEditor\RichContentCustomBlock;
6+
7+
class ImageGalleryBlock extends RichContentCustomBlock
8+
{
9+
public static function getId(): string
10+
{
11+
return 'image-gallery';
12+
}
13+
14+
public static function getLabel(): string
15+
{
16+
return 'Image gallery';
17+
}
18+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace App\RichContentBlocks;
4+
5+
use Filament\Forms\Components\RichEditor\RichContentCustomBlock;
6+
7+
class VideoEmbedBlock extends RichContentCustomBlock
8+
{
9+
public static function getId(): string
10+
{
11+
return 'video-embed';
12+
}
13+
14+
public static function getLabel(): string
15+
{
16+
return 'Video embed';
17+
}
18+
}
-11 Bytes
Loading
112 KB
Loading
110 KB
Loading

docs-assets/screenshots/schema.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,6 +1706,26 @@ export default {
17061706
await new Promise((resolve) => setTimeout(resolve, 500))
17071707
},
17081708
},
1709+
'forms/fields/rich-editor/grouped-custom-blocks': {
1710+
url: 'forms/fields/rich-editor',
1711+
selector: '#richEditorGroupedCustomBlocks',
1712+
viewport: {
1713+
width: 1920,
1714+
height: 640,
1715+
deviceScaleFactor: 3,
1716+
},
1717+
before: async (page) => {
1718+
// Scroll into view so JS initializes.
1719+
await page.evaluate(() => {
1720+
document.querySelector('#richEditorGroupedCustomBlocks').scrollIntoView()
1721+
})
1722+
await new Promise((resolve) => setTimeout(resolve, 1000))
1723+
1724+
// Click the custom blocks toolbar button to open the side panel.
1725+
await page.click('#richEditorGroupedCustomBlocks button[aria-label="Blocks"]')
1726+
await new Promise((resolve) => setTimeout(resolve, 500))
1727+
},
1728+
},
17091729
'forms/fields/rich-editor/floating-toolbar': {
17101730
url: 'forms/fields/rich-editor',
17111731
selector: '#richEditorFloatingToolbar',

packages/forms/docs/10-rich-editor.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,6 +598,50 @@ RichContentRenderer::make($record->content)
598598
->toHtml()
599599
```
600600

601+
### Grouping custom blocks
602+
603+
You can organize custom blocks into groups using string keys in the `customBlocks()` array. Blocks passed directly (without a string key) are ungrouped and appear first in the panel:
604+
605+
```php
606+
use Filament\Forms\Components\RichEditor;
607+
608+
RichEditor::make('content')
609+
->customBlocks([
610+
AlertBlock::class,
611+
DividerBlock::class,
612+
'Marketing' => [
613+
HeroBlock::class,
614+
CallToActionBlock::class,
615+
BannerBlock::class,
616+
],
617+
'Media' => [
618+
ImageGalleryBlock::class,
619+
VideoEmbedBlock::class,
620+
],
621+
])
622+
```
623+
624+
<AutoScreenshot name="forms/fields/rich-editor/grouped-custom-blocks" alt="Rich editor with grouped custom blocks panel open" version="4.x" />
625+
626+
Groups are displayed in the order they are defined in the array, with sticky headings in the side panel.
627+
628+
When rendering content with grouped blocks, you can pass the same grouped array structure to the `RichContentRenderer`. Groups are ignored during rendering — only the block classes are used:
629+
630+
```php
631+
use Filament\Forms\Components\RichEditor\RichContentRenderer;
632+
633+
RichContentRenderer::make($record->content)
634+
->customBlocks([
635+
'Marketing' => [
636+
HeroBlock::class => [
637+
'categoryUrl' => $record->category->getUrl(),
638+
],
639+
CallToActionBlock::class,
640+
],
641+
])
642+
->toHtml()
643+
```
644+
601645
### Opening the custom blocks panel by default
602646

603647
If you want the custom blocks panel to be open by default when the rich editor is loaded, you can use the `activePanel('customBlocks')` method:

0 commit comments

Comments
 (0)