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 @@
{!! value($html) !!}

View File

@@ -0,0 +1,19 @@
@if (isset($data))
<script>
window.filamentData = @js($data)
</script>
@endif
@foreach ($assets as $asset)
@if (! $asset->isLoadedOnRequest())
{{ $asset->getHtml() }}
@endif
@endforeach
<style>
:root {
@foreach ($cssVariables ?? [] as $cssVariableName => $cssVariableValue) --{{ $cssVariableName }}:{{ $cssVariableValue }}; @endforeach
}
@foreach ($customColors ?? [] as $customColorName => $customColorShades) .fi-color-{{ $customColorName }} { @foreach ($customColorShades as $customColorShade) --color-{{ $customColorShade }}:var(--{{ $customColorName }}-{{ $customColorShade }}); @endforeach } @endforeach
</style>

View File

@@ -0,0 +1,57 @@
@php
use Filament\Support\Enums\Alignment;
@endphp
@props([
'actions' => [],
'alignment' => Alignment::Start,
'fullWidth' => false,
])
@php
if (is_array($actions)) {
$actions = array_filter(
$actions,
fn ($action): bool => $action->isVisible(),
);
}
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
}
$hasActions = false;
$hasSlot = ! \Filament\Support\is_slot_empty($slot);
$actionsAreHtmlable = $actions instanceof \Illuminate\Contracts\Support\Htmlable;
if ($hasSlot) {
$hasActions = true;
} elseif ($actionsAreHtmlable) {
$hasActions = ! \Filament\Support\is_slot_empty($actions);
} else {
$hasActions = filled($actions);
}
@endphp
@if ($hasActions)
<div
{{
$attributes->class([
'fi-ac',
'fi-width-full' => $fullWidth,
($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : (is_string($alignment) ? $alignment : null) => ! $fullWidth,
])
}}
>
@if ($hasSlot)
{{ $slot }}
@elseif ($actionsAreHtmlable)
{{ $actions }}
@else
@foreach ($actions as $action)
{{ $action }}
@endforeach
@endif
</div>
@endif

View File

@@ -0,0 +1,18 @@
@props([
'circular' => true,
'size' => 'md',
])
<img
{{
$attributes
->class([
'fi-avatar',
'fi-circular' => $circular,
match ($size) {
'sm', 'md', 'lg' => "fi-size-{$size}",
default => $size,
},
])
}}
/>

View File

@@ -0,0 +1,182 @@
@php
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
use Filament\Support\Enums\Size;
use Filament\Support\View\Components\BadgeComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'color' => 'primary',
'deleteButton' => null,
'disabled' => false,
'form' => null,
'formId' => null,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconPosition' => IconPosition::Before,
'iconSize' => null,
'keyBindings' => null,
'loadingIndicator' => true,
'size' => Size::Medium,
'spaMode' => null,
'tag' => 'span',
'target' => null,
'tooltip' => null,
'type' => 'button',
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
if (! $size instanceof Size) {
$size = filled($size) ? (Size::tryFrom($size) ?? $size) : null;
}
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$isDeletable = count($deleteButton?->attributes->getAttributes() ?? []) > 0;
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget) || ($type === 'submit' && filled($form));
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
<{{ $tag }}
@if (($tag === 'a') && (! ($disabled && $hasTooltip)))
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->merge([
'aria-disabled' => $disabled ? 'true' : null,
'disabled' => $disabled && blank($tooltip),
'form' => $tag === 'button' ? $formId : null,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
], escape: false)
->when(
$disabled && $hasTooltip,
fn (ComponentAttributeBag $attributes) => $attributes->filter(
fn (mixed $value, string $key): bool => ! str($key)->startsWith(['href', 'x-on:', 'wire:click']),
),
)
->class([
'fi-badge',
'fi-disabled' => $disabled,
($size instanceof Size) ? "fi-size-{$size->value}" : (is_string($size) ? $size : ''),
])
->color(BadgeComponent::class, $color)
}}
>
@if ($iconPosition === IconPosition::Before)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize ?? \Filament\Support\Enums\IconSize::Small)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize ?? \Filament\Support\Enums\IconSize::Small)
}}
@endif
@endif
<span class="fi-badge-label-ctn">
<span class="fi-badge-label">
{{ $slot }}
</span>
</span>
@if ($isDeletable)
@php
$deleteButtonWireTarget = $deleteButton->attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first();
$deleteButtonHasLoadingIndicator = filled($deleteButtonWireTarget);
if ($deleteButtonHasLoadingIndicator) {
$deleteButtonLoadingIndicatorTarget = html_entity_decode($deleteButtonWireTarget, ENT_QUOTES);
}
@endphp
<button
type="button"
{{
$deleteButton->attributes
->except(['label'])
->class([
'fi-badge-delete-btn',
])
}}
>
{{
\Filament\Support\generate_icon_html(\Filament\Support\Icons\Heroicon::XMark, alias: \Filament\Support\View\SupportIconAlias::BADGE_DELETE_BUTTON, attributes: (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $deleteButtonHasLoadingIndicator,
'wire:target' => $deleteButtonHasLoadingIndicator ? $deleteButtonLoadingIndicatorTarget : false,
])), size: \Filament\Support\Enums\IconSize::ExtraSmall)
}}
@if ($deleteButtonHasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $deleteButtonLoadingIndicatorTarget,
])), size: \Filament\Support\Enums\IconSize::ExtraSmall)
}}
@endif
@if (filled($label = $deleteButton->attributes->get('label')))
<span class="fi-sr-only">
{{ $label }}
</span>
@endif
</button>
@elseif ($iconPosition === IconPosition::After)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize ?? \Filament\Support\Enums\IconSize::Small)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize ?? \Filament\Support\Enums\IconSize::Small)
}}
@endif
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,44 @@
@php
use Illuminate\View\ComponentAttributeBag;
use function Filament\Support\generate_icon_html;
@endphp
@props([
'breadcrumbs' => [],
])
<nav {{ $attributes->class(['fi-breadcrumbs']) }}>
<ol class="fi-breadcrumbs-list">
@foreach ($breadcrumbs as $url => $label)
<li class="fi-breadcrumbs-item">
@if (! $loop->first)
{{
generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronRight, alias: \Filament\Support\View\SupportIconAlias::BREADCRUMBS_SEPARATOR, attributes: (new ComponentAttributeBag)->class([
'fi-breadcrumbs-item-separator fi-ltr',
]))
}}
{{
generate_icon_html(\Filament\Support\Icons\Heroicon::ChevronLeft, alias: \Filament\Support\View\SupportIconAlias::BREADCRUMBS_SEPARATOR_RTL, attributes: (new ComponentAttributeBag)->class([
'fi-breadcrumbs-item-separator fi-rtl',
]))
}}
@endif
@if (is_int($url))
<span class="fi-breadcrumbs-item-label">
{{ $label }}
</span>
@else
<a
{{ \Filament\Support\generate_href_html($url) }}
class="fi-breadcrumbs-item-label"
>
{{ $label }}
</a>
@endif
</li>
@endforeach
</ol>
</nav>

View File

@@ -0,0 +1,3 @@
<div {{ $attributes->class(['fi-btn-group']) }}>
{{ $slot }}
</div>

View File

