mergeConfigFrom(__DIR__.'/../config/livewire-material.php', 'livewire-material'); $this->disableBladeIconsComponent(); $this->registerErrorViews(); $this->registerMailComponents(); } public function boot(): void { $this->loadViewsFrom(__DIR__.'/../resources/views', 'livewire-material'); $this->loadTranslationsFrom(__DIR__.'/../lang', 'livewire-material'); $this->registerComponents(); $this->registerPagination(); $this->registerShowcase(); if ($this->app->runningInConsole()) { $this->commands([ Console\SchemeCommand::class, ]); $this->publishes([ __DIR__.'/../config/livewire-material.php' => config_path('livewire-material.php'), ], 'livewire-material-config'); $this->publishes([ static::errorViewPath().'/errors' => resource_path('views/errors'), ], 'livewire-material-errors'); $this->publishes([ static::mailComponentPath().'/html' => resource_path('views/vendor/mail/html'), static::mailComponentPath().'/text' => resource_path('views/vendor/mail/text'), ], 'livewire-material-mail'); } } /** * The anonymous components. Blade names their view namespace after a hash of this string, and * compiled views keep that name, so it stays written the way it always was. */ public static function componentPath(): string { return __DIR__.'/../resources/views/components'; } /** * The error-view root: a folder holding only `errors/`. */ public static function errorViewPath(): string { return dirname(__DIR__).'/resources/views/error-pages'; } /** * The mail component root, laid out like the framework's: `html/` and `text/`. */ public static function mailComponentPath(): string { return dirname(__DIR__).'/resources/views/mail'; } /** * Append the error-view root to `view.paths`, after the application's own. * * The exception handler replaces the `errors` namespace each time it renders an HTTP * exception, with every entry of `view.paths` plus `/errors` and the framework's views last * (RegisterErrorViewPaths), so a namespace added with addNamespace() is gone by then; only a * view path survives. That config is read at render time, but also once when the view * finder is built: appended here, in register(), before any boot() resolves the view * factory, the finder and `view:cache` see the same paths the handler does. Appending keeps * `view.paths[0]` — Laravel's viewPath() — the application's, and puts the application's * own `resources/views/errors` first. Idempotent, since a cached config already holds it. */ protected function registerErrorViews(): void { $paths = (array) config('view.paths', []); if (! in_array(static::errorViewPath(), $paths, true)) { config(['view.paths' => [...$paths, static::errorViewPath()]]); } } /** * Put the package's mail header and message after the application's own mail components, * when `livewire-material.mail.components` asks for it. Off by default: it changes every * Markdown mail the application sends, theme or not, and the framework reads * `mail.markdown.paths` once, when the Markdown renderer is first made — after register(). */ protected function registerMailComponents(): void { if (! config('livewire-material.mail.components')) { return; } $paths = (array) config('mail.markdown.paths', []); if (! in_array(static::mailComponentPath(), $paths, true)) { config(['mail.markdown.paths' => [...$paths, static::mailComponentPath()]]); } } /** * Register the components as anonymous Blade components under the configured prefix, or * under `livewire-material` without one. * * A compiled `` names the view namespace Blade derives from the prefix, or from the * component folder's absolute path when there is none. That path differs between a laptop and * a container sharing `storage/framework/views`, or between release directories, while the * compiled file's name does not — so a view compiled on one showed `a1b2…::button` as text on * the other. A prefix does not stop an unprefixed tag resolving. The path's namespace stays * registered, so views compiled before this release still render until they are recompiled. * * The package's own views never go through this registration: they write * ``, which resolves through the view namespace whatever the * prefix, and which an application's own `` cannot shadow. */ protected function registerComponents(): void { Blade::anonymousComponentPath( static::componentPath(), filled(config('livewire-material.prefix')) ? config('livewire-material.prefix') : 'livewire-material', ); View::addNamespace(hash('xxh128', static::componentPath()), static::componentPath()); } /** * Put the M3 paginators in front of Laravel's and Livewire's own. Prepended to their * namespaces rather than set as the default view, because Livewire sets its own default on * every render; an application's published `vendor/pagination` or `vendor/livewire` views are * looked up before any namespace path, so they still win. */ protected function registerPagination(): void { if (! config('livewire-material.pagination')) { return; } $this->callAfterResolving('view', function (Factory $view): void { $view->prependNamespace('pagination', __DIR__.'/../resources/views/pagination/laravel'); $view->prependNamespace('livewire', __DIR__.'/../resources/views/pagination/livewire'); }); } /** * blade-icons registers a class-based of its own, and Blade resolves a * registered class alias before any anonymous component path, so ours would never * render. It reads the key in its boot(); a booting callback runs after every * register() — so after blade-icons merges its defaults over the key — and before * any provider boots. */ protected function disableBladeIconsComponent(): void { $this->app->booting(function (): void { config(['blade-icons.components.default' => null]); }); } /** * Mount the showcase when it is enabled. */ protected function registerShowcase(): void { // Registered even with the showcase off: `php artisan view:cache` compiles every view in the // package's namespace, the showcase's pages included, and must resolve there. Blade::anonymousComponentPath(__DIR__.'/../resources/views/showcase/components', 'showcase'); if (! config('livewire-material.showcase.enabled')) { return; } if ($this->app->routesAreCached()) { return; } Route::middleware(config('livewire-material.showcase.middleware')) ->prefix(config('livewire-material.showcase.path')) ->name('livewire-material.') ->group(__DIR__.'/../routes/showcase.php'); } }