This commit is contained in:
2025-10-22 20:08:22 +05:00
commit 736e3bef18
2573 changed files with 120385 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
@php
use Filament\Support\Enums\VerticalAlignment;
$actions = $getChildSchema()->getComponents();
$alignment = $getAlignment();
$isFullWidth = $isFullWidth();
$verticalAlignment = $getVerticalAlignment();
if (! $verticalAlignment instanceof VerticalAlignment) {
$verticalAlignment = filled($verticalAlignment) ? (VerticalAlignment::tryFrom($verticalAlignment) ?? $verticalAlignment) : null;
}
@endphp
<div
@if ($isSticky())
x-data="filamentActionsSchemaComponent()"
x-intersect:enter.half="disableSticky"
x-intersect:leave="enableSticky"
x-bind:class="{ 'fi-sticky': isSticky }"
@endif
{{
$attributes
->merge([
'id' => $getId(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class([
'fi-sc-actions',
($verticalAlignment instanceof VerticalAlignment) ? "fi-vertical-align-{$verticalAlignment->value}" : $verticalAlignment,
])
}}
>
@if (filled($label = $getLabel()))
<div class="fi-sc-actions-label-ctn">
{{ $getChildSchema($schemaComponent::BEFORE_LABEL_SCHEMA_KEY) }}
<div class="fi-sc-actions-label">
{{ $label }}
</div>
{{ $getChildSchema($schemaComponent::AFTER_LABEL_SCHEMA_KEY) }}
</div>
@endif
@if ($aboveContentContainer = $getChildSchema($schemaComponent::ABOVE_CONTENT_SCHEMA_KEY)?->toHtmlString())
{{ $aboveContentContainer }}
@endif
<x-filament::actions
:actions="$actions"
:alignment="$alignment"
:full-width="$isFullWidth"
/>
@if ($belowContentContainer = $getChildSchema($schemaComponent::BELOW_CONTENT_SCHEMA_KEY)?->toHtmlString())
{{ $belowContentContainer }}
@endif
</div>

View File

@@ -0,0 +1,27 @@
@php
$description = $getDescription();
$footer = $getChildSchema($schemaComponent::FOOTER_SCHEMA_KEY)?->toHtmlString();
$heading = $getHeading();
$headingTag = $getHeadingTag();
$icon = $getIcon();
$iconColor = $getIconColor();
$iconSize = $getIconSize();
@endphp
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class(['fi-sc-empty-state'])
}}
>
<x-filament::empty-state
:description="$description"
:footer="$footer"
:heading="$heading"
:heading-tag="$headingTag"
:icon="$icon"
:icon-color="$iconColor"
:icon-size="$iconSize"
/>
</div>

View File

@@ -0,0 +1,24 @@
@php
$extraAttributes = $getExtraAttributes();
$id = $getId();
$isLabelHidden = $isLabelHidden();
$label = $getLabel();
$isContained = $isContained();
@endphp
<x-filament::fieldset
:contained="$isContained"
:label="$label"
:label-hidden="$isLabelHidden"
:required="isset($isMarkedAsRequired) ? $isMarkedAsRequired() : false"
:attributes="
\Filament\Support\prepare_inherited_attributes($attributes)
->merge([
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
->class(['fi-sc-fieldset'])
"
>
{{ $getChildSchema() }}
</x-filament::fieldset>

View File

@@ -0,0 +1,71 @@
@php
use Filament\Actions\Action;
use Filament\Actions\ActionGroup;
use Filament\Schemas\Components\Component;
use Filament\Support\Enums\VerticalAlignment;
$statePath = $getStatePath();
$fromBreakpoint = $getFromBreakpoint();
$verticalAlignment = $getVerticalAlignment();
if (! $verticalAlignment instanceof VerticalAlignment) {
$verticalAlignment = filled($verticalAlignment) ? (VerticalAlignment::tryFrom($verticalAlignment) ?? $verticalAlignment) : null;
}
@endphp
<div
{{
$attributes
->merge($getExtraAttributes(), escape: false)
->class([
'fi-sc-flex',
'fi-dense' => $isDense(),
'fi-from-' . ($fromBreakpoint ?? 'default'),
($verticalAlignment instanceof VerticalAlignment) ? "fi-vertical-align-{$verticalAlignment->value}" : $verticalAlignment,
])
}}
>
@foreach ($getChildSchema()->getComponents() as $component)
@if (($component instanceof Action) || ($component instanceof ActionGroup))
<div>
{{ $component }}
</div>
@else
@php
$hiddenJs = $component->getHiddenJs();
$visibleJs = $component->getVisibleJs();
$componentStatePath = $component->getStatePath();
@endphp
<div
x-data="filamentSchemaComponent({
path: @js($componentStatePath),
containerPath: @js($statePath),
$wire,
})"
@if ($afterStateUpdatedJs = $schemaComponent->getAfterStateUpdatedJs())
x-init="{!! implode(';', array_map(
fn (string $js): string => '$wire.watch(' . Js::from($componentStatePath) . ', ($state, $old) => isStateChanged($state, $old) && eval(' . Js::from($js) . '))',
$afterStateUpdatedJs,
)) !!}"
@endif
@if (filled($visibilityJs = match ([filled($hiddenJs), filled($visibleJs)]) {
[true, true] => "(! ({$hiddenJs})) && ({$visibleJs})",
[true, false] => "! ({$hiddenJs})",
[false, true] => $visibleJs,
default => null,
}))
x-bind:class="{ 'fi-hidden': ! ({!! $visibilityJs !!}) }"
x-cloak
@endif
@class([
'fi-growable' => ($component instanceof Component) && $component->canGrow(),
])
>
{{ $component }}
</div>
@endif
@endforeach
</div>