@@ -0,0 +1,237 @@
@php
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
use Filament\Support\Enums\Size;
use Filament\Support\View\Components\BadgeComponent;
use Filament\Support\View\Components\ButtonComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'badge' => null,
'badgeColor' => 'primary',
'badgeSize' => Size::ExtraSmall,
'color' => 'primary',
'disabled' => false,
'form' => null,
'formId' => null,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconPosition' => IconPosition::Before,
'iconSize' => null,
'keyBindings' => null,
'labeledFrom' => null,
'labelSrOnly' => false,
'loadingIndicator' => true,
'outlined' => false,
'size' => Size::Medium,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'tooltip' => null,
'type' => 'button',
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
if (! $size instanceof Size) {
$size = filled($size) ? (Size::tryFrom($size) ?? $size) : null;
}
if (! $badgeSize instanceof Size) {
$badgeSize = filled($badgeSize) ? (Size::tryFrom($badgeSize) ?? $badgeSize) : null;
}
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$iconSize ??= match ($size) {
Size::ExtraSmall, Size::Small => IconSize::Small,
default => null,
};
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasFormProcessingLoadingIndicator = $type === 'submit' && filled($form);
$hasLoadingIndicator = filled($wireTarget) || $hasFormProcessingLoadingIndicator;
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
@if ($labeledFrom)
<x-filament::icon-button
:badge="$badge"
:badge-color="$badgeColor"
:badge-size="$badgeSize"
:color="$color"
:disabled="$disabled"
:form="$form"
:form-id="$formId"
:href="$href"
:icon="$icon"
:icon-alias="$iconAlias"
:icon-size="$iconSize"
:key-bindings="$keyBindings"
:label="$slot"
:loading-indicator="$loadingIndicator"
:size="$size"
:spa-mode="$spaMode"
:tag="$tag"
:target="$target"
:tooltip="$tooltip"
:type="$type"
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)"
/>
@endif
<{{ $tag }}
@if (($tag === 'a') && (! ($disabled && $hasTooltip)))
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
@if ($hasFormProcessingLoadingIndicator)
x-data="filamentFormButton"
x-bind:class="{ 'fi-processing': isProcessing }"
@endif
{{
$attributes
->merge([
'aria-disabled' => $disabled ? 'true' : null,
'aria-label' => $labelSrOnly ? trim(strip_tags($slot->toHtml())) : null,
'disabled' => $disabled && blank($tooltip),
'form' => $formId,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
'x-bind:disabled' => $hasFormProcessingLoadingIndicator ? 'isProcessing' : null,
'x-bind:aria-label' => ($labelSrOnly && $hasFormProcessingLoadingIndicator) ? ('isProcessing ? processingMessage : ' . \Illuminate\Support\Js::from(trim(strip_tags($slot->toHtml())))) : null,
], escape: false)
->when(
$disabled && $hasTooltip,
fn (ComponentAttributeBag $attributes) => $attributes->filter(
fn (mixed $value, string $key): bool => ! str($key)->startsWith(['href', 'x-on:', 'wire:click']),
),
)
->class([
'fi-btn',
'fi-disabled' => $disabled,
'fi-outlined' => $outlined,
($size instanceof Size) ? "fi-size-{$size->value}" : (is_string($size) ? $size : ''),
is_string($labeledFrom) ? "fi-labeled-from-{$labeledFrom}" : null,
])
->color(app(ButtonComponent::class, ['isOutlined' => $outlined]), $color)
}}
>
@if ($iconPosition === IconPosition::Before)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize)
}}
@endif
@if ($hasFormProcessingLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'x-cloak' => 'x-cloak',
'x-show' => 'isProcessing',
])), size: $iconSize)
}}
@endif
@endif
@if (! $labelSrOnly)
@if ($hasFormProcessingLoadingIndicator)
<span x-show="! isProcessing">
{{ $slot }}
</span>
@else
{{ $slot }}
@endif
@endif
@if ($hasFormProcessingLoadingIndicator && (! $labelSrOnly))
<span
x-cloak
x-show="isProcessing"
x-text="processingMessage"
></span>
@endif
@if ($iconPosition === IconPosition::After)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize)
}}
@endif
@if ($hasFormProcessingLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'x-cloak' => 'x-cloak',
'x-show' => 'isProcessing',
])), size: $iconSize)
}}
@endif
@endif
@if (filled($badge))
<div class="fi-btn-badge-ctn">
@if ($badge instanceof \Illuminate\View\ComponentSlot)
{{ $badge }}
@else
<span
{{
(new ComponentAttributeBag)->color(BadgeComponent::class, $badgeColor)->class([
'fi-badge',
($badgeSize instanceof Size) ? "fi-size-{$badgeSize->value}" : (is_string($badgeSize) ? $badgeSize : ''),
])
}}
>
{{ $badge }}
</span>
@endif
</div>
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,5 @@
<x-filament::section
:attributes="\Filament\Support\prepare_inherited_attributes($attributes)"
>
{{ $slot }}
</x-filament::section>

View File

@@ -0,0 +1,34 @@
@php
use Filament\Support\Enums\IconSize;
use Filament\Support\View\Components\DropdownComponent\HeaderComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'color' => 'gray',
'icon' => null,
'iconSize' => null,
'tag' => 'div',
])
@php
if (! ($iconSize instanceof IconSize)) {
$iconSize = filled($iconSize) ? (IconSize::tryFrom($iconSize) ?? $iconSize) : null;
}
@endphp
<{{ $tag }}
{{
$attributes
->class([
'fi-dropdown-header',
])
->color(HeaderComponent::class, $color)
}}
>
{{ \Filament\Support\generate_icon_html($icon, size: $iconSize) }}
<span>
{{ $slot }}
</span>
</{{ $tag }}>

View File

@@ -0,0 +1,64 @@
@props([
'availableHeight' => null,
'availableWidth' => null,
'flip' => true,
'maxHeight' => null,
'offset' => 8,
'placement' => null,
'shift' => false,
'size' => false,
'sizePadding' => 16,
'teleport' => false,
'trigger' => null,
'width' => null,
])
@php
use Filament\Support\Enums\Width;
$sizeConfig = collect([
'availableHeight' => $availableHeight,
'availableWidth' => $availableWidth,
'padding' => $sizePadding,
])->filter()->toJson();
if (is_string($width)) {
$width = Width::tryFrom($width) ?? $width;
}
@endphp
<div
x-data="filamentDropdown"
{{ $attributes->class(['fi-dropdown']) }}
>
<div
x-on:mousedown="if ($event.button === 0) toggle($event)"
{{ $trigger->attributes->class(['fi-dropdown-trigger']) }}
>
{{ $trigger }}
</div>
@if (! \Filament\Support\is_slot_empty($slot))
<div
x-cloak
x-float{{ $placement ? ".placement.{$placement}" : '' }}{{ $size ? '.size' : '' }}{{ $flip ? '.flip' : '' }}{{ $shift ? '.shift' : '' }}{{ $teleport ? '.teleport' : '' }}{{ $offset ? '.offset' : '' }}="{ offset: {{ $offset }}, {{ $size ? ('size: ' . $sizeConfig) : '' }} }"
x-ref="panel"
x-transition:enter-start="fi-opacity-0"
x-transition:leave-end="fi-opacity-0"
@if ($attributes->has('wire:key'))
wire:ignore.self
wire:key="{{ $attributes->get('wire:key') }}.panel"
@endif
@class([
'fi-dropdown-panel',
($width instanceof Width) ? "fi-width-{$width->value}" : (is_string($width) ? $width : ''),
'fi-scrollable' => $maxHeight || $size,
])
@style([
"max-height: {$maxHeight}" => $maxHeight,
])
>
{{ $slot }}
</div>
@endif
</div>

View File

@@ -0,0 +1,3 @@
<div {{ $attributes->class(['fi-dropdown-list']) }}>
{{ $slot }}
</div>

View File

