index.blade.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273
  1. @php
  2. use Filament\Support\Enums\Alignment;
  3. use Filament\Support\Enums\Width;
  4. use Filament\Support\View\Components\ModalComponent\IconComponent;
  5. use Illuminate\View\ComponentAttributeBag;
  6. @endphp
  7. @props([
  8. 'alignment' => Alignment::Start,
  9. 'ariaLabelledby' => null,
  10. 'autofocus' => \Filament\Support\View\Components\ModalComponent::$isAutofocused,
  11. 'closeButton' => \Filament\Support\View\Components\ModalComponent::$hasCloseButton,
  12. 'closeByClickingAway' => \Filament\Support\View\Components\ModalComponent::$isClosedByClickingAway,
  13. 'closeByEscaping' => \Filament\Support\View\Components\ModalComponent::$isClosedByEscaping,
  14. 'closeEventName' => 'close-modal',
  15. 'closeQuietlyEventName' => 'close-modal-quietly',
  16. 'description' => null,
  17. 'extraModalWindowAttributeBag' => null,
  18. 'footer' => null,
  19. 'footerActions' => [],
  20. 'footerActionsAlignment' => Alignment::Start,
  21. 'header' => null,
  22. 'heading' => null,
  23. 'icon' => null,
  24. 'iconAlias' => null,
  25. 'iconColor' => 'primary',
  26. 'id' => null,
  27. 'openEventName' => 'open-modal',
  28. 'slideOver' => false,
  29. 'stickyFooter' => false,
  30. 'stickyHeader' => false,
  31. 'teleport' => null,
  32. 'trigger' => null,
  33. 'visible' => true,
  34. 'width' => 'sm',
  35. ])
  36. @php
  37. $hasContent = ! \Filament\Support\is_slot_empty($slot);
  38. $hasDescription = filled($description);
  39. $hasFooter = (! \Filament\Support\is_slot_empty($footer)) || (is_array($footerActions) && count($footerActions)) || (! is_array($footerActions) && (! \Filament\Support\is_slot_empty($footerActions)));
  40. $hasHeading = filled($heading);
  41. $hasIcon = filled($icon);
  42. if (! $alignment instanceof Alignment) {
  43. $alignment = filled($alignment) ? (Alignment::tryFrom($alignment) ?? $alignment) : null;
  44. }
  45. if (! $footerActionsAlignment instanceof Alignment) {
  46. $footerActionsAlignment = filled($footerActionsAlignment) ? (Alignment::tryFrom($footerActionsAlignment) ?? $footerActionsAlignment) : null;
  47. }
  48. if (is_string($width)) {
  49. $width = Width::tryFrom($width) ?? $width;
  50. }
  51. $closeEventHandler = filled($id) ? '$dispatch(' . \Illuminate\Support\Js::from($closeEventName) . ', { id: ' . \Illuminate\Support\Js::from($id) . ' })' : 'close()';
  52. $wireSubmitHandler = $attributes->get('wire:submit.prevent');
  53. $attributes = $attributes->except(['wire:submit.prevent']);
  54. @endphp
  55. @if ($trigger)
  56. {!! '<div>' !!}
  57. {{-- Avoid formatting issues with unclosed elements --}}
  58. <div
  59. @if (! $trigger->attributes->get('disabled'))
  60. @if ($id)
  61. x-on:click="$dispatch(@js($openEventName), { id: @js($id) })"
  62. @else
  63. x-on:click="$el.nextElementSibling.dispatchEvent(new CustomEvent(@js($openEventName)))"
  64. @endif
  65. @endif
  66. {{ $trigger->attributes->except(['disabled'])->class(['fi-modal-trigger']) }}
  67. >
  68. {{ $trigger }}
  69. </div>
  70. @endif
  71. @if (filled($teleport))
  72. {!! "<template x-teleport=\"{$teleport}\">" !!}
  73. {{-- Avoid formatting issues with unclosed elements --}}
  74. @endif
  75. <div
  76. @if ($ariaLabelledby)
  77. aria-labelledby="{{ $ariaLabelledby }}"
  78. @elseif ($heading)
  79. aria-labelledby="{{ "{$id}.heading" }}"
  80. @endif
  81. aria-modal="true"
  82. id="{{ $id }}"
  83. role="dialog"
  84. x-data="filamentModal({
  85. id: @js($id),
  86. })"
  87. @if ($id)
  88. data-fi-modal-id="{{ $id }}"
  89. x-on:{{ $closeEventName }}.window="if (($event.detail.id === @js($id)) && isOpen) close()"
  90. x-on:{{ $closeQuietlyEventName }}.window="if (($event.detail.id === @js($id)) && isOpen) closeQuietly()"
  91. x-on:{{ $openEventName }}.window="if (($event.detail.id === @js($id)) && (! isOpen)) open()"
  92. @else
  93. x-on:{{ $closeEventName }}.stop="if (isOpen) close()"
  94. x-on:{{ $closeQuietlyEventName }}.stop="if (isOpen) closeQuietly()"
  95. x-on:{{ $openEventName }}.stop="if (! isOpen) open()"
  96. @endif
  97. x-bind:class="{
  98. 'fi-modal-open': isOpen,
  99. }"
  100. x-cloak
  101. x-show="isOpen"
  102. x-trap.noscroll{{ $autofocus ? '' : '.noautofocus' }}="isOpen"
  103. {{
  104. $attributes->class([
  105. 'fi-modal',
  106. 'fi-absolute-positioning-context',
  107. 'fi-modal-slide-over' => $slideOver,
  108. 'fi-width-screen' => $width === Width::Screen,
  109. ])
  110. }}
  111. >
  112. <div
  113. aria-hidden="true"
  114. x-show="isOpen"
  115. x-transition.duration.300ms.opacity
  116. class="fi-modal-close-overlay"
  117. ></div>
  118. <div
  119. @if ($closeByClickingAway)
  120. x-on:click.self="{{ $closeEventHandler }}"
  121. @endif
  122. @class([
  123. 'fi-modal-window-ctn',
  124. 'fi-clickable' => $closeByClickingAway,
  125. ])
  126. >
  127. <{{ filled($wireSubmitHandler) ? 'form' : 'div' }}
  128. @if ($closeByEscaping)
  129. x-on:keydown.window.escape="{{ $closeEventHandler }}"
  130. @endif
  131. x-show="isWindowVisible"
  132. x-transition:enter="fi-transition-enter"
  133. x-transition:leave="fi-transition-leave"
  134. @if ($width !== Width::Screen)
  135. x-transition:enter-start="fi-transition-enter-start"
  136. x-transition:enter-end="fi-transition-enter-end"
  137. x-transition:leave-start="fi-transition-leave-start"
  138. x-transition:leave-end="fi-transition-leave-end"
  139. @endif
  140. @if (filled($wireSubmitHandler))
  141. wire:submit.prevent="{!! $wireSubmitHandler !!}"
  142. @endif
  143. @if (filled($id))
  144. wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.window"
  145. @endif
  146. {{
  147. ($extraModalWindowAttributeBag ?? new \Illuminate\View\ComponentAttributeBag)->class([
  148. 'fi-modal-window',
  149. 'fi-modal-window-has-close-btn' => $closeButton,
  150. 'fi-modal-window-has-content' => $hasContent,
  151. 'fi-modal-window-has-footer' => $hasFooter,
  152. 'fi-modal-window-has-icon' => $hasIcon,
  153. 'fi-modal-window-has-sticky-header' => $stickyHeader,
  154. 'fi-hidden' => ! $visible,
  155. ($alignment instanceof Alignment) ? "fi-align-{$alignment->value}" : null,
  156. ($width instanceof Width) ? "fi-width-{$width->value}" : (is_string($width) ? $width : null),
  157. ])
  158. }}
  159. >
  160. @if ($heading || $header)
  161. <div
  162. @if (filled($id))
  163. wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.header"
  164. @endif
  165. @class([
  166. 'fi-modal-header',
  167. 'fi-sticky' => $stickyHeader,
  168. 'fi-vertical-align-center' => $hasIcon && $hasHeading && (! $hasDescription) && in_array($alignment, [Alignment::Start, Alignment::Left]),
  169. ])
  170. >
  171. @if ($closeButton)
  172. <x-filament::icon-button
  173. color="gray"
  174. :icon="\Filament\Support\Icons\Heroicon::OutlinedXMark"
  175. :icon-alias="\Filament\Support\View\SupportIconAlias::MODAL_CLOSE_BUTTON"
  176. icon-size="lg"
  177. :label="__('filament::components/modal.actions.close.label')"
  178. tabindex="-1"
  179. :x-on:click="$closeEventHandler"
  180. class="fi-modal-close-btn"
  181. />
  182. @endif
  183. @if ($header)
  184. {{ $header }}
  185. @else
  186. @if ($hasIcon)
  187. <div class="fi-modal-icon-ctn">
  188. <div
  189. {{ (new ComponentAttributeBag)->color(IconComponent::class, $iconColor)->class(['fi-modal-icon-bg']) }}
  190. >
  191. {{ \Filament\Support\generate_icon_html($icon, $iconAlias, size: \Filament\Support\Enums\IconSize::Large) }}
  192. </div>
  193. </div>
  194. @endif
  195. <div>
  196. <h2 class="fi-modal-heading">
  197. {{ $heading }}
  198. </h2>
  199. @if ($hasDescription)
  200. <p class="fi-modal-description">
  201. {{ $description }}
  202. </p>
  203. @endif
  204. </div>
  205. @endif
  206. </div>
  207. @endif
  208. @if ($hasContent)
  209. <div
  210. @if (filled($id))
  211. wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.content"
  212. @endif
  213. class="fi-modal-content"
  214. >
  215. {{ $slot }}
  216. </div>
  217. @endif
  218. @if ($hasFooter)
  219. <div
  220. @if (filled($id))
  221. wire:key="{{ isset($this) ? "{$this->getId()}." : '' }}modal.{{ $id }}.footer"
  222. @endif
  223. @class([
  224. 'fi-modal-footer',
  225. 'fi-sticky' => $stickyFooter,
  226. ($footerActionsAlignment instanceof Alignment) ? "fi-align-{$footerActionsAlignment->value}" : null,
  227. ])
  228. >
  229. @if (! \Filament\Support\is_slot_empty($footer))
  230. {{ $footer }}
  231. @else
  232. <div class="fi-modal-footer-actions">
  233. @if (is_array($footerActions))
  234. @foreach ($footerActions as $action)
  235. {{ $action }}
  236. @endforeach
  237. @else
  238. {{ $footerActions }}
  239. @endif
  240. </div>
  241. @endif
  242. </div>
  243. @endif
  244. </{{ filled($wireSubmitHandler) ? 'form' : 'div' }}>
  245. </div>
  246. </div>
  247. @if (filled($teleport))
  248. {!! '</template>' !!}
  249. {{-- Avoid formatting issues with unclosed elements --}}
  250. @endif
  251. @if ($trigger)
  252. {!! '</div>' !!}
  253. {{-- Avoid formatting issues with unclosed elements --}}
  254. @endif