View File

@@ -0,0 +1,20 @@
<form
{{
$attributes
->merge([
'id' => $getId(),
'wire:submit' => $getLivewireSubmitHandler(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class([
'fi-sc-form',
'fi-dense' => $isDense(),
])
}}
>
{{ $getChildSchema($schemaComponent::HEADER_SCHEMA_KEY) }}
{{ $getChildSchema() }}
{{ $getChildSchema($schemaComponent::FOOTER_SCHEMA_KEY) }}
</form>

View File

@@ -0,0 +1,73 @@
@php
use Filament\Forms\Components\Contracts\HasNestedRecursiveValidationRules;
use Filament\Forms\Components\Field;
$fieldWrapperView = $getFieldWrapperView();
$errorMessages = null;
$errorMessage = null;
foreach ($getChildComponentContainer()->getComponents() as $childComponent) {
if (! ($childComponent instanceof Field)) {
continue;
}
$statePath = $childComponent->getStatePath();
if (blank($statePath)) {
continue;
}
if ($errors->has($statePath)) {
if ($childComponent->shouldShowAllValidationMessages()) {
$errorMessages = $errors->get($statePath);
$shouldShowAllValidationMessages = true;
} else {
$errorMessage = $errors->first($statePath);
}
$areHtmlValidationMessagesAllowed = $childComponent->areHtmlValidationMessagesAllowed();
break;
}
if (! ($childComponent instanceof HasNestedRecursiveValidationRules)) {
continue;
}
if ($errors->has("{$statePath}.*")) {
if ($childComponent->shouldShowAllValidationMessages()) {
$errorMessages = $errors->get("{$statePath}.*");
$shouldShowAllValidationMessages = true;
} else {
$errorMessage = $errors->first("{$statePath}.*");
}
$areHtmlValidationMessagesAllowed = $childComponent->areHtmlValidationMessagesAllowed();
break;
}
}
@endphp
<x-dynamic-component
:component="$fieldWrapperView"
:error-message="$errorMessage"
:error-messages="$errorMessages"
:are-html-error-messages-allowed="$areHtmlValidationMessagesAllowed ?? false"
:should-show-all-validation-messages="$shouldShowAllValidationMessages ?? false"
:field="$schemaComponent"
>
<div
{{
$attributes
->merge([
'id' => $getId(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-sc-fused-group'])
}}
>
{{ $getChildSchema() }}
</div>
</x-dynamic-component>

View File

@@ -0,0 +1,11 @@
<div
{{
$attributes
->merge([
'id' => $getId(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
}}
>
{{ $getChildSchema() }}
</div>

View File

@@ -0,0 +1,31 @@
@php
use Filament\Support\Enums\Alignment;
$alignment = $getAlignment();
$height = $getImageHeight() ?? '8rem';
$width = $getImageWidth();
$tooltip = $getTooltip();
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
}
@endphp
<img
alt="{{ $getAlt() }}"
src="{{ $getUrl() }}"
@if (filled($tooltip))
x-tooltip="{ content: @js($tooltip), theme: $store.theme }"
@endif
{{
$getExtraAttributeBag()
->class([
'fi-sc-image',
($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : $alignment,
])
->style([
"height: {$height}" => $height,
"width: {$width}" => $width,
])
}}
/>

View File

@@ -0,0 +1,27 @@
@php
$extraAttributes = $getExtraAttributes();
$id = $getId();
@endphp
@if (filled($id) || filled($extraAttributes))
{!! '<div' !!}
{{-- Avoid formatting issues with unclosed elements --}}
{{
$attributes
->merge([
'id' => $id,
], escape: false)
->merge($extraAttributes, escape: false)
}}
>
@endif
@if (filled($key = $getLivewireKey()))
@livewire($getComponent(), $getComponentProperties(), key($key))
@else
@livewire($getComponent(), $getComponentProperties())
@endif
@if (filled($id) || filled($extraAttributes))
{!! '</div>' !!}
{{-- Avoid formatting issues with unclosed elements --}}
@endif

View File

@@ -0,0 +1,76 @@
@php
$afterHeader = $getChildSchema($schemaComponent::AFTER_HEADER_SCHEMA_KEY)?->toHtmlString();
$isAside = $isAside();
$isCollapsed = $isCollapsed();
$isCollapsible = $isCollapsible();
$isCompact = $isCompact();
$isContained = $isContained();
$isDivided = $isDivided();
$isFormBefore = $isFormBefore();
$description = $getDescription();
$footer = $getChildSchema($schemaComponent::FOOTER_SCHEMA_KEY)?->toHtmlString();
$heading = $getHeading();
$headingTag = $getHeadingTag();
$icon = $getIcon();
$iconColor = $getIconColor();
$iconSize = $getIconSize();
$shouldPersistCollapsed = $shouldPersistCollapsed();
$isSecondary = $isSecondary();
$id = $getId();
@endphp
<div
{{
$attributes
->merge([
'id' => $id,
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class(['fi-sc-section'])
}}
>
@if (filled($label = $getLabel()))
<div class="fi-sc-section-label-ctn">
{{ $getChildSchema($schemaComponent::BEFORE_LABEL_SCHEMA_KEY) }}
<div class="fi-sc-section-label">
{{ $label }}
</div>
{{ $getChildSchema($schemaComponent::AFTER_LABEL_SCHEMA_KEY) }}
</div>
@endif
@if ($aboveContentContainer = $getChildSchema($schemaComponent::ABOVE_CONTENT_SCHEMA_KEY)?->toHtmlString())
{{ $aboveContentContainer }}
@endif
<x-filament::section
:after-header="$afterHeader"
:aside="$isAside"
:collapsed="$isCollapsed"
:collapse-id="$id"
:collapsible="$isCollapsible && (! $isAside)"
:compact="$isCompact"
:contained="$isContained"
:content-before="$isFormBefore"
:description="$description"
:divided="$isDivided"
:footer="$footer"
:has-content-el="false"
:heading="$heading"
:heading-tag="$headingTag"
:icon="$icon"
:icon-color="$iconColor"
:icon-size="$iconSize"
:persist-collapsed="$shouldPersistCollapsed"
:secondary="$isSecondary"
>
{{ $getChildSchema()->gap(! $isDivided)->extraAttributes(['class' => 'fi-section-content']) }}
</x-filament::section>
@if ($belowContentContainer = $getChildSchema($schemaComponent::BELOW_CONTENT_SCHEMA_KEY)?->toHtmlString())
{{ $belowContentContainer }}
@endif
</div>

View File

@@ -0,0 +1,194 @@
@php
use Filament\Schemas\Components\Tabs\Tab;
$activeTab = $getActiveTab();
$isContained = $isContained();
$isVertical = $isVertical();
$label = $getLabel();
$livewireProperty = $getLivewireProperty();
$renderHookScopes = $getRenderHookScopes();
$id = $getId();
@endphp
@if (blank($livewireProperty))
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('tabs', 'filament/schemas') }}"
x-data="tabsSchemaComponent({
activeTab: @js($activeTab),
isTabPersistedInQueryString: @js($isTabPersistedInQueryString()),
livewireId: @js($this->getId()),
tab: @if ($isTabPersisted() && filled($id)) $persist(null).as(@js($id)) @else @js(null) @endif,
tabQueryStringKey: @js($getTabQueryStringKey()),
})"
wire:ignore.self
{{
$attributes
->merge([
'id' => $id,
'wire:key' => $getLivewireKey() . '.container',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class([
'fi-sc-tabs',
'fi-contained' => $isContained,
'fi-vertical' => $isVertical,
])
}}
>
<input
type="hidden"
value="{{
collect($getChildSchema()->getComponents())
->filter(static fn (Tab $tab): bool => $tab->isVisible())
->map(static fn (Tab $tab) => $tab->getKey(isAbsolute: false))
->values()
->toJson()
}}"
x-ref="tabsData"
/>
<x-filament::tabs
:contained="$isContained"
:label="$label"
:vertical="$isVertical"
x-cloak
>
@foreach ($getStartRenderHooks() as $startRenderHook)
{{ \Filament\Support\Facades\FilamentView::renderHook($startRenderHook, scopes: $renderHookScopes) }}
@endforeach
@foreach ($getChildSchema()->getComponents() as $tab)
@php
$tabKey = $tab->getKey(isAbsolute: false);
$tabBadge = $tab->getBadge();
$tabBadgeColor = $tab->getBadgeColor();
$tabBadgeIcon = $tab->getBadgeIcon();
$tabBadgeIconPosition = $tab->getBadgeIconPosition();
$tabBadgeTooltip = $tab->getBadgeTooltip();
$tabIcon = $tab->getIcon();
$tabIconPosition = $tab->getIconPosition();
$tabExtraAttributeBag = $tab->getExtraAttributeBag();
$tabHiddenJs = $tab->getHiddenJs();
$tabVisibleJs = $tab->getVisibleJs();
$tabVisibilityJs = match ([filled($tabHiddenJs), filled($tabVisibleJs)]) {
[true, true] => "(! ({$tabHiddenJs})) && ({$tabVisibleJs})",
[true, false] => "! ({$tabHiddenJs})",
[false, true] => $tabVisibleJs,
default => null,
};
@endphp
<x-filament::tabs.item
:alpine-active="'tab === \'' . $tabKey . '\''"
:badge="$tabBadge"
:badge-color="$tabBadgeColor"
:badge-icon="$tabBadgeIcon"
:badge-icon-position="$tabBadgeIconPosition"
:badge-tooltip="$tabBadgeTooltip"
:icon="$tabIcon"
:icon-position="$tabIconPosition"
:x-on:click="'tab = \'' . $tabKey . '\''"
:x-show="$tabVisibilityJs"
:x-cloak="$tabVisibilityJs !== null"
:attributes="$tabExtraAttributeBag"
>
{{ $tab->getLabel() }}
</x-filament::tabs.item>
@endforeach
@foreach ($getEndRenderHooks() as $endRenderHook)
{{ \Filament\Support\Facades\FilamentView::renderHook($endRenderHook, scopes: $renderHookScopes) }}
@endforeach
</x-filament::tabs>
@foreach ($getChildSchema()->getComponents() as $tab)
@php
$tabHiddenJs = $tab->getHiddenJs();
$tabVisibleJs = $tab->getVisibleJs();
$tabVisibilityJs = match ([filled($tabHiddenJs), filled($tabVisibleJs)]) {
[true, true] => "(! ({$tabHiddenJs})) && ({$tabVisibleJs})",
[true, false] => "! ({$tabHiddenJs})",
[false, true] => $tabVisibleJs,
default => null,
};
@endphp
@if ($tabVisibilityJs)
<div x-show="{!! $tabVisibilityJs !!}" x-cloak>
{{ $tab }}
</div>
@else
{{ $tab }}
@endif
@endforeach
</div>
@else
@php
$activeTab = strval($this->{$livewireProperty});
@endphp
<div
{{
$attributes
->merge([
'id' => $id,
'wire:key' => $getLivewireKey() . '.container',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class([
'fi-sc-tabs',
'fi-contained' => $isContained,
'fi-vertical' => $isVertical,
])
}}
>
<x-filament::tabs
:contained="$isContained"
:label="$label"
:vertical="$isVertical"
>
@foreach ($getStartRenderHooks() as $startRenderHook)
{{ \Filament\Support\Facades\FilamentView::renderHook($startRenderHook, scopes: $renderHookScopes) }}
@endforeach
@foreach ($getChildSchema()->getComponents(withOriginalKeys: true) as $tabKey => $tab)
@php
$tabBadge = $tab->getBadge();
$tabBadgeColor = $tab->getBadgeColor();
$tabBadgeIcon = $tab->getBadgeIcon();
$tabBadgeIconPosition = $tab->getBadgeIconPosition();
$tabBadgeTooltip = $tab->getBadgeTooltip();
$tabIcon = $tab->getIcon();
$tabIconPosition = $tab->getIconPosition();
$tabExtraAttributeBag = $tab->getExtraAttributeBag();
$tabKey = strval($tabKey);
@endphp
<x-filament::tabs.item
:active="$activeTab === $tabKey"
:badge="$tabBadge"
:badge-color="$tabBadgeColor"
:badge-icon="$tabBadgeIcon"
:badge-icon-position="$tabBadgeIconPosition"
:badge-tooltip="$tabBadgeTooltip"
:icon="$tabIcon"
:icon-position="$tabIconPosition"
:wire:click="'$set(\'' . $livewireProperty . '\', ' . (filled($tabKey) ? ('\'' . $tabKey . '\'') : 'null') . ')'"
:attributes="$tabExtraAttributeBag"
>
{{ $tab->getLabel() ?? $this->generateTabLabel($tabKey) }}
</x-filament::tabs.item>
@endforeach
@foreach ($getEndRenderHooks() as $endRenderHook)
{{ \Filament\Support\Facades\FilamentView::renderHook($endRenderHook, scopes: $renderHookScopes) }}
@endforeach
</x-filament::tabs>
@foreach ($getChildSchema()->getComponents(withOriginalKeys: true) as $tabKey => $tab)
{{ $tab->key($tabKey) }}
@endforeach
</div>
@endif

View File

@@ -0,0 +1,51 @@
@php
$id = $getId();
$key = $getKey(isAbsolute: false);
$tabs = $getContainer()->getParentComponent();
$isContained = $tabs->isContained();
$livewireProperty = $tabs->getLivewireProperty();
$childSchema = $getChildSchema();
@endphp
@if (! empty($childSchema->getComponents()))
@if (blank($livewireProperty))
<div
x-bind:class="{
'fi-active': tab === @js($key),
}"
x-on:expand="tab = @js($key)"
{{
$attributes
->merge([
'aria-labelledby' => $id,
'id' => $id,
'role' => 'tabpanel',
'tabindex' => '0',
'wire:key' => $getLivewireKey() . '.container',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-sc-tabs-tab'])
}}
>
{{ $childSchema }}
</div>
@elseif (strval($this->{$livewireProperty}) === strval($key))
<div
{{
$attributes
->merge([
'aria-labelledby' => $id,
'id' => $id,
'role' => 'tabpanel',
'tabindex' => '0',
'wire:key' => $getLivewireKey() . '.container',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-sc-tabs-tab fi-active'])
}}
>
{{ $childSchema }}
</div>
@endif
@endif

View File

@@ -0,0 +1,74 @@
@php
use Filament\Schemas\View\Components\TextComponent;
use Filament\Support\Enums\FontFamily;
use Filament\Support\Enums\FontWeight;
use Filament\Support\RawJs;
$color = $getColor();
$content = $getContent();
$icon = $getIcon();
$iconPosition = $getIconPosition();
$iconSize = $getIconSize();
$size = $getSize();
$tooltip = $getTooltip();
$weight = $getWeight();
$fontFamily = $getFontFamily();
$copyableState = $getCopyableState($content) ?? $content;
$copyMessage = $getCopyMessage($copyableState);
$copyMessageDuration = $getCopyMessageDuration($copyableState);
$isCopyable = $isCopyable($copyableState);
@endphp
@if ($isBadge())
<x-filament::badge
:color="$color"
:icon="$icon"
:icon-position="$iconPosition"
:icon-size="$iconSize"
:size="$size instanceof \Filament\Support\Enums\TextSize ? $size->value : $size"
:x-on:click="
$isCopyable ? '
window.navigator.clipboard.writeText(' . \Illuminate\Support\Js::from($copyableState) . ')
$tooltip(' . \Illuminate\Support\Js::from($copyMessage) . ', {
theme: $store.theme,
timeout: ' . \Illuminate\Support\Js::from($copyMessageDuration) . ',
})
' : null
"
:tag="$isCopyable ? 'button' : 'span'"
:tooltip="$tooltip"
:attributes="\Filament\Support\prepare_inherited_attributes($getExtraAttributeBag()->class(['fi-sc-text']))"
>
{{ $content }}
</x-filament::badge>
@else
<span
@if ($isCopyable)
x-on:click="
window.navigator.clipboard.writeText(@js($copyableState))
$tooltip(@js($copyMessage), {
theme: $store.theme,
timeout: @js($copyMessageDuration),
})
"
@endif
@if (filled($tooltip))
x-tooltip="{ content: @js($tooltip), theme: $store.theme }"
@endif
{{
(new \Illuminate\View\ComponentAttributeBag)
->color(TextComponent::class, $color)
->class([
'fi-sc-text',
'fi-copyable' => $isCopyable,
($size instanceof \BackedEnum) ? "fi-size-{$size->value}" : $size,
($weight instanceof FontWeight) ? "fi-font-{$weight->value}" : $weight,
($fontFamily instanceof FontFamily) ? "fi-font-{$fontFamily->value}" : $fontFamily,
])
->merge($getExtraAttributes(), escape: false)
}}
>
{{ $content }}
</span>
@endif

View File

@@ -0,0 +1,14 @@
<ul
{{
$getExtraAttributeBag()->class([
'fi-sc-unordered-list',
(($size = $getSize()) instanceof \Filament\Support\Enums\TextSize) ? "fi-size-{$size->value}" : $size,
])
}}
>
@foreach ($getChildSchema()->getComponents() as $component)
<li>
{{ $component }}
</li>
@endforeach
</ul>

View File

@@ -0,0 +1,184 @@
@php
$isContained = $isContained();
$key = $getKey();
$previousAction = $getAction('previous');
$nextAction = $getAction('next');
$steps = $getChildSchema()->getComponents();
$isHeaderHidden = $isHeaderHidden();
@endphp
<div
x-load
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('wizard', 'filament/schemas') }}"
x-data="wizardSchemaComponent({
isSkippable: @js($isSkippable()),
isStepPersistedInQueryString: @js($isStepPersistedInQueryString()),
key: @js($key),
startStep: @js($getStartStep()),
stepQueryStringKey: @js($getStepQueryStringKey()),
})"
x-on:next-wizard-step.window="if ($event.detail.key === @js($key)) goToNextStep()"
wire:ignore.self
{{
$attributes
->merge([
'id' => $getId(),
], escape: false)
->merge($getExtraAttributes(), escape: false)
->merge($getExtraAlpineAttributes(), escape: false)
->class([
'fi-sc-wizard',
'fi-contained' => $isContained,
'fi-sc-wizard-header-hidden' => $isHeaderHidden,
])
}}
>
<input
type="hidden"
value="{{
collect($steps)
->filter(static fn (\Filament\Schemas\Components\Wizard\Step $step): bool => $step->isVisible())
->map(static fn (\Filament\Schemas\Components\Wizard\Step $step): ?string => $step->getKey())
->values()
->toJson()
}}"
x-ref="stepsData"
/>
@if (! $isHeaderHidden)
<ol
@if (filled($label = $getLabel()))
aria-label="{{ $label }}"
@endif
role="list"
x-cloak
x-ref="header"
class="fi-sc-wizard-header"
>
@foreach ($steps as $step)
<li
class="fi-sc-wizard-header-step"
x-bind:class="{
'fi-active': getStepIndex(step) === {{ $loop->index }},
'fi-completed': getStepIndex(step) > {{ $loop->index }},
}"
>
<button
type="button"
x-bind:aria-current="getStepIndex(step) === {{ $loop->index }} ? 'step' : null"
x-on:click="step = @js($step->getKey())"
x-bind:disabled="! isStepAccessible(@js($step->getKey())) || @js($previousAction->isDisabled())"
role="step"
class="fi-sc-wizard-header-step-btn"
>
<div class="fi-sc-wizard-header-step-icon-ctn">
@php
$completedIcon = $step->getCompletedIcon();
@endphp
{{
\Filament\Support\generate_icon_html(
$completedIcon ?? \Filament\Support\Icons\Heroicon::OutlinedCheck,
alias: filled($completedIcon) ? null : \Filament\Schemas\View\SchemaIconAlias::COMPONENTS_WIZARD_COMPLETED_STEP,
attributes: new \Illuminate\View\ComponentAttributeBag([
'x-cloak' => 'x-cloak',
'x-show' => "getStepIndex(step) > {$loop->index}",
]),
size: \Filament\Support\Enums\IconSize::Large,
)
}}
@if (filled($icon = $step->getIcon()))
{{
\Filament\Support\generate_icon_html(
$icon,
attributes: new \Illuminate\View\ComponentAttributeBag([
'x-cloak' => 'x-cloak',
'x-show' => "getStepIndex(step) <= {$loop->index}",
]),
size: \Filament\Support\Enums\IconSize::Large,
)
}}
@else
<span
x-show="getStepIndex(step) <= {{ $loop->index }}"
class="fi-sc-wizard-header-step-number"
>
{{ str_pad($loop->index + 1, 2, '0', STR_PAD_LEFT) }}
</span>
@endif
</div>
<div class="fi-sc-wizard-header-step-text">
@if (! $step->isLabelHidden())
<span class="fi-sc-wizard-header-step-label">
{{ $step->getLabel() }}
</span>
@endif
@if (filled($description = $step->getDescription()))
<span
class="fi-sc-wizard-header-step-description"
>
{{ $description }}
</span>
@endif
</div>
</button>
@if (! $loop->last)
<svg
fill="none"
preserveAspectRatio="none"
viewBox="0 0 22 80"
aria-hidden="true"
class="fi-sc-wizard-header-step-separator"
>
<path
d="M0 -2L20 40L0 82"
stroke-linejoin="round"
stroke="currentcolor"
vector-effect="non-scaling-stroke"
></path>
</svg>
@endif
</li>
@endforeach
</ol>
@endif
@foreach ($steps as $step)
{{ $step }}
@endforeach
<div x-cloak class="fi-sc-wizard-footer">
<div
x-cloak
@if (! $previousAction->isDisabled())
x-on:click="goToPreviousStep"
@endif
x-show="! isFirstStep()"
>
{{ $previousAction }}
</div>
<div x-show="isFirstStep()">
{{ $getCancelAction() }}
</div>
<div
x-cloak
@if (! $nextAction->isDisabled())
x-on:click="requestNextStep()"
@endif
x-bind:class="{ 'fi-hidden': isLastStep() }"
wire:loading.class="fi-disabled"
>
{{ $nextAction }}
</div>
<div x-bind:class="{ 'fi-hidden': ! isLastStep() }">
{{ $getSubmitAction() }}
</div>
</div>
</div>

View File

@@ -0,0 +1,43 @@
@php
$id = $getId();
$key = $getKey();
$wizard = $getContainer()->getParentComponent();
$isContained = $wizard->isContained();
$alpineSubmitHandler = $hasFormWrapper() ? $wizard->getAlpineSubmitHandler() : null;
@endphp
<{{ filled($alpineSubmitHandler) ? 'form' : 'div' }}
x-bind:tabindex="$el.querySelector('[autofocus]') ? '-1' : '0'"
x-bind:class="{
'fi-active': step === @js($key),
}"
x-on:expand="
if (! isStepAccessible(@js($key))) {
return
}
step = @js($key)
"
@if (filled($alpineSubmitHandler))
x-on:submit.prevent="isLastStep() ? {!! $alpineSubmitHandler !!} : requestNextStep()"
@endif
x-cloak
x-ref="step-{{ $key }}"
{{
$attributes
->merge([
'aria-labelledby' => $id,
'id' => $id,
'role' => 'tabpanel',
], escape: false)
->merge($getExtraAttributes(), escape: false)
->class(['fi-sc-wizard-step'])
}}
>
{{ $getChildSchema() }}
@if (filled($alpineSubmitHandler))
{{-- This is a hack to allow the form to submit when the user presses the enter key, even if there is no other submit button in the form. --}}
<input type="submit" hidden />
@endif
</{{ filled($alpineSubmitHandler) ? 'form' : 'div' }}>