@@ -0,0 +1,150 @@
@php
use Filament\Support\Enums\IconSize;
use Filament\Support\Enums\Size;
use Filament\Support\View\Components\BadgeComponent;
use Filament\Support\View\Components\DropdownComponent\ItemComponent;
use Filament\Support\View\Components\DropdownComponent\ItemComponent\IconComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'badge' => null,
'badgeColor' => 'primary',
'badgeTooltip' => null,
'color' => 'gray',
'disabled' => false,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconColor' => null,
'iconSize' => null,
'image' => null,
'keyBindings' => null,
'loadingIndicator' => true,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'tooltip' => null,
])
@php
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$iconColor ??= $color;
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget);
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
{!! ($tag === 'form') ? ('<form ' . $attributes->only(['action', 'class', 'method', 'wire:submit'])->toHtml() . '>') : '' !!}
@if ($tag === 'form')
@csrf
@endif
<{{ ($tag === 'form') ? 'button' : $tag }}
@if (($tag === 'a') && (! ($disabled && $hasTooltip)))
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->when(
$tag === 'form',
fn (ComponentAttributeBag $attributes) => $attributes->except(['action', 'class', 'method', 'wire:submit']),
)
->merge([
'aria-disabled' => $disabled ? 'true' : null,
'disabled' => $disabled && blank($tooltip),
'type' => match ($tag) {
'button' => 'button',
'form' => 'submit',
default => null,
},
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
], escape: false)
->when(
$disabled && $hasTooltip,
fn (ComponentAttributeBag $attributes) => $attributes->filter(
fn (mixed $value, string $key): bool => ! str($key)->startsWith(['href', 'x-on:', 'wire:click']),
),
)
->class([
'fi-dropdown-list-item',
'fi-disabled' => $disabled,
])
->color(ItemComponent::class, $color)
}}
>
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
]))->color(IconComponent::class, $iconColor), size: $iconSize)
}}
@endif
@if ($image)
<div
class="fi-dropdown-list-item-image"
style="background-image: url('{{ $image }}')"
@if ($hasLoadingIndicator)
wire:loading.remove.delay.{{ config('filament.livewire_loading_delay', 'default') }}
wire:target="{{ $loadingIndicatorTarget }}"
@endif
></div>
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
]))->color(IconComponent::class, $iconColor), size: $iconSize)
}}
@endif
<span class="fi-dropdown-list-item-label">
{{ $slot }}
</span>
@if (filled($badge))
@if ($badge instanceof \Illuminate\View\ComponentSlot)
{{ $badge }}
@else
<span
@if ($badgeTooltip)
x-tooltip="{
content: @js($badgeTooltip),
theme: $store.theme,
}"
@endif
{{ (new ComponentAttributeBag)->color(BadgeComponent::class, $badgeColor)->class(['fi-badge']) }}
>
{{ $badge }}
</span>
@endif
@endif
</{{ ($tag === 'form') ? 'button' : $tag }}>
{!! ($tag === 'form') ? '</form>' : '' !!}

View File

@@ -0,0 +1,61 @@
@php
use Filament\Support\Enums\IconSize;
use Filament\Support\View\Components\SectionComponent\IconComponent;
@endphp
@props([
'description' => null,
'footer' => null,
'heading',
'headingTag' => 'h2',
'icon' => null,
'iconColor' => 'primary',
'iconSize' => null,
])
@php
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$hasDescription = filled((string) $description);
$hasIcon = filled($icon);
@endphp
<section
{{
$attributes->class([
'fi-empty-state',
])
}}
>
<div class="fi-empty-state-content">
@if ($hasIcon)
<div
@class([
'fi-empty-state-icon-bg',
'fi-color ' . ('fi-color-' . $iconColor) => $iconColor !== 'gray',
])
>
{{
\Filament\Support\generate_icon_html($icon, attributes: (new \Illuminate\View\ComponentAttributeBag)
->color(IconComponent::class, $iconColor), size: $iconSize ?? IconSize::Large)
}}
</div>
@endif
<{{ $headingTag }} class="fi-empty-state-heading">
{{ $heading }}
</{{ $headingTag }}>
@if ($hasDescription)
<p class="fi-empty-state-description">
{{ $description }}
</p>
@endif
<footer class="fi-empty-state-footer">
{{ $footer }}
</footer>
</div>
</section>

View File

@@ -0,0 +1,25 @@
@props([
'contained' => true,
'label' => null,
'labelHidden' => false,
'required' => false,
])
<fieldset
{{
$attributes->class([
'fi-fieldset',
'fi-fieldset-label-hidden' => $labelHidden,
'fi-fieldset-not-contained' => ! $contained,
])
}}
>
@if (filled($label))
<legend>
{{ $label }}@if ($required)<sup class="fi-fieldset-label-required-mark">*</sup>
@endif
</legend>
@endif
{{ $slot }}
</fieldset>

View File

@@ -0,0 +1,138 @@
@php
use Filament\Support\Enums\IconSize;
use Filament\Support\Enums\Size;
use Filament\Support\View\Components\BadgeComponent;
use Filament\Support\View\Components\IconButtonComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'badge' => null,
'badgeColor' => 'primary',
'badgeSize' => Size::ExtraSmall,
'color' => 'primary',
'disabled' => false,
'form' => null,
'formId' => null,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconSize' => null,
'keyBindings' => null,
'label' => null,
'loadingIndicator' => true,
'size' => Size::Medium,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'tooltip' => null,
'type' => 'button',
])
@php
if (! $size instanceof Size) {
$size = filled($size) ? (Size::tryFrom($size) ?? $size) : null;
}
if (! $badgeSize instanceof Size) {
$badgeSize = filled($badgeSize) ? (Size::tryFrom($badgeSize) ?? $badgeSize) : null;
}
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$iconSize ??= match ($size) {
Size::ExtraSmall => IconSize::Small,
Size::Large, Size::ExtraLarge => IconSize::Large,
default => null,
};
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget) || ($type === 'submit' && filled($form));
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = $hasTooltip = filled($tooltip);
@endphp
<{{ $tag }}
@if (($tag === 'a') && (! ($disabled && $hasTooltip)))
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->merge([
'aria-disabled' => $disabled ? 'true' : null,
'aria-label' => $label,
'disabled' => $disabled && blank($tooltip),
'form' => $formId,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
], escape: false)
->merge([
'title' => $hasTooltip ? null : $label,
], escape: true)
->when(
$disabled && $hasTooltip,
fn (ComponentAttributeBag $attributes) => $attributes->filter(
fn (mixed $value, string $key): bool => ! str($key)->startsWith(['href', 'x-on:', 'wire:click']),
),
)
->class([
'fi-icon-btn',
'fi-disabled' => $disabled,
($size instanceof Size) ? "fi-size-{$size->value}" : (is_string($size) ? $size : ''),
])
->color(IconButtonComponent::class, $color)
}}
>
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize)
}}
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize)
}}
@endif
@if (filled($badge))
<div class="fi-icon-btn-badge-ctn">
@if ($badge instanceof \Illuminate\View\ComponentSlot)
{{ $badge }}
@else
<span
{{
(new ComponentAttributeBag)->color(BadgeComponent::class, $badgeColor)->class([
'fi-badge',
($badgeSize instanceof Size) ? "fi-size-{$badgeSize->value}" : (is_string($badgeSize) ? $badgeSize : ''),
])
}}
>
{{ $badge }}
</span>
@endif
</div>
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,7 @@
@props([
'alias' => null,
'icon' => null,
'size' => null,
])
{{ \Filament\Support\generate_icon_html($icon, $alias, $attributes, $size) }}

View File

@@ -0,0 +1,26 @@
@props([
'alpineValid' => null,
'valid' => true,
])
@php
$hasAlpineValidClasses = filled($alpineValid);
@endphp
<input
type="checkbox"
@if ($hasAlpineValidClasses)
x-bind:class="{
'fi-valid': {{ $alpineValid }},
'fi-invalid': {{ "(! {$alpineValid})" }},
}"
@endif
{{
$attributes
->class([
'fi-checkbox-input',
'fi-valid' => (! $hasAlpineValidClasses) && $valid,
'fi-invalid' => (! $hasAlpineValidClasses) && (! $valid),
])
}}
/>

