feat: add resources and view components
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
@php
|
||||
use Filament\Schemas\Components\Tabs\Tab;
|
||||
use Filament\Schemas\View\SchemaIconAlias;
|
||||
use Filament\Support\Icons\Heroicon;
|
||||
|
||||
$activeTab = $getActiveTab();
|
||||
$hasDeferredBadges = $hasDeferredBadges();
|
||||
$id = $getId();
|
||||
$isContained = $isContained();
|
||||
$isScrollable = $isScrollable();
|
||||
$isVertical = $isVertical();
|
||||
$label = $getLabel();
|
||||
$livewireProperty = $getLivewireProperty();
|
||||
$renderHookScopes = $getRenderHookScopes();
|
||||
$tabs = $getChildSchema()->getComponents();
|
||||
$tabsKey = $getKey();
|
||||
|
||||
$getTabVisibilityJs = function (Tab $tab, ?int $index = null, ?string $mode = null) use ($isScrollable): ?string {
|
||||
$hiddenJs = $tab->getHiddenJs();
|
||||
$visibleJs = $tab->getVisibleJs();
|
||||
|
||||
$baseJs = match ([filled($hiddenJs), filled($visibleJs)]) {
|
||||
[true, true] => "(! ({$hiddenJs})) && ({$visibleJs})",
|
||||
[true, false] => "! ({$hiddenJs})",
|
||||
[false, true] => $visibleJs,
|
||||
default => null,
|
||||
};
|
||||
|
||||
if ($isScrollable || $index === null || $mode === null) {
|
||||
return $baseJs;
|
||||
}
|
||||
|
||||
$tabKey = $tab->getKey(isAbsolute: false);
|
||||
|
||||
$dropdownJs = match ($mode) {
|
||||
'inline' => "(!withinDropdownMounted || withinDropdownIndex === null || {$index} < withinDropdownIndex)",
|
||||
'trigger' => "(withinDropdownMounted && withinDropdownIndex !== null && {$index} >= withinDropdownIndex && '{$tabKey}' === tab)",
|
||||
default => null,
|
||||
};
|
||||
|
||||
return $baseJs ? "{$baseJs} && {$dropdownJs}" : $dropdownJs;
|
||||
};
|
||||
@endphp
|
||||
|
||||
@if (blank($livewireProperty))
|
||||
<div
|
||||
x-data="tabsSchemaComponent({
|
||||
activeTab: @js($activeTab),
|
||||
isScrollable: @js($isScrollable),
|
||||
isTabPersistedInQueryString: @js($isTabPersistedInQueryString()),
|
||||
livewireId: @js($this->getId()),
|
||||
tab: @if ($isTabPersisted() && filled($id)) $persist(null).as(@js($id)) @else @js(null) @endif,
|
||||
tabQueryStringKey: @js($getTabQueryStringKey()),
|
||||
})"
|
||||
x-load
|
||||
x-load-src="{{ \Filament\Support\Facades\FilamentAsset::getAlpineComponentSrc('tabs', 'filament/schemas') }}"
|
||||
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($tabs)->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
|
||||
:x-bind:class="! $isScrollable ? '{ \'fi-invisible\': ! withinDropdownMounted }' : null"
|
||||
:x-data="
|
||||
$hasDeferredBadges ? '{
|
||||
deferredBadges: {},
|
||||
isLoadingDeferredBadges: true,
|
||||
unsubscribeLivewireHook: null,
|
||||
|
||||
async fetchDeferredBadges() {
|
||||
this.isLoadingDeferredBadges = true
|
||||
|
||||
try {
|
||||
const badges = await $wire.callSchemaComponentMethod(' . \Illuminate\Support\Js::from($tabsKey) . ', \'getDeferredTabBadges\')
|
||||
this.deferredBadges = badges ?? {}
|
||||
} finally {
|
||||
this.isLoadingDeferredBadges = false
|
||||
}
|
||||
},
|
||||
|
||||
async init() {
|
||||
await this.fetchDeferredBadges()
|
||||
|
||||
this.unsubscribeLivewireHook = Livewire.hook(\'commit\', ({ component, succeed }) => {
|
||||
succeed(() => {
|
||||
if (component.id !== $wire.__instance.id) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLoadingDeferredBadges) {
|
||||
return
|
||||
}
|
||||
|
||||
this.fetchDeferredBadges()
|
||||
})
|
||||
})
|
||||
},
|
||||
|
||||
destroy() {
|
||||
this.unsubscribeLivewireHook?.()
|
||||
},
|
||||
}' : null
|
||||
"
|
||||
>
|
||||
@foreach ($getStartRenderHooks() as $startRenderHook)
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook($startRenderHook, scopes: $renderHookScopes) }}
|
||||
@endforeach
|
||||
|
||||
@foreach ($tabs as $index => $tab)
|
||||
@php
|
||||
$isTabBadgeDeferred = $tab->isBadgeDeferred();
|
||||
$tabBadge = $isTabBadgeDeferred ? null : $tab->getBadge();
|
||||
$tabBadgeColor = $isTabBadgeDeferred ? null : $tab->getBadgeColor();
|
||||
$tabBadgeIcon = $isTabBadgeDeferred ? null : $tab->getBadgeIcon();
|
||||
$tabBadgeIconPosition = $isTabBadgeDeferred ? null : $tab->getBadgeIconPosition();
|
||||
$tabBadgeTooltip = $isTabBadgeDeferred ? null : $tab->getBadgeTooltip();
|
||||
$tabExtraAttributeBag = $tab->getExtraAttributeBag();
|
||||
$tabIcon = $tab->getIcon();
|
||||
$tabIconPosition = $tab->getIconPosition();
|
||||
$tabKey = $tab->getKey(isAbsolute: false);
|
||||
$tabLabel = $tab->getLabel();
|
||||
$tabVisibilityJs = $getTabVisibilityJs($tab, $index, 'inline');
|
||||
@endphp
|
||||
|
||||
<x-filament::tabs.item
|
||||
:alpine-active="'tab === \'' . $tabKey . '\''"
|
||||
:alpine-deferred-badge-data="$isTabBadgeDeferred ? 'deferredBadges[' . \Illuminate\Support\Js::from($index) . ']' : null"
|
||||
:alpine-deferred-badge-loading="$isTabBadgeDeferred ? 'isLoadingDeferredBadges' : null"
|
||||
:attributes="$tabExtraAttributeBag"
|
||||
:badge="$tabBadge"
|
||||
:badge-color="$tabBadgeColor"
|
||||
:badge-icon="$tabBadgeIcon"
|
||||
:badge-icon-position="$tabBadgeIconPosition"
|
||||
:badge-tooltip="$tabBadgeTooltip"
|
||||
:data-tab-key="$tabKey"
|
||||
:icon="$tabIcon"
|
||||
:icon-position="$tabIconPosition"
|
||||
:x-cloak="$tabVisibilityJs !== null"
|
||||
:x-on:click="'tab = \'' . $tabKey . '\''"
|
||||
:x-show="$tabVisibilityJs"
|
||||
>
|
||||
{{ $tabLabel }}
|
||||
</x-filament::tabs.item>
|
||||
@endforeach
|
||||
|
||||
@if (! $isScrollable)
|
||||
<x-filament::dropdown
|
||||
:placement="__('filament-panels::layout.direction') === 'ltr' ? 'bottom-start' : 'bottom-end'"
|
||||
>
|
||||
<x-slot name="trigger">
|
||||
@foreach ($tabs as $index => $tab)
|
||||
@php
|
||||
$isTabBadgeDeferred = $tab->isBadgeDeferred();
|
||||
$tabBadge = $isTabBadgeDeferred ? null : $tab->getBadge();
|
||||
$tabBadgeColor = $isTabBadgeDeferred ? null : $tab->getBadgeColor();
|
||||
$tabBadgeTooltip = $isTabBadgeDeferred ? null : $tab->getBadgeTooltip();
|
||||
$tabExtraAttributeBag = $tab->getExtraAttributeBag();
|
||||
$tabKey = $tab->getKey(isAbsolute: false);
|
||||
$tabLabel = $tab->getLabel();
|
||||
$tabVisibilityJs = $getTabVisibilityJs($tab, $index, 'trigger');
|
||||
@endphp
|
||||
|
||||
<x-filament::tabs.item
|
||||
:alpine-active="'tab === \'' . $tabKey . '\''"
|
||||
:alpine-deferred-badge-data="$isTabBadgeDeferred ? 'deferredBadges[' . \Illuminate\Support\Js::from($index) . ']' : null"
|
||||
:alpine-deferred-badge-loading="$isTabBadgeDeferred ? 'isLoadingDeferredBadges' : null"
|
||||
:attributes="$tabExtraAttributeBag"
|
||||
:badge="$tabBadge"
|
||||
:badge-color="$tabBadgeColor"
|
||||
:badge-tooltip="$tabBadgeTooltip"
|
||||
:icon="Heroicon::ChevronDown"
|
||||
:icon-alias="SchemaIconAlias::COMPONENTS_TABS_DROPDOWN_TRIGGER_BUTTON"
|
||||
:x-cloak="$tabVisibilityJs !== null"
|
||||
:x-show="$tabVisibilityJs"
|
||||
>
|
||||
{{ $tabLabel }}
|
||||
</x-filament::tabs.item>
|
||||
@endforeach
|
||||
|
||||
<x-filament::tabs.item x-show="isDropdownButtonVisible">
|
||||
{{
|
||||
\Filament\Support\generate_icon_html(
|
||||
Heroicon::EllipsisHorizontal,
|
||||
alias: SchemaIconAlias::COMPONENTS_TABS_MORE_TABS_BUTTON,
|
||||
)
|
||||
}}
|
||||
</x-filament::tabs.item>
|
||||
</x-slot>
|
||||
|
||||
<x-filament::dropdown.list>
|
||||
@foreach ($tabs as $index => $tab)
|
||||
@php
|
||||
$isTabBadgeDeferred = $tab->isBadgeDeferred();
|
||||
$tabBadge = $isTabBadgeDeferred ? null : $tab->getBadge();
|
||||
$tabBadgeColor = $isTabBadgeDeferred ? null : $tab->getBadgeColor();
|
||||
$tabBadgeTooltip = $isTabBadgeDeferred ? null : $tab->getBadgeTooltip();
|
||||
$tabIcon = $tab->getIcon();
|
||||
$tabKey = $tab->getKey(isAbsolute: false);
|
||||
$tabLabel = $tab->getLabel();
|
||||
@endphp
|
||||
|
||||
<x-filament::dropdown.list.item
|
||||
:alpine-deferred-badge-data="$isTabBadgeDeferred ? 'deferredBadges[' . \Illuminate\Support\Js::from($index) . ']' : null"
|
||||
:alpine-deferred-badge-loading="$isTabBadgeDeferred ? 'isLoadingDeferredBadges' : null"
|
||||
:badge="$tabBadge"
|
||||
:badge-color="$tabBadgeColor"
|
||||
:badge-tooltip="$tabBadgeTooltip"
|
||||
:icon="$tabIcon"
|
||||
x-bind:class="{ 'fi-selected': tab === '{{ $tabKey }}' }"
|
||||
:x-on:click="'tab = \'' . $tabKey . '\'; close($event);'"
|
||||
:x-show="$index . ' >= withinDropdownIndex'"
|
||||
>
|
||||
{{ $tabLabel }}
|
||||
</x-filament::dropdown.list.item>
|
||||
@endforeach
|
||||
</x-filament::dropdown.list>
|
||||
</x-filament::dropdown>
|
||||
@endif
|
||||
|
||||
@foreach ($getEndRenderHooks() as $endRenderHook)
|
||||
{{ \Filament\Support\Facades\FilamentView::renderHook($endRenderHook, scopes: $renderHookScopes) }}
|
||||
@endforeach
|
||||
</x-filament::tabs>
|
||||
|
||||
@foreach ($tabs as $tab)
|
||||
@php
|
||||
$tabVisibilityJs = $getTabVisibilityJs($tab);
|
||||
@endphp
|
||||
|
||||
@if ($tabVisibilityJs)
|
||||
<div x-cloak x-show="{!! $tabVisibilityJs !!}">
|
||||
{{ $tab }}
|
||||
</div>
|
||||
@else
|
||||
{{ $tab }}
|
||||
@endif
|
||||
@endforeach
|
||||
</div>
|
||||
@else
|
||||
@php
|
||||
$activeTab = strval($this->{$livewireProperty});
|
||||
@endphp
|
||||
|
||||
<div
|
||||
@if ($hasDeferredBadges)
|
||||
x-data="{
|
||||
deferredBadges: {},
|
||||
isLoadingDeferredBadges: true,
|
||||
unsubscribeLivewireHook: null,
|
||||
|
||||
async fetchDeferredBadges() {
|
||||
this.isLoadingDeferredBadges = true
|
||||
|
||||
try {
|
||||
const badges = await $wire.callSchemaComponentMethod(
|
||||
@js($tabsKey),
|
||||
'getDeferredTabBadges',
|
||||
)
|
||||
|
||||
this.deferredBadges = badges ?? {}
|
||||
} finally {
|
||||
this.isLoadingDeferredBadges = false
|
||||
}
|
||||
},
|
||||
|
||||
async init() {
|
||||
await this.fetchDeferredBadges()
|
||||
|
||||
this.unsubscribeLivewireHook = Livewire.hook(
|
||||
'commit',
|
||||
({ component, commit, succeed }) => {
|
||||
succeed(() => {
|
||||
if (component.id !== $wire.__instance.id) {
|
||||
return
|
||||
}
|
||||
|
||||
if (this.isLoadingDeferredBadges) {
|
||||
return
|
||||
}
|
||||
|
||||
const updateKeys = Object.keys(commit.updates ?? {})
|
||||
|
||||
if (updateKeys.length === 1 && updateKeys[0] === @js($livewireProperty)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.fetchDeferredBadges()
|
||||
})
|
||||
},
|
||||
)
|
||||
},
|
||||
|
||||
destroy() {
|
||||
this.unsubscribeLivewireHook?.()
|
||||
},
|
||||
}"
|
||||
@endif
|
||||
{{
|
||||
$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
|
||||
$isTabBadgeDeferred = $tab->isBadgeDeferred();
|
||||
$tabBadge = $isTabBadgeDeferred ? null : $tab->getBadge();
|
||||
$tabBadgeColor = $isTabBadgeDeferred ? null : $tab->getBadgeColor();
|
||||
$tabBadgeIcon = $isTabBadgeDeferred ? null : $tab->getBadgeIcon();
|
||||
$tabBadgeIconPosition = $isTabBadgeDeferred ? null : $tab->getBadgeIconPosition();
|
||||
$tabBadgeTooltip = $isTabBadgeDeferred ? null : $tab->getBadgeTooltip();
|
||||
$tabExtraAttributeBag = $tab->getExtraAttributeBag();
|
||||
$tabIcon = $tab->getIcon();
|
||||
$tabIconPosition = $tab->getIconPosition();
|
||||
$tabKey = strval($tabKey);
|
||||
$tabLabel = $tab->getLabel() ?? $this->generateTabLabel($tabKey);
|
||||
@endphp
|
||||
|
||||
<x-filament::tabs.item
|
||||
:active="$activeTab === $tabKey"
|
||||
:alpine-deferred-badge-data="$isTabBadgeDeferred ? 'deferredBadges[' . \Illuminate\Support\Js::from($tabKey) . ']' : null"
|
||||
:alpine-deferred-badge-loading="$isTabBadgeDeferred ? 'isLoadingDeferredBadges' : null"
|
||||
:attributes="$tabExtraAttributeBag"
|
||||
: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') . ')'"
|
||||
>
|
||||
{{ $tabLabel }}
|
||||
</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
|
||||
Reference in New Issue
Block a user