Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support previews in builder #12629

Merged
merged 10 commits into from
Jun 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions packages/forms/docs/03-fields/13-builder.md
Original file line number Diff line number Diff line change
Expand Up @@ -464,6 +464,49 @@ $state[Str::uuid()] = [
$component->state($state);
```

## Previewing blocks

If you prefer to render read-only previews in the builder instead of the blocks' forms, you can use the `blockPreviews()` method. This will render each block's `preview()` instead of the form. Block data will be passed to the preview Blade view in a variable with the same name:

```php
use Filament\Forms\Components\Builder;
use Filament\Forms\Components\Builder\Block;
use Filament\Forms\Components\TextInput;

Builder::make('content')
->blockPreviews()
->blocks([
Block::make('heading')
->schema([
TextInput::make('text')
->placeholder('Default heading'),
])
->preview('filament.content.blocks-previews.heading'),
])
```

In `/resources/views/filament/content/block-previews/heading.blade.php`, you can access the block data like so:

```blade
<h1>
{{ $text ?? 'Default heading' }}
</h1>
```

### Interactive block previews

By default, preview content is not interactive, and clicking it will open the Edit modal for that block to manage its settings. If you have links and buttons that you'd like to remain interactive in the block previews, you can use the `areInteractive: true` argument of the `blockPreviews()` method:

```php
use Filament\Forms\Components\Builder;

Builder::make('content')
->blockPreviews(areInteractive: true)
->blocks([
//
])
```

## Testing builders

Internally, builders generate UUIDs for items to keep track of them in the Livewire HTML easier. This means that when you are testing a form with a builder, you need to ensure that the UUIDs are consistent between the form and the test. This can be tricky, and if you don't do it correctly, your tests can fail as the tests are expecting a UUID, not a numeric key.
Expand Down
52 changes: 52 additions & 0 deletions packages/forms/resources/lang/en/components.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,69 @@
],

'add' => [

'label' => 'Add to :label',

'modal' => [

'heading' => 'Add to :label',

'actions' => [

'add' => [
'label' => 'Add',
],

],

],

],

'add_between' => [

'label' => 'Insert between blocks',

'modal' => [

'heading' => 'Add to :label',

'actions' => [

'add' => [
'label' => 'Add',
],

],

],

],

'delete' => [
'label' => 'Delete',
],

'edit' => [

'label' => 'Edit',

'modal' => [

'heading' => 'Edit block',

'actions' => [

'save' => [
'label' => 'Save changes',
],

],

],

],

'reorder' => [
'label' => 'Move',
],
Expand Down
41 changes: 37 additions & 4 deletions packages/forms/resources/views/components/builder.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@
$blockPickerBlocks = $getBlockPickerBlocks();
$blockPickerColumns = $getBlockPickerColumns();
$blockPickerWidth = $getBlockPickerWidth();
$hasBlockPreviews = $hasBlockPreviews();
$hasInteractiveBlockPreviews = $hasInteractiveBlockPreviews();

$addAction = $getAction($getAddActionName());
$addBetweenAction = $getAction($getAddBetweenActionName());
$cloneAction = $getAction($getCloneActionName());
$collapseAllAction = $getAction($getCollapseAllActionName());
$editAction = $getAction($getEditActionName());
$expandAllAction = $getAction($getExpandAllActionName());
$deleteAction = $getAction($getDeleteActionName());
$moveDownAction = $getAction($getMoveDownActionName());
Expand Down Expand Up @@ -86,6 +89,8 @@ class="space-y-4"
$cloneActionIsVisible = $isCloneable && $cloneAction->isVisible();
$deleteAction = $deleteAction(['item' => $uuid]);
$deleteActionIsVisible = $isDeletable && $deleteAction->isVisible();
$editAction = $editAction(['item' => $uuid]);
$editActionIsVisible = $hasBlockPreviews && $editAction->isVisible();
$moveDownAction = $moveDownAction(['item' => $uuid])->disabled($loop->last);
$moveDownActionIsVisible = $isReorderableWithButtons && $moveDownAction->isVisible();
$moveUpAction = $moveUpAction(['item' => $uuid])->disabled($loop->first);
Expand All @@ -105,7 +110,7 @@ class="space-y-4"
class="fi-fo-builder-item rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 dark:bg-white/5 dark:ring-white/10"
x-bind:class="{ 'fi-collapsed overflow-hidden': isCollapsed }"
>
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $hasBlockLabels || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
@if ($reorderActionIsVisible || $moveUpActionIsVisible || $moveDownActionIsVisible || $hasBlockLabels || $editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<div
@if ($isCollapsible)
x-on:click.stop="isCollapsed = !isCollapsed"
Expand Down Expand Up @@ -153,7 +158,7 @@ class="fi-fo-builder-item rounded-xl bg-white shadow-sm ring-1 ring-gray-950/5 d
</h4>
@endif

@if ($cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
@if ($editActionIsVisible || $cloneActionIsVisible || $deleteActionIsVisible || $isCollapsible || $visibleExtraItemActions)
<ul
class="ms-auto flex items-center gap-x-3"
>
Expand All @@ -163,6 +168,12 @@ class="ms-auto flex items-center gap-x-3"
</li>
@endforeach

@if ($editActionIsVisible)
<li x-on:click.stop>
{{ $editAction }}
</li>
@endif

@if ($cloneActionIsVisible)
<li x-on:click.stop>
{{ $cloneAction }}
Expand Down Expand Up @@ -203,9 +214,31 @@ class="absolute inset-0 rotate-180 transition"

<div
x-show="! isCollapsed"
class="fi-fo-builder-item-content border-t border-gray-100 p-4 dark:border-white/10"
@class([
'fi-fo-builder-item-content relative border-t border-gray-100 dark:border-white/10',
'p-4' => ! $hasBlockPreviews,
])
>
{{ $item }}
@if ($hasBlockPreviews)
<div
@class([
'fi-fo-builder-item-preview',
'pointer-events-none' => ! $hasInteractiveBlockPreviews,
])
>
{{ $item->getParentComponent()->renderPreview($item->getRawState()) }}
</div>

@if ($editActionIsVisible && (! $hasInteractiveBlockPreviews))
<div
class="absolute inset-0 z-[1] cursor-pointer"
role="button"
x-on:click.stop="{{ '$wire.mountFormComponentAction(\'' . $statePath . '\', \'edit\', { item: \'' . $uuid . '\' })' }}"
></div>
@endif
@else
{{ $item }}
@endif
</div>
</li>

Expand Down
Loading
Loading