View File

@@ -0,0 +1,14 @@
@props([
'inlinePrefix' => false,
'inlineSuffix' => false,
])
<input
{{
$attributes->class([
'fi-input',
'fi-input-has-inline-prefix' => $inlinePrefix,
'fi-input-has-inline-suffix' => $inlineSuffix,
])
}}
/>

View File

@@ -0,0 +1,42 @@
@props([
'length' => 6,
])
<div
x-data="{ currentNumberOfDigits: null }"
{{
$attributes
->class([
'fi-one-time-code-input-ctn',
])
}}
>
@foreach (range(1, $length) as $digit)
<div
x-bind:class="{
'fi-active':
currentNumberOfDigits !== null &&
currentNumberOfDigits >= {{ $digit }},
}"
class="fi-one-time-code-input-digit-field"
></div>
@endforeach
<input
autocomplete="one-time-code"
inputmode="numeric"
minlength="{{ $length }}"
maxlength="{{ $length }}"
pattern="\d{{ '{' . $length . '}' }}"
type="text"
x-data="{}"
x-on:focus="currentNumberOfDigits = $el.value.length"
x-on:blur="currentNumberOfDigits = null"
x-on:input="
$el.value = $el.value.replace(/\D/g, '')
currentNumberOfDigits = $el.value.length
"
x-bind:class="{ 'fi-valid': currentNumberOfDigits >= {{ $length }} }"
class="fi-one-time-code-input"
/>
</div>

View File

@@ -0,0 +1,14 @@
@props([
'valid' => true,
])
<input
type="radio"
{{
$attributes
->class([
'fi-radio-input',
'fi-invalid' => ! $valid,
])
}}
/>

View File

@@ -0,0 +1,15 @@
@props([
'inlinePrefix' => false,
'inlineSuffix' => false,
])
<select
{{
$attributes->class([
'fi-select-input',
'fi-select-input-has-inline-prefix' => $inlinePrefix,
])
}}
>
{{ $slot }}
</select>

View File

@@ -0,0 +1,163 @@
@props([
'alpineDisabled' => null,
'alpineValid' => null,
'disabled' => false,
'inlinePrefix' => false,
'inlineSuffix' => false,
'prefix' => null,
'prefixActions' => [],
'prefixIcon' => null,
'prefixIconColor' => 'gray',
'prefixIconAlias' => null,
'suffix' => null,
'suffixActions' => [],
'suffixIcon' => null,
'suffixIconColor' => 'gray',
'suffixIconAlias' => null,
'valid' => true,
])
@php
use Filament\Support\View\Components\InputComponent\WrapperComponent\IconComponent;
use Illuminate\View\ComponentAttributeBag;
$prefixActions = array_filter(
$prefixActions,
fn (\Filament\Actions\Action $prefixAction): bool => $prefixAction->isVisible(),
);
$suffixActions = array_filter(
$suffixActions,
fn (\Filament\Actions\Action $suffixAction): bool => $suffixAction->isVisible(),
);
$hasPrefix = count($prefixActions) || $prefixIcon || filled($prefix);
$hasSuffix = count($suffixActions) || $suffixIcon || filled($suffix);
$hasAlpineDisabledClasses = filled($alpineDisabled);
$hasAlpineValidClasses = filled($alpineValid);
$hasAlpineClasses = $hasAlpineDisabledClasses || $hasAlpineValidClasses;
$wireTarget = $attributes->whereStartsWith(['wire:target'])->first();
$hasLoadingIndicator = filled($wireTarget);
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget, ENT_QUOTES);
}
@endphp
<div
@if ($hasAlpineClasses)
x-bind:class="{
{{ $hasAlpineDisabledClasses ? "'fi-disabled': {$alpineDisabled}," : null }}
{{ $hasAlpineValidClasses ? "'fi-invalid': ! ({$alpineValid})," : null }}
}"
@endif
{{
$attributes
->except(['wire:target', 'tabindex'])
->class([
'fi-input-wrp',
'fi-disabled' => (! $hasAlpineClasses) && $disabled,
'fi-invalid' => (! $hasAlpineClasses) && (! $valid),
])
}}
>
@if ($hasPrefix || $hasLoadingIndicator)
<div
@if (! $hasPrefix)
wire:loading.delay.{{ config('filament.livewire_loading_delay', 'default') }}.flex
wire:target="{{ $loadingIndicatorTarget }}"
wire:key="{{ \Illuminate\Support\Str::random() }}" {{-- Makes sure the loading indicator gets hidden again. --}}
@endif
@class([
'fi-input-wrp-prefix',
'fi-input-wrp-prefix-has-content' => $hasPrefix,
'fi-inline' => $inlinePrefix,
'fi-input-wrp-prefix-has-label' => filled($prefix),
])
>
@if (count($prefixActions))
<div class="fi-input-wrp-actions">
@foreach ($prefixActions as $prefixAction)
{{ $prefixAction }}
@endforeach
</div>
@endif
{{
\Filament\Support\generate_icon_html($prefixIcon, $prefixIconAlias, (new \Illuminate\View\ComponentAttributeBag)
->merge([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
], escape: false)
->color(IconComponent::class, $prefixIconColor))
}}
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => $hasPrefix,
'wire:target' => $hasPrefix ? $loadingIndicatorTarget : null,
]))->color(IconComponent::class, 'gray'))
}}
@endif
@if (filled($prefix))
<span class="fi-input-wrp-label">
{{ $prefix }}
</span>
@endif
</div>
@endif
<div
@if ($hasLoadingIndicator && (! $hasPrefix))
@if ($inlinePrefix)
wire:loading.delay.{{ config('filament.livewire_loading_delay', 'default') }}.class.remove="ps-3"
@endif
wire:target="{{ $loadingIndicatorTarget }}"
@endif
@class([
'fi-input-wrp-content-ctn',
'fi-input-wrp-content-ctn-ps' => $hasLoadingIndicator && (! $hasPrefix) && $inlinePrefix,
])
>
{{ $slot }}
</div>
@if ($hasSuffix)
<div
@class([
'fi-input-wrp-suffix',
'fi-inline' => $inlineSuffix,
'fi-input-wrp-suffix-has-label' => filled($suffix),
])
>
@if (filled($suffix))
<span class="fi-input-wrp-label">
{{ $suffix }}
</span>
@endif
{{
\Filament\Support\generate_icon_html($suffixIcon, $suffixIconAlias, (new \Illuminate\View\ComponentAttributeBag)
->merge([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
], escape: false)
->color(IconComponent::class, $suffixIconColor))
}}
@if (count($suffixActions))
<div class="fi-input-wrp-actions">
@foreach ($suffixActions as $suffixAction)
{{ $suffixAction }}
@endforeach
</div>
@endif
</div>
@endif
</div>

View File

@@ -0,0 +1,175 @@
@php
use Filament\Support\Enums\FontWeight;
use Filament\Support\Enums\IconPosition;
use Filament\Support\Enums\IconSize;
use Filament\Support\Enums\Size;
use Filament\Support\View\Components\BadgeComponent;
use Filament\Support\View\Components\LinkComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'badge' => null,
'badgeColor' => 'primary',
'badgeSize' => Size::ExtraSmall,
'color' => 'primary',
'disabled' => false,
'form' => null,
'formId' => null,
'href' => null,
'icon' => null,
'iconAlias' => null,
'iconPosition' => IconPosition::Before,
'iconSize' => null,
'keyBindings' => null,
'labelSrOnly' => false,
'loadingIndicator' => true,
'size' => Size::Medium,
'spaMode' => null,
'tag' => 'a',
'target' => null,
'tooltip' => null,
'type' => 'button',
'weight' => null,
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
if (! $badgeSize instanceof Size) {
$badgeSize = filled($badgeSize) ? (Size::tryFrom($badgeSize) ?? $badgeSize) : null;
}
if (! $size instanceof Size) {
$size = filled($size) ? (Size::tryFrom($size) ?? $size) : null;
}
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$iconSize ??= match ($size) {
Size::ExtraSmall, Size::Small => IconSize::Small,
default => null,
};
if (! $weight instanceof FontWeight) {
$weight = filled($weight) ? (FontWeight::tryFrom($weight) ?? $weight) : null;
}
$wireTarget = $loadingIndicator ? $attributes->whereStartsWith(['wire:target', 'wire:click'])->filter(fn ($value): bool => filled($value))->first() : null;
$hasLoadingIndicator = filled($wireTarget) || ($type === 'submit' && filled($form));
if ($hasLoadingIndicator) {
$loadingIndicatorTarget = html_entity_decode($wireTarget ?: $form, ENT_QUOTES);
}
$hasTooltip = filled($tooltip);
@endphp
<{{ $tag }}
@if (($tag === 'a') && (! ($disabled && $hasTooltip)))
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($keyBindings)
x-bind:id="$id('key-bindings')"
x-mousetrap.global.{{ collect($keyBindings)->map(fn (string $keyBinding): string => str_replace('+', '-', $keyBinding))->implode('.') }}="document.getElementById($el.id).click()"
@endif
@if ($hasTooltip)
x-tooltip="{
content: @js($tooltip),
theme: $store.theme,
}"
@endif
{{
$attributes
->merge([
'aria-disabled' => $disabled ? 'true' : null,
'disabled' => $disabled && blank($tooltip),
'form' => $formId,
'type' => $tag === 'button' ? $type : null,
'wire:loading.attr' => $tag === 'button' ? 'disabled' : null,
'wire:target' => ($hasLoadingIndicator && $loadingIndicatorTarget) ? $loadingIndicatorTarget : null,
], escape: false)
->when(
$disabled && $hasTooltip,
fn (ComponentAttributeBag $attributes) => $attributes->filter(
fn (mixed $value, string $key): bool => ! str($key)->startsWith(['href', 'x-on:', 'wire:click']),
),
)
->class([
'fi-link',
'fi-disabled' => $disabled,
($size instanceof Size) ? "fi-size-{$size->value}" : (is_string($size) ? $size : ''),
($weight instanceof FontWeight) ? "fi-font-{$weight->value}" : (is_string($weight) ? $weight : ''),
])
->color(LinkComponent::class, $color)
}}
>
@if ($iconPosition === IconPosition::Before)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize)
}}
@endif
@endif
@if (! $labelSrOnly)
{{ $slot }}
@endif
@if ($iconPosition === IconPosition::After)
@if ($icon)
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, (new \Illuminate\View\ComponentAttributeBag([
'wire:loading.remove.delay.' . config('filament.livewire_loading_delay', 'default') => $hasLoadingIndicator,
'wire:target' => $hasLoadingIndicator ? $loadingIndicatorTarget : false,
])), size: $iconSize)
}}
@endif
@if ($hasLoadingIndicator)
{{
\Filament\Support\generate_loading_indicator_html((new \Illuminate\View\ComponentAttributeBag([
'wire:loading.delay.' . config('filament.livewire_loading_delay', 'default') => '',
'wire:target' => $loadingIndicatorTarget,
])), size: $iconSize)
}}
@endif
@endif
@if (filled($badge))
<div class="fi-link-badge-ctn">
@if ($badge instanceof \Illuminate\View\ComponentSlot)
{{ $badge }}
@else
<span
{{
(new ComponentAttributeBag)->color(BadgeComponent::class, $badgeColor)->class([
'fi-badge',
($badgeSize instanceof Size) ? "fi-size-{$badgeSize->value}" : (is_string($badgeSize) ? $badgeSize : ''),
])
}}
>
{{ $badge }}
</span>
@endif
</div>
@endif
</{{ $tag }}>
@trim

View File

@@ -0,0 +1 @@
{{ \Filament\Support\generate_loading_indicator_html($attributes) }}

View File

@@ -0,0 +1,14 @@
@props([
'columnSpan' => [],
'columnStart' => [],
'height' => null,
])
<div
{{
($attributes ?? new \Illuminate\View\ComponentAttributeBag)
->gridColumn($columnSpan, $columnStart)
->class(['fi-section fi-loading-section'])
->style(['height: ' . ($height ?? '8rem')])
}}
></div>

View File

@@ -0,0 +1,5 @@
<p
{{ $attributes->class(['fi-modal-description']) }}
>
{{ $slot }}
</p>

View File

@@ -0,0 +1,5 @@
<h2
{{ $attributes->class(['fi-modal-heading']) }}
>
{{ $slot }}
</h2>

View File

@@ -0,0 +1,273 @@
@php
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\Width;
use Filament\Support\View\Components\ModalComponent\IconComponent;
use Illuminate\View\ComponentAttributeBag;
@endphp
@props([
'alignment' => Alignment::Start,
'ariaLabelledby' => null,
'autofocus' => \Filament\Support\View\Components\ModalComponent::$isAutofocused,
'closeButton' => \Filament\Support\View\Components\ModalComponent::$hasCloseButton,
'closeByClickingAway' => \Filament\Support\View\Components\ModalComponent::$isClosedByClickingAway,
'closeByEscaping' => \Filament\Support\View\Components\ModalComponent::$isClosedByEscaping,
'closeEventName' => 'close-modal',
'closeQuietlyEventName' => 'close-modal-quietly',
'description' => null,
'extraModalWindowAttributeBag' => null,
'footer' => null,
'footerActions' => [],
'footerActionsAlignment' => Alignment::Start,
'header' => null,
'heading' => null,
'icon' => null,
'iconAlias' => null,
'iconColor' => 'primary',
'id' => null,
'openEventName' => 'open-modal',
'slideOver' => false,
'stickyFooter' => false,
'stickyHeader' => false,
'teleport' => null,
'trigger' => null,
'visible' => true,
'width' => 'sm',
])
@php
$hasContent = ! \Filament\Support\is_slot_empty($slot);
$hasDescription = filled($description);
$hasFooter = (! \Filament\Support\is_slot_empty($footer)) || (is_array($footerActions) && count($footerActions)) || (! is_array($footerActions) && (! \Filament\Support\is_slot_empty($footerActions)));
$hasHeading = filled($heading);
$hasIcon = filled($icon);
if (! $alignment instanceof Alignment) {
$alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
}
if (! $footerActionsAlignment instanceof Alignment) {
$footerActionsAlignment = filled($footerActionsAlignment) ? (Alignment::tryFrom($footerActionsAlignment) ?? $footerActionsAlignment) : null;
}
if (is_string($width)) {
$width = Width::tryFrom($width) ?? $width;
}
$closeEventHandler = filled($id) ? '$dispatch(' . \Illuminate\Support\Js::from($closeEventName) . ', { id: ' . \Illuminate\Support\Js::from($id) . ' })' : 'close()';
$wireSubmitHandler = $attributes->get('wire:submit.prevent');
$attributes = $attributes->except(['wire:submit.prevent']);
@endphp
@if ($trigger)
{!! '<div>' !!}
{{-- Avoid formatting issues with unclosed elements --}}
<div
@if (! $trigger->attributes->get('disabled'))
@if ($id)
x-on:click="$dispatch(@js($openEventName), { id: @js($id) })"
@else
x-on:click="$el.nextElementSibling.dispatchEvent(new CustomEvent(@js($openEventName)))"
@endif
@endif
{{ $trigger->attributes->except(['disabled'])->class(['fi-modal-trigger']) }}
>
{{ $trigger }}
</div>
@endif
@if (filled($teleport))
{!! "<template x-teleport=\"{$teleport}\">" !!}
{{-- Avoid formatting issues with unclosed elements --}}
@endif
<div
@if ($ariaLabelledby)
aria-labelledby="{{ $ariaLabelledby }}"
@elseif ($heading)
aria-labelledby="{{ "{$id}.heading" }}"
@endif
aria-modal="true"
id="{{ $id }}"
role="dialog"
x-data="filamentModal({
id: @js($id),
})"
@if ($id)
data-fi-modal-id="{{ $id }}"
x-on:{{ $closeEventName }}.window="if (($event.detail.id === @js($id)) && isOpen) close()"
x-on:{{ $closeQuietlyEventName }}.window="if (($event.detail.id === @js($id)) && isOpen) closeQuietly()"
x-on:{{ $openEventName }}.window="if (($event.detail.id === @js($id)) && (! isOpen)) open()"
@else
x-on:{{ $closeEventName }}.stop="if (isOpen) close()"
x-on:{{ $closeQuietlyEventName }}.stop="if (isOpen) closeQuietly()"
x-on:{{ $openEventName }}.stop="if (! isOpen) open()"
@endif
x-bind:class="{
'fi-modal-open': isOpen,
}"
x-cloak
x-show="isOpen"
x-trap.noscroll{{ $autofocus ? '' : '.noautofocus' }}="isOpen"
{{
$attributes->class([
'fi-modal',
'fi-absolute-positioning-context',
'fi-modal-slide-over' => $slideOver,
'fi-width-screen' => $width === Width::Screen,
])
}}
>
<div
aria-hidden="true"
x-show="isOpen"
x-transition.duration.300ms.opacity
class="fi-modal-close-overlay"
></div>
<div
@if ($closeByClickingAway)
x-on:click.self="{{ $closeEventHandler }}"
@endif
@class([
'fi-modal-window-ctn',
'fi-clickable' => $closeByClickingAway,
])
>
<{{ filled($wireSubmitHandler) ? 'form' : 'div' }}
@if ($closeByEscaping)
x-on:keydown.window.escape="{{ $closeEventHandler }}"
@endif
x-show="isWindowVisible"
x-transition:enter="fi-transition-enter"
x-transition:leave="fi-transition-leave"
@if ($width !== Width::Screen)
x-transition:enter-start="fi-transition-enter-start"
x-transition:enter-end="fi-transition-enter-end"
x-transition:leave-start="fi-transition-leave-start"
x-transition:leave-end="fi-transition-leave-end"
@endif
@if (filled($wireSubmitHandler))
wire:submit.prevent="{!! $wireSubmitHandler !!}"
@endif
@if (filled($id))
wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.window"
@endif
{{
($extraModalWindowAttributeBag ?? new \Illuminate\View\ComponentAttributeBag)->class([
'fi-modal-window',
'fi-modal-window-has-close-btn' => $closeButton,
'fi-modal-window-has-content' => $hasContent,
'fi-modal-window-has-footer' => $hasFooter,
'fi-modal-window-has-icon' => $hasIcon,
'fi-modal-window-has-sticky-header' => $stickyHeader,
'fi-hidden' => ! $visible,
($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : null,
($width instanceof Width) ? "fi-width-{$width->value}" : (is_string($width) ? $width : null),
])
}}
>
@if ($heading || $header)
<div
@if (filled($id))
wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.header"
@endif
@class([
'fi-modal-header',
'fi-sticky' => $stickyHeader,
'fi-vertical-align-center' => $hasIcon && $hasHeading && (! $hasDescription) && in_array($alignment, [Alignment::Start, Alignment::Left]),
])
>
@if ($closeButton)
<x-filament::icon-button
color="gray"
:icon="\Filament\Support\Icons\Heroicon::OutlinedXMark"
:icon-alias="\Filament\Support\View\SupportIconAlias::MODAL_CLOSE_BUTTON"
icon-size="lg"
:label="__('filament::components/modal.actions.close.label')"
tabindex="-1"
:x-on:click="$closeEventHandler"
class="fi-modal-close-btn"
/>
@endif
@if ($header)
{{ $header }}
@else
@if ($hasIcon)
<div class="fi-modal-icon-ctn">
<div
{{ (new ComponentAttributeBag)->color(IconComponent::class, $iconColor)->class(['fi-modal-icon-bg']) }}
>
{{ \Filament\Support\generate_icon_html($icon, $iconAlias, size: \Filament\Support\Enums\IconSize::Large) }}
</div>
</div>
@endif
<div>
<h2 class="fi-modal-heading">
{{ $heading }}
</h2>
@if ($hasDescription)
<p class="fi-modal-description">
{{ $description }}
</p>
@endif
</div>
@endif
</div>
@endif
@if ($hasContent)
<div
@if (filled($id))
wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.content"
@endif
class="fi-modal-content"
>
{{ $slot }}
</div>
@endif
@if ($hasFooter)
<div
@if (filled($id))
wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.footer"
@endif
@class([
'fi-modal-footer',
'fi-sticky' => $stickyFooter,
($footerActionsAlignment instanceof Alignment) ? "fi-align-{$footerActionsAlignment->value}" : null,
])
>
@if (! \Filament\Support\is_slot_empty($footer))
{{ $footer }}
@else
<div class="fi-modal-footer-actions">
@if (is_array($footerActions))
@foreach ($footerActions as $action)
{{ $action }}
@endforeach
@else
{{ $footerActions }}
@endif
</div>
@endif
</div>
@endif
</{{ filled($wireSubmitHandler) ? 'form' : 'div' }}>
</div>
</div>
@if (filled($teleport))
{!! '</template>' !!}
{{-- Avoid formatting issues with unclosed elements --}}
@endif
@if ($trigger)
{!! '</div>' !!}
{{-- Avoid formatting issues with unclosed elements --}}
@endif

View File

@@ -0,0 +1,208 @@
@props([
'currentPageOptionProperty' => 'tableRecordsPerPage',
'extremeLinks' => false,
'paginator',
'pageOptions' => [],
])
@php
use Illuminate\Contracts\Pagination\CursorPaginator;
$isRtl = __('filament-panels::layout.direction') === 'rtl';
$isSimple = ! $paginator instanceof \Illuminate\Pagination\LengthAwarePaginator;
@endphp
<nav
aria-label="{{ __('filament::components/pagination.label') }}"
role="navigation"
{{
$attributes->class([
'fi-pagination',
'fi-simple' => $isSimple,
])
}}
>
@if (! $paginator->onFirstPage())
@php
if ($paginator instanceof CursorPaginator) {
$wireClickAction = "setPage('{$paginator->previousCursor()->encode()}', '{$paginator->getCursorName()}')";
} else {
$wireClickAction = "previousPage('{$paginator->getPageName()}')";
}
@endphp
<x-filament::button
color="gray"
rel="prev"
:wire:click="$wireClickAction"
:wire:key="$this->getId() . '.pagination.previous'"
class="fi-pagination-previous-btn"
>
{{ __('filament::components/pagination.actions.previous.label') }}
</x-filament::button>
@endif
@if (! $isSimple)
<span class="fi-pagination-overview">
{{
trans_choice(
'filament::components/pagination.overview',
$paginator->total(),
[
'first' => \Illuminate\Support\Number::format($paginator->firstItem() ?? 0),
'last' => \Illuminate\Support\Number::format($paginator->lastItem() ?? 0),
'total' => \Illuminate\Support\Number::format($paginator->total()),
],
)
}}
</span>
@endif
@if (count($pageOptions) > 1)
<div class="fi-pagination-records-per-page-select-ctn">
<label class="fi-pagination-records-per-page-select fi-compact">
<x-filament::input.wrapper>
<x-filament::input.select
:wire:model.live="$currentPageOptionProperty"
>
@foreach ($pageOptions as $option)
<option value="{{ $option }}">
{{ $option === 'all' ? __('filament::components/pagination.fields.records_per_page.options.all') : $option }}
</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
<span class="fi-sr-only">
{{ __('filament::components/pagination.fields.records_per_page.label') }}
</span>
</label>
<label class="fi-pagination-records-per-page-select">
<x-filament::input.wrapper
:prefix="__('filament::components/pagination.fields.records_per_page.label')"
>
<x-filament::input.select
:wire:model.live="$currentPageOptionProperty"
>
@foreach ($pageOptions as $option)
<option value="{{ $option }}">
{{ $option === 'all' ? __('filament::components/pagination.fields.records_per_page.options.all') : $option }}
</option>
@endforeach
</x-filament::input.select>
</x-filament::input.wrapper>
</label>
</div>
@endif
@if ($paginator->hasMorePages())
@php
if ($paginator instanceof CursorPaginator) {
$wireClickAction = "setPage('{$paginator->nextCursor()->encode()}', '{$paginator->getCursorName()}')";
} else {
$wireClickAction = "nextPage('{$paginator->getPageName()}')";
}
@endphp
<x-filament::button
color="gray"
rel="next"
:wire:click="$wireClickAction"
:wire:key="$this->getId() . '.pagination.next'"
class="fi-pagination-next-btn"
>
{{ __('filament::components/pagination.actions.next.label') }}
</x-filament::button>
@endif
@if ((! $isSimple) && $paginator->hasPages())
<ol class="fi-pagination-items">
@if (! $paginator->onFirstPage())
@if ($extremeLinks)
<x-filament::pagination.item
:aria-label="__('filament::components/pagination.actions.first.label')"
:icon="$isRtl ? \Filament\Support\Icons\Heroicon::ChevronDoubleRight : \Filament\Support\Icons\Heroicon::ChevronDoubleLeft"
:icon-alias="
$isRtl
? \Filament\Support\View\SupportIconAlias::PAGINATION_FIRST_BUTTON_RTL
: \Filament\Support\View\SupportIconAlias::PAGINATION_FIRST_BUTTON
"
rel="first"
:wire:click="'gotoPage(1, \'' . $paginator->getPageName() . '\')'"
:wire:key="$this->getId() . '.pagination.first'"
/>
@endif
<x-filament::pagination.item
:aria-label="__('filament::components/pagination.actions.previous.label')"
:icon="$isRtl ? \Filament\Support\Icons\Heroicon::ChevronRight : \Filament\Support\Icons\Heroicon::ChevronLeft"
{{-- @deprecated Use `SupportIconAlias::PAGINATION_PREVIOUS_BUTTON_RTL` instead of `SupportIconAlias::PAGINATION_PREVIOUS_BUTTON` for RTL. --}}
:icon-alias="
$isRtl
? [
\Filament\Support\View\SupportIconAlias::PAGINATION_PREVIOUS_BUTTON_RTL,
\Filament\Support\View\SupportIconAlias::PAGINATION_PREVIOUS_BUTTON,
]
: \Filament\Support\View\SupportIconAlias::PAGINATION_PREVIOUS_BUTTON
"
rel="prev"
:wire:click="'previousPage(\'' . $paginator->getPageName() . '\')'"
:wire:key="$this->getId() . '.pagination.previous'"
/>
@endif
@foreach ($paginator->render()->offsetGet('elements') as $element)
@if (is_string($element))
<x-filament::pagination.item disabled :label="$element" />
@endif
@if (is_array($element))
@foreach ($element as $page => $url)
<x-filament::pagination.item
:active="$page === $paginator->currentPage()"
:aria-label="trans_choice('filament::components/pagination.actions.go_to_page.label', $page, ['page' => $page])"
:label="$page"
:wire:click="'gotoPage(' . $page . ', \'' . $paginator->getPageName() . '\')'"
:wire:key="$this->getId() . '.pagination.' . $paginator->getPageName() . '.' . $page"
/>
@endforeach
@endif
@endforeach
@if ($paginator->hasMorePages())
<x-filament::pagination.item
:aria-label="__('filament::components/pagination.actions.next.label')"
:icon="$isRtl ? \Filament\Support\Icons\Heroicon::ChevronLeft : \Filament\Support\Icons\Heroicon::ChevronRight"
{{-- @deprecated Use `SupportIconAlias::PAGINATION_NEXT_BUTTON_RTL` instead of `SupportIconAlias::PAGINATION_NEXT_BUTTON` for RTL. --}}
:icon-alias="
$isRtl
? [
\Filament\Support\View\SupportIconAlias::PAGINATION_NEXT_BUTTON_RTL,
\Filament\Support\View\SupportIconAlias::PAGINATION_NEXT_BUTTON,
]
: \Filament\Support\View\SupportIconAlias::PAGINATION_NEXT_BUTTON
"
rel="next"
:wire:click="'nextPage(\'' . $paginator->getPageName() . '\')'"
:wire:key="$this->getId() . '.pagination.next'"
/>
@if ($extremeLinks)
<x-filament::pagination.item
:aria-label="__('filament::components/pagination.actions.last.label')"
:icon="$isRtl ? \Filament\Support\Icons\Heroicon::ChevronDoubleLeft : \Filament\Support\Icons\Heroicon::ChevronDoubleRight"
:icon-alias="
$isRtl
? \Filament\Support\View\SupportIconAlias::PAGINATION_LAST_BUTTON_RTL
: \Filament\Support\View\SupportIconAlias::PAGINATION_LAST_BUTTON
"
rel="last"
:wire:click="'gotoPage(' . $paginator->lastPage() . ', \'' . $paginator->getPageName() . '\')'"
:wire:key="$this->getId() . '.pagination.last'"
/>
@endif
@endif
</ol>
@endif
</nav>

View File

@@ -0,0 +1,39 @@
@props([
'active' => false,
'ariaLabel' => null,
'disabled' => false,
'icon' => null,
'iconAlias' => null,
'label' => null,
])
<li
{{
$attributes->class([
'fi-pagination-item',
'fi-disabled' => $disabled,
'fi-active' => $active,
])
}}
>
<button
aria-label="{{ $ariaLabel }}"
@disabled($disabled)
type="button"
class="fi-pagination-item-btn"
>
@if (filled($icon))
{{
\Filament\Support\generate_icon_html($icon, $iconAlias, attributes: (new \Illuminate\View\ComponentAttributeBag)->class([
'fi-pagination-item-icon',
]))
}}
@endif
@if (filled($label))
<span class="fi-pagination-item-label">
{{ is_numeric($label) ? \Illuminate\Support\Number::format($label) : ($label ?? '...') }}
</span>
@endif
</button>
</li>

View File

@@ -0,0 +1,5 @@
<p
{{ $attributes->class(['fi-section-header-description']) }}
>
{{ $slot }}
</p>

View File

@@ -0,0 +1,5 @@
<h2
{{ $attributes->class(['fi-section-header-heading']) }}
>
{{ $slot }}
</h2>

View File

@@ -0,0 +1,140 @@
@php
use Filament\Support\Enums\Alignment;
use Filament\Support\Enums\IconSize;
use Filament\Support\View\Components\SectionComponent\IconComponent;
use function Filament\Support\is_slot_empty;
@endphp
@props([
'afterHeader' => null,
'aside' => false,
'collapsed' => false,
'collapseId' => null,
'collapsible' => false,
'compact' => false,
'contained' => true,
'contentBefore' => false,
'description' => null,
'divided' => false,
'footer' => null,
'hasContentEl' => true,
'heading' => null,
'headingTag' => 'h2',
'icon' => null,
'iconColor' => 'gray',
'iconSize' => null,
'persistCollapsed' => false,
'secondary' => false,
])
@php
if (filled($iconSize) && (! $iconSize instanceof IconSize)) {
$iconSize = IconSize::tryFrom($iconSize) ?? $iconSize;
}
$hasDescription = filled((string) $description);
$hasHeading = filled($heading);
$hasIcon = filled($icon);
$hasHeader = $hasIcon || $hasHeading || $hasDescription || $collapsible || (! is_slot_empty($afterHeader));
@endphp
<section
{{-- TODO: Investigate Livewire bug - https://github.com/filamentphp/filament/pull/8511 --}}
x-data="{
isCollapsed: @if ($persistCollapsed) $persist(@js($collapsed)).as(`section-${@js($collapseId) ?? $el.id}-isCollapsed`) @else @js($collapsed) @endif,
}"
@if ($collapsible)
x-on:collapse-section.window="if ($event.detail.id == @js($collapseId) ?? $el.id) isCollapsed = true"
x-on:expand="isCollapsed = false"
x-on:expand-section.window="if ($event.detail.id == @js($collapseId) ?? $el.id) isCollapsed = false"
x-on:open-section.window="if ($event.detail.id == @js($collapseId) ?? $el.id) isCollapsed = false"
x-on:toggle-section.window="if ($event.detail.id == @js($collapseId) ?? $el.id) isCollapsed = ! isCollapsed"
x-bind:class="isCollapsed && 'fi-collapsed'"
@endif
{{
$attributes->class([
'fi-section',
'fi-section-not-contained' => ! $contained,
'fi-section-has-content-before' => $contentBefore,
'fi-section-has-header' => $hasHeader,
'fi-aside' => $aside,
'fi-compact' => $compact,
'fi-collapsible' => $collapsible,
'fi-divided' => $divided,
'fi-secondary' => $secondary,
])
}}
>
@if ($hasHeader)
<header
@if ($collapsible)
x-on:click="isCollapsed = ! isCollapsed"
@endif
class="fi-section-header"
>
{{
\Filament\Support\generate_icon_html($icon, attributes: (new \Illuminate\View\ComponentAttributeBag)
->color(IconComponent::class, $iconColor), size: $iconSize ?? IconSize::Large)
}}
@if ($hasHeading || $hasDescription)
<div class="fi-section-header-text-ctn">
@if ($hasHeading)
<{{ $headingTag }} class="fi-section-header-heading">
{{ $heading }}
</{{ $headingTag }}>
@endif
@if ($hasDescription)
<p class="fi-section-header-description">
{{ $description }}
</p>
@endif
</div>
@endif
@if (! is_slot_empty($afterHeader))
<div x-on:click.stop class="fi-section-header-after-ctn">
{{ $afterHeader }}
</div>
@endif
@if ($collapsible)
<x-filament::icon-button
color="gray"
:icon="\Filament\Support\Icons\Heroicon::ChevronUp"
:icon-alias="\Filament\Support\View\SupportIconAlias::SECTION_COLLAPSE_BUTTON"
x-on:click.stop="isCollapsed = ! isCollapsed"
class="fi-section-collapse-btn"
/>
@endif
</header>
@endif
@if ((! is_slot_empty($slot)) || (! is_slot_empty($footer)))
<div
@if ($collapsible)
x-bind:aria-expanded="(! isCollapsed).toString()"
@if ($collapsed || $persistCollapsed)
x-cloak
@endif
@endif
class="fi-section-content-ctn"
>
@if ($hasContentEl)
<div class="fi-section-content">
{{ $slot }}
</div>
@else
{{ $slot }}
@endif
@if (! is_slot_empty($footer))
<footer class="fi-section-footer">
{{ $footer }}
</footer>
@endif
</div>
@endif
</section>

View File

@@ -0,0 +1,22 @@
@props([
'contained' => false,
'label' => null,
'vertical' => false,
])
<nav
{{
$attributes
->merge([
'aria-label' => $label,
'role' => 'tablist',
])
->class([
'fi-tabs',
'fi-contained' => $contained,
'fi-vertical' => $vertical,
])
}}
>
{{ $slot }}
</nav>

View File

@@ -0,0 +1,81 @@
@php
use Filament\Support\Enums\IconPosition;
@endphp
@props([
'active' => false,
'alpineActive' => null,
'badge' => null,
'badgeColor' => null,
'badgeTooltip' => null,
'badgeIcon' => null,
'badgeIconPosition' => IconPosition::Before,
'href' => null,
'icon' => null,
'iconColor' => 'gray',
'iconPosition' => IconPosition::Before,
'spaMode' => null,
'tag' => 'button',
'target' => null,
'type' => 'button',
])
@php
if (! $iconPosition instanceof IconPosition) {
$iconPosition = filled($iconPosition) ? (IconPosition::tryFrom($iconPosition) ?? $iconPosition) : null;
}
$hasAlpineActiveClasses = filled($alpineActive);
@endphp
<{{ $tag }}
@if ($tag === 'button')
type="{{ $type }}"
@elseif ($tag === 'a')
{{ \Filament\Support\generate_href_html($href, $target === '_blank', $spaMode) }}
@endif
@if ($hasAlpineActiveClasses)
x-bind:class="{
'fi-active': {{ $alpineActive }},
}"
@endif
{{
$attributes
->merge([
'aria-selected' => $active,
'role' => 'tab',
])
->class([
'fi-tabs-item',
'fi-active' => (! $hasAlpineActiveClasses) && $active,
])
}}
>
@if ($icon && $iconPosition === IconPosition::Before)
{{ \Filament\Support\generate_icon_html($icon) }}
@endif
<span class="fi-tabs-item-label">
{{ $slot }}
</span>
@if ($icon && $iconPosition === IconPosition::After)
{{ \Filament\Support\generate_icon_html($icon) }}
@endif
@if (filled($badge))
@if ($badge instanceof \Illuminate\View\ComponentSlot)
{{ $badge }}
@else
<x-filament::badge
:color="$badgeColor"
:icon="$badgeIcon"
:icon-position="$badgeIconPosition"
size="sm"
:tooltip="$badgeTooltip"
>
{{ $badge }}
</x-filament::badge>
@endif
@endif
</{{ $tag }}>

View File

@@ -0,0 +1,67 @@
@php
use Filament\Support\View\Components\ToggleComponent;
use Illuminate\Support\Arr;
@endphp
@props([
'state',
'offColor' => 'gray',
'offIcon' => null,
'onColor' => 'primary',
'onIcon' => null,
])
<button
x-data="{ state: {{ $state }} }"
x-bind:aria-checked="state?.toString()"
x-on:click="state = ! state"
x-bind:class="
state ? @js(Arr::toCssClasses([
'fi-toggle-on',
...\Filament\Support\get_component_color_classes(ToggleComponent::class, $onColor),
])) : @js(Arr::toCssClasses([
'fi-toggle-off',
...\Filament\Support\get_component_color_classes(ToggleComponent::class, $offColor),
]))
"
@if ($state)
x-cloak
@endif
{{
$attributes
->merge([
'role' => 'switch',
'type' => 'button',
], escape: false)
->class(['fi-toggle'])
}}
>
<div>
<div aria-hidden="true">
{{ \Filament\Support\generate_icon_html($offIcon, size: \Filament\Support\Enums\IconSize::ExtraSmall) }}
</div>
<div aria-hidden="true">
{{ \Filament\Support\generate_icon_html($onIcon, size: \Filament\Support\Enums\IconSize::ExtraSmall) }}
</div>
</div>
</button>
@if ($state)
<div
x-cloak="inline-flex"
wire:ignore
@class([
'fi-toggle fi-toggle-on fi-hidden',
...\Filament\Support\get_component_color_classes(ToggleComponent::class, $onColor),
])
>
<div>
<div aria-hidden="true"></div>
<div aria-hidden="true">
{{ \Filament\Support\generate_icon_html($onIcon, size: \Filament\Support\Enums\IconSize::ExtraSmall) }}
</div>
</div>
</div>
@endif