diff --git a/UPGRADING.md b/UPGRADING.md
new file mode 100644
index 00000000..48446df2
--- /dev/null
+++ b/UPGRADING.md
@@ -0,0 +1,10 @@
+# Upgrading
+
+Because there are many breaking changes an upgrade is not that easy. There are many edge cases this guide does not cover. We accept PRs to improve this guide.
+
+## From v0 to v1
+
+- It now includes a basic set of components. It can optionally be disabled in `config/wireuse.php`.
+- The `classFor` behavior has been changed. You now need to specify the class attribute: ` `.
+- The `spatie/laravel-model-states` package is now not registered by default. You now need to register `ModelStateObjectSynth::class` manually in a `Service Provider`.
+- The `CreateForm` and `UpdateForm` classes have been removed.
diff --git a/composer.json b/composer.json
index 47a49177..bc528d0f 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,6 @@
"illuminate/contracts": "^10.0|^11.0",
"laravel/scout": "^10.0|^11.0",
"livewire/livewire": "^3.4",
- "spatie/laravel-model-states": "^2.7",
"spatie/laravel-package-tools": "^1.16.3",
"spatie/php-structure-discoverer": "^2.1"
},
@@ -36,6 +35,7 @@
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan-deprecation-rules": "^1.1.4",
"phpstan/phpstan-phpunit": "^1.3.16",
+ "spatie/laravel-model-states": "^2.7",
"spatie/laravel-ray": "^1.35.1"
},
"autoload": {
diff --git a/config/wireuse.php b/config/wireuse.php
index 630fd84e..510ab2ee 100644
--- a/config/wireuse.php
+++ b/config/wireuse.php
@@ -11,4 +11,26 @@
*/
'register_macros' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Components
+ |--------------------------------------------------------------------------
+ |
+ | This controls components registration.
+ |
+ */
+
+ 'register_components' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Views
+ |--------------------------------------------------------------------------
+ |
+ | This controls views registration.
+ |
+ */
+
+ 'view_prefix' => 'wireuse',
];
diff --git a/resources/css/presets/tailwind.config.preset.js b/resources/css/presets/tailwind.config.preset.js
new file mode 100644
index 00000000..d7f3248b
--- /dev/null
+++ b/resources/css/presets/tailwind.config.preset.js
@@ -0,0 +1,8 @@
+import forms from '@tailwindcss/forms';
+import typography from '@tailwindcss/typography';
+
+/** @type {import('tailwindcss').Config} */
+export default {
+ content: ['./resources/**/*.blade.php', './app/View/**/*.php', './src/**/*.php', './vendor/foxws/wireuse/**/*.blade.php'],
+ plugins: [forms, typography],
+};
diff --git a/resources/views/.gitkeep b/resources/views/.gitkeep
new file mode 100644
index 00000000..e69de29b
diff --git a/resources/views/actions/button.blade.php b/resources/views/actions/button.blade.php
new file mode 100644
index 00000000..097923a5
--- /dev/null
+++ b/resources/views/actions/button.blade.php
@@ -0,0 +1,20 @@
+cssClass([
+ 'layer' => 'inline-flex shrink-0 cursor-pointer items-center justify-center',
+ 'primary' => 'py-1.5 px-3 bg-primary-500 rounded border border-primary-500',
+ ])
+ ->mergeAttributes($action->getComponentAttributes())
+ ->classMerge([
+ 'layer',
+ 'primary' => $attributes->get('type') === 'submit',
+ ])
+ ->merge([
+ 'aria-label' => $label(),
+ ])
+}}>
+ @if ($slot->isEmpty())
+ {{ $label() }}
+ @else
+ {{ $slot }}
+ @endif
+
diff --git a/resources/views/actions/icon.blade.php b/resources/views/actions/icon.blade.php
new file mode 100644
index 00000000..9470b1d3
--- /dev/null
+++ b/resources/views/actions/icon.blade.php
@@ -0,0 +1,29 @@
+
cssClass([
+ 'layer' => 'inline-flex items-center justify-center',
+ 'icon' => 'size-6 sm:size-7',
+ ])
+ ->classMerge([
+ 'layer',
+ ])
+}}>
+ @if ($iconName() && filled($action->getState()))
+
+
+ @if ($hasActiveIcon())
+
+ @endif
+ @elseif ($iconName())
+
+ @endif
+
diff --git a/resources/views/actions/link.blade.php b/resources/views/actions/link.blade.php
new file mode 100644
index 00000000..a23e0520
--- /dev/null
+++ b/resources/views/actions/link.blade.php
@@ -0,0 +1,24 @@
+cssClass([
+ 'layer' => 'inline-flex shrink-0 cursor-pointer items-center justify-center',
+ 'active' => 'text-primary-400 hover:text-primary-300',
+ 'inactive' => 'text-secondary-400 hover:text-primary-400',
+ ])
+ ->mergeAttributes($action->getComponentAttributes())
+ ->classMerge([
+ 'layer',
+ 'active' => $isCurrent(),
+ 'inactive' => ! $isCurrent(),
+ ])
+ ->merge([
+ 'wire:navigate' => $navigate(),
+ 'href' => $url(),
+ 'aria-label' => $label(),
+ ])
+}}>
+ @if ($slot->isEmpty())
+ {{ $label() }}
+ @else
+ {{ $slot }}
+ @endif
+
diff --git a/resources/views/auth/login.blade.php b/resources/views/auth/login.blade.php
new file mode 100644
index 00000000..88918348
--- /dev/null
+++ b/resources/views/auth/login.blade.php
@@ -0,0 +1,19 @@
+
diff --git a/resources/views/auth/logout.blade.php b/resources/views/auth/logout.blade.php
new file mode 100644
index 00000000..9a277598
--- /dev/null
+++ b/resources/views/auth/logout.blade.php
@@ -0,0 +1,3 @@
+
+ {{-- redirecting --}}
+
diff --git a/resources/views/auth/register.blade.php b/resources/views/auth/register.blade.php
new file mode 100644
index 00000000..33515c48
--- /dev/null
+++ b/resources/views/auth/register.blade.php
@@ -0,0 +1,3 @@
+
diff --git a/resources/views/components/forms/actions.blade.php b/resources/views/components/forms/actions.blade.php
new file mode 100644
index 00000000..ed11a469
--- /dev/null
+++ b/resources/views/components/forms/actions.blade.php
@@ -0,0 +1,16 @@
+@props([
+ 'actions',
+])
+
+
+
+
+ @foreach ($actions as $action)
+
+
+ {{ $action->getLabel() }}
+
+ @endforeach
+
+
+
diff --git a/resources/views/components/forms/checkbox.blade.php b/resources/views/components/forms/checkbox.blade.php
new file mode 100644
index 00000000..25f85175
--- /dev/null
+++ b/resources/views/components/forms/checkbox.blade.php
@@ -0,0 +1,15 @@
+ cssClass([
+ 'layer' => 'peer shrink-0',
+ 'error' => 'border-red-500',
+ ])
+ ->classMerge([
+ 'layer',
+ 'error' => $errors->has($wireModel()),
+ ])
+ ->merge([
+ 'wire:key' => $wireKey(),
+ 'id' => $wireKey(),
+ 'type' => 'checkbox',
+ ])
+}}>
diff --git a/resources/views/components/forms/input.blade.php b/resources/views/components/forms/input.blade.php
new file mode 100644
index 00000000..e0869c5a
--- /dev/null
+++ b/resources/views/components/forms/input.blade.php
@@ -0,0 +1,53 @@
+@props([
+ 'prepend' => null,
+ 'append' => null,
+ 'label' => null,
+ 'hint' => null,
+])
+
+cssClass([
+ 'layer' => 'flex flex-col gap-1.5 w-full',
+ 'input' => 'p-3 h-10 w-full text-base bg-secondary-800/90 border-secondary-500/50 focus:border-secondary-500 focus:border-2 focus:ring-0',
+ 'label' => 'flex items-center',
+ 'error' => '!border-red-500',
+ 'hint' => 'py-3 text-xs',
+ 'message' => 'text-red-500 text-sm',
+ ])
+ ->classMerge([
+ 'layer',
+ ])
+ ->only('class')
+}}>
+
+ {{ $label }}
+
+
+ {{ $prepend }}
+
+
classMerge([
+ 'input',
+ 'error' => $errors->has($attributes->wireModel()),
+ ])
+ ->merge([
+ ...['id' => $attributes->wireKey(), 'type' => 'text'],
+ ...$attributes->whereStartsWith('wire:model')
+ ])
+ }} />
+
+ {{ $append }}
+
+ @if ($hint)
+
{{ $hint }}
+ @endif
+
+ @error($attributes->wireKey())
+
+ {{ $message }}
+
+ @enderror
+
diff --git a/resources/views/components/forms/label.blade.php b/resources/views/components/forms/label.blade.php
new file mode 100644
index 00000000..f5fdc631
--- /dev/null
+++ b/resources/views/components/forms/label.blade.php
@@ -0,0 +1,36 @@
+@props([
+ 'id',
+ 'label' => null,
+ 'required' => false,
+ 'hint' => null,
+])
+
+cssClass([
+ 'layer' => 'flex items-center text-sm font-medium cursor-pointer',
+ 'error' => 'text-red-500',
+ 'hint' => 'pt-1 text-red-500',
+ 'required' => 'px-1 text-primary-400',
+ ])
+ ->classMerge([
+ 'layer',
+ 'error' => $errors->has($id),
+ ])
+ ->merge([
+ 'for' => $id,
+ ])
+}}>
+ {{ $slot }}
+
+ {{ $label }}
+
+ @if ($required)
+ *
+ @endif
+
+ @if ($hint)
+
+ {{ $hint }}
+
+ @endif
+
diff --git a/resources/views/components/forms/messages.blade.php b/resources/views/components/forms/messages.blade.php
new file mode 100644
index 00000000..f52f02b3
--- /dev/null
+++ b/resources/views/components/forms/messages.blade.php
@@ -0,0 +1,14 @@
+@if (flash()->message)
+ cssClass([
+ 'layer' => 'flex gap-3 w-full',
+ 'success' => 'bg-primary-500 rounded text-base p-3 text-sm font-medium',
+ ])
+ ->classMerge([
+ 'layer',
+ 'success' => flash()->level === 'success',
+ ])
+ }}>
+ {{ flash()->message }}
+
+@endif
diff --git a/resources/views/components/forms/tags.blade.php b/resources/views/components/forms/tags.blade.php
new file mode 100644
index 00000000..a3403df8
--- /dev/null
+++ b/resources/views/components/forms/tags.blade.php
@@ -0,0 +1,84 @@
+@props([
+ 'prepend' => null,
+ 'append' => null,
+ 'label' => null,
+ 'hint' => null,
+ 'items' => [],
+])
+
+cssClass([
+ 'layer' => 'flex flex-col gap-y-3 relative',
+ 'items' => 'flex items-start gap-2 pt-1 w-full',
+ 'item' => 'inline-flex items-center gap-2 px-2 py-1 rounded-xs text-xs bg-secondary-500',
+ 'error' => '!border-red-500',
+ ])
+ ->classMerge([
+ 'layer',
+ ])
+ ->merge([
+ 'x-data' => 'tags',
+ 'x-modelable' => 'tags',
+ ])
+}}>
+
+
+
+
+
+
+
+@script
+
+@endscript
diff --git a/resources/views/navigation/tabs.blade.php b/resources/views/navigation/tabs.blade.php
new file mode 100644
index 00000000..3dde89a0
--- /dev/null
+++ b/resources/views/navigation/tabs.blade.php
@@ -0,0 +1,39 @@
+@php
+ $current = $this->getPropertyValue($wireModel())
+@endphp
+
+cssClass([
+ 'layer' => 'flex items-center px-3 gap-x-5 overflow-x-auto border-b border-secondary-500/50',
+ 'tab' => 'py-3 gap-x-1.5 border-b',
+ 'tab-icon' => 'size-5 sm:size-6',
+ 'tab-active' => 'border-primary-400 text-primary-400',
+ 'tab-inactive' => 'border-secondary-400 text-secondary-400',
+ ])
+ ->classMerge([
+ 'layer',
+ ])
+ ->merge([
+ 'x-data' => '{ active: null }',
+ 'x-modelable' => 'active',
+ ])
+}}>
+ @foreach ($tabs as $action)
+
+
+
+ {{ $action->getLabel() }}
+
+ @endforeach
+
diff --git a/src/Actions/Components/Button.php b/src/Actions/Components/Button.php
new file mode 100644
index 00000000..57790fd9
--- /dev/null
+++ b/src/Actions/Components/Button.php
@@ -0,0 +1,26 @@
+action->getLabel() ?: $this->action->getName();
+ }
+}
diff --git a/src/Actions/Components/Icon.php b/src/Actions/Components/Icon.php
new file mode 100644
index 00000000..793c9ccd
--- /dev/null
+++ b/src/Actions/Components/Icon.php
@@ -0,0 +1,45 @@
+isCurrent()) {
+ return $this->action->getActiveIcon();
+ }
+
+ return $this->action->getIcon();
+ }
+
+ public function isCurrent(): bool
+ {
+ if ($this->active === $this->action->getName()) {
+ return true;
+ }
+
+ return $this->action->routeIs() || $this->action->fullUrlIs();
+ }
+
+ public function hasActiveIcon(): bool
+ {
+ return $this->action->getActiveIcon() !== $this->iconName();
+ }
+}
diff --git a/src/Actions/Components/Link.php b/src/Actions/Components/Link.php
new file mode 100644
index 00000000..a407b2ac
--- /dev/null
+++ b/src/Actions/Components/Link.php
@@ -0,0 +1,50 @@
+action->getLabel() ?: $this->action->getName();
+ }
+
+ public function url(): ?string
+ {
+ return $this->action->getRoute() ?: $this->action->getUrl();
+ }
+
+ public function navigate(): bool
+ {
+ if ($this->action->getWireNavigate() === false) {
+ return false;
+ }
+
+ return $this->action->routeExist() || $this->action->isAppUrl();
+ }
+
+ public function isCurrent(): bool
+ {
+ if ($this->active === $this->action->getName()) {
+ return true;
+ }
+
+ return $this->action->routeIs() || $this->action->fullUrlIs();
+ }
+}
diff --git a/src/Actions/Concerns/WithAction.php b/src/Actions/Concerns/WithAction.php
new file mode 100644
index 00000000..bcf58712
--- /dev/null
+++ b/src/Actions/Concerns/WithAction.php
@@ -0,0 +1,12 @@
+container = $container;
+
+ $this->name = $name;
+ }
+
+ public static function make(?string $name = null, ?array $attributes = null): static
+ {
+ return app(static::class, compact('name', 'attributes'));
+ }
+
+ public function add(string $name, ?Closure $callback = null, ?array $attributes = null): self
+ {
+ $node = new Action($this, $name);
+
+ if ($callback instanceof Closure) {
+ $callback($node);
+ }
+
+ if ($attributes) {
+ $node->attributes($attributes);
+ }
+
+ $this->addNode($node);
+
+ return $this;
+ }
+
+ public function addIf(string $name, mixed $condition = false, ?Closure $callback = null, ?array $attributes = null): self
+ {
+ if (value($condition)) {
+ $this->add($name, $callback, $attributes);
+ }
+
+ return $this;
+ }
+
+ public function getContainer(): mixed
+ {
+ return $this->value('container');
+ }
+
+ public function getContainers(): array
+ {
+ if (! $this->container) {
+ return [];
+ }
+
+ return array_merge($this->container->getContainers(), [$this->container]);
+ }
+
+ public function getDepth(): int
+ {
+ if (! $this->container) {
+ return 0;
+ }
+
+ return count($this->container->getContainers());
+ }
+
+ public function toArray(): array
+ {
+ return [
+ 'name' => $this->name,
+ 'container' => $this->container,
+ 'attributes' => $this->attributes,
+ ];
+ }
+}
diff --git a/src/Auth/Concerns/WithAuthentication.php b/src/Auth/Concerns/WithAuthentication.php
index f10c585a..67023fd3 100644
--- a/src/Auth/Concerns/WithAuthentication.php
+++ b/src/Auth/Concerns/WithAuthentication.php
@@ -25,4 +25,14 @@ protected static function getAuthKey(): int|string|null
{
return static::getAuthUser()?->getRouteKey();
}
+
+ protected static function can(string $ability, mixed $arguments = []): bool
+ {
+ return static::getAuthUser()->can($ability, $arguments);
+ }
+
+ protected static function cannot(string $ability, mixed $arguments = []): bool
+ {
+ return static::getAuthUser()->cannot($ability, $arguments);
+ }
}
diff --git a/src/Auth/Controllers/LoginController.php b/src/Auth/Controllers/LoginController.php
new file mode 100644
index 00000000..16124259
--- /dev/null
+++ b/src/Auth/Controllers/LoginController.php
@@ -0,0 +1,53 @@
+intended();
+ }
+ }
+
+ public function mount(): void
+ {
+ $this->seo()->setTitle(__('Login'));
+ $this->seo()->setDescription(__('Login to Account'));
+ }
+
+ public function render(): View
+ {
+ return view('wireuse::auth.login')->with([
+ 'actions' => $this->actions(),
+ ]);
+ }
+
+ public function submit(): void
+ {
+ $this->form->submit();
+
+ redirect()->intended();
+ }
+
+ protected function actions(): array
+ {
+ return [
+ Action::make('submit')
+ ->label(__('Login'))
+ ->componentAttributes([
+ 'type' => 'submit',
+ ]),
+ ];
+ }
+}
diff --git a/src/Auth/Controllers/LogoutController.php b/src/Auth/Controllers/LogoutController.php
new file mode 100644
index 00000000..b26f15dc
--- /dev/null
+++ b/src/Auth/Controllers/LogoutController.php
@@ -0,0 +1,36 @@
+seo()->setTitle(__('Logout'));
+ $this->seo()->setDescription(__('Account Logout'));
+
+ $this->submit();
+ }
+
+ public function render(): View
+ {
+ return view('wireuse::auth.logout');
+ }
+
+ public function submit(): Redirector
+ {
+ auth()->logout();
+
+ request()->session()->invalidate();
+
+ request()->session()->regenerateToken();
+
+ return redirect('/');
+ }
+}
diff --git a/src/Auth/Controllers/RegisterController.php b/src/Auth/Controllers/RegisterController.php
new file mode 100644
index 00000000..4376d3b6
--- /dev/null
+++ b/src/Auth/Controllers/RegisterController.php
@@ -0,0 +1,39 @@
+intended();
+ }
+ }
+
+ public function mount(): void
+ {
+ $this->seo()->setTitle(__('Register'));
+ $this->seo()->setDescription(__('Sign up'));
+ }
+
+ public function render(): View
+ {
+ return view('wireuse::auth.register');
+ }
+
+ public function submit(): void
+ {
+ $this->form->submit();
+
+ redirect()->to('/');
+ }
+}
diff --git a/src/Auth/Forms/LoginForm.php b/src/Auth/Forms/LoginForm.php
new file mode 100644
index 00000000..c890bd54
--- /dev/null
+++ b/src/Auth/Forms/LoginForm.php
@@ -0,0 +1,45 @@
+ 'required|email',
+ 'remember' => 'nullable|boolean',
+ 'password' => [
+ 'required',
+ Password::defaults(),
+ ],
+ ];
+ }
+
+ protected function handle(): void
+ {
+ if (! Auth::attempt($this->only('email', 'password'), $this->remember)) {
+ $this->addError('email', __('These credentials do not match our records'));
+
+ return;
+ }
+
+ session()->regenerate();
+ }
+}
diff --git a/src/Auth/Forms/RegisterForm.php b/src/Auth/Forms/RegisterForm.php
new file mode 100644
index 00000000..42bfdd90
--- /dev/null
+++ b/src/Auth/Forms/RegisterForm.php
@@ -0,0 +1,67 @@
+ 'required|email|unique:users',
+ 'password' => [
+ 'required',
+ 'confirmed',
+ Password::defaults(),
+ ],
+ 'password_confirmation' => [
+ 'required',
+ Password::defaults(),
+ ],
+ ];
+ }
+
+ protected function handle(): void
+ {
+ $user = $this->getUserModel()::create(
+ $this->getUserData()
+ );
+
+ request()->session()->regenerate();
+
+ auth()->login($user);
+
+ event(new Registered($user));
+ }
+
+ protected function getUserModel(): User
+ {
+ return app(config('auth.providers.users.model'));
+ }
+
+ protected function getUserData(): array
+ {
+ $data = $this->only('email', 'password');
+
+ $data['password'] = Hash::make($data['password']);
+
+ return $data;
+ }
+}
diff --git a/src/Facades/WireUse.php b/src/Facades/WireUse.php
index 5eeb741f..a60103ab 100644
--- a/src/Facades/WireUse.php
+++ b/src/Facades/WireUse.php
@@ -7,6 +7,7 @@
/**
* @see \Foxws\WireUse\WireUse
*
+ * @method static void routes()
* @method static void registerComponents(string $name, string $namespace, string $prefix, ?Closure $callback = null)
* @method static void registerLivewireComponents(string $name, string $namespace, string $prefix, ?Closure $callback = null)
* @method static Stringable componentName(DiscoveredClass $class, string $namespace, string $prefix)
diff --git a/src/Forms/Concerns/WithForm.php b/src/Forms/Concerns/WithForm.php
deleted file mode 100644
index d602188d..00000000
--- a/src/Forms/Concerns/WithForm.php
+++ /dev/null
@@ -1,105 +0,0 @@
-getType()->getName();
- }
-
- protected function toCollection(...$properties): Collection
- {
- return $properties
- ? new Collection($this->only(...$properties))
- : new Collection($this->all());
- }
-
- protected function toFluent(...$properties): Fluent
- {
- return $properties
- ? new Fluent($this->only(...$properties))
- : new Fluent($this->all());
- }
-
- protected function keys(): array
- {
- return array_keys($this->all());
- }
-
- public function get(string $property, mixed $default = null): mixed
- {
- return $this->getPropertyValue($property) ?: $default;
- }
-
- public function has(...$properties): bool
- {
- return $this->toCollection()
- ->has($properties);
- }
-
- public function contains(string $property, mixed $args): bool
- {
- $propertyValue = $this->get($property);
-
- if (is_array($propertyValue)) {
- return in_array($args, $propertyValue);
- }
-
- return $propertyValue === $args;
- }
-
- public function is(string $property, mixed $args = null): bool
- {
- return $this->get($property) == $args;
- }
-
- public function isStrict(string $property, mixed $args = null): bool
- {
- return $this->get($property) === $args;
- }
-
- public function filled(...$properties): bool
- {
- return $this->toCollection($properties)
- ->filter()
- ->isNotEmpty();
- }
-
- public function blank(...$properties): bool
- {
- return $this->toCollection($properties)
- ->filter()
- ->isEmpty();
- }
-
- public function clear(bool $submit = true): void
- {
- $properties = $this->keys();
-
- $this->reset($properties);
-
- if ($submit && method_exists($this, 'submit')) {
- $this->submit();
- }
- }
-
- public function fails($rules = null, $messages = [], $attributes = []): bool
- {
- try {
- $this->parentValidate($rules, $messages, $attributes);
- } catch (ValidationException $e) {
- return invade($e->validator)->fails();
- }
-
- return false;
- }
-}
diff --git a/src/Forms/Concerns/WithThrottle.php b/src/Forms/Concerns/WithThrottle.php
index d040c672..236d6573 100644
--- a/src/Forms/Concerns/WithThrottle.php
+++ b/src/Forms/Concerns/WithThrottle.php
@@ -3,11 +3,11 @@
namespace Foxws\WireUse\Forms\Concerns;
use Foxws\WireUse\Exceptions\RateLimitedException;
-use Foxws\WireUse\Support\Concerns\WithRateLimiting;
+use Foxws\WireUse\Views\Concerns\WithRateLimiter;
trait WithThrottle
{
- use WithRateLimiting;
+ use WithRateLimiter;
protected function handleThrottle(RateLimitedException $e): void
{
diff --git a/src/Forms/Support/Form.php b/src/Forms/Support/Form.php
index 04c9ac6c..a87d2837 100644
--- a/src/Forms/Support/Form.php
+++ b/src/Forms/Support/Form.php
@@ -4,17 +4,17 @@
use Foxws\WireUse\Auth\Concerns\WithAuthorization;
use Foxws\WireUse\Exceptions\RateLimitedException;
-use Foxws\WireUse\Forms\Concerns\WithForm;
use Foxws\WireUse\Forms\Concerns\WithSession;
use Foxws\WireUse\Forms\Concerns\WithThrottle;
use Foxws\WireUse\Forms\Concerns\WithValidation;
use Foxws\WireUse\Support\Concerns\WithHooks;
+use Illuminate\Support\Collection;
+use Illuminate\Support\Fluent;
use Livewire\Form as BaseForm;
abstract class Form extends BaseForm
{
use WithAuthorization;
- use WithForm;
use WithHooks;
use WithSession;
use WithThrottle;
@@ -47,4 +47,87 @@ protected function handle(): void
{
//
}
+
+ protected function keys(): array
+ {
+ return array_keys($this->all());
+ }
+
+ public function fill($values)
+ {
+ $values = $this->callHook('beforeFill', $values);
+
+ return parent::fill($values);
+ }
+
+ public function get(string $property, mixed $default = null): mixed
+ {
+ return $this->getPropertyValue($property) ?: $default;
+ }
+
+ public function has(...$properties): bool
+ {
+ return $this->toCollection()
+ ->has($properties);
+ }
+
+ public function contains(string $property, mixed $args): bool
+ {
+ $propertyValue = $this->get($property);
+
+ if (is_array($propertyValue)) {
+ return in_array($args, $propertyValue);
+ }
+
+ return $propertyValue === $args;
+ }
+
+ public function is(string $property, mixed $args = null): bool
+ {
+ return $this->get($property) == $args;
+ }
+
+ public function isStrict(string $property, mixed $args = null): bool
+ {
+ return $this->get($property) === $args;
+ }
+
+ public function filled(...$properties): bool
+ {
+ return $this->toCollection($properties)
+ ->filter()
+ ->isNotEmpty();
+ }
+
+ public function blank(...$properties): bool
+ {
+ return $this->toCollection($properties)
+ ->filter()
+ ->isEmpty();
+ }
+
+ public function clear(bool $submit = true): void
+ {
+ $properties = $this->keys();
+
+ $this->reset($properties);
+
+ if ($submit && method_exists($this, 'submit')) {
+ $this->submit();
+ }
+ }
+
+ protected function toCollection(...$properties): Collection
+ {
+ return $properties
+ ? new Collection($this->only(...$properties))
+ : new Collection($this->all());
+ }
+
+ protected function toFluent(...$properties): Fluent
+ {
+ return $properties
+ ? new Fluent($this->only(...$properties))
+ : new Fluent($this->all());
+ }
}
diff --git a/src/Models/Concerns/WithQueryBuilder.php b/src/Models/Concerns/WithQueryBuilder.php
index 47251919..192f1b86 100644
--- a/src/Models/Concerns/WithQueryBuilder.php
+++ b/src/Models/Concerns/WithQueryBuilder.php
@@ -12,8 +12,6 @@
*/
trait WithQueryBuilder
{
- protected static ?int $limit = 16;
-
public function bootWithQueryBuilder(): void
{
throw_if(! is_subclass_of($this->getModelClass(), Model::class));
@@ -33,18 +31,11 @@ protected static function getModel(): Model
protected static function getQuery(): Builder
{
- return static::getModel()
- ->newQuery();
+ return static::getModel()->newQuery();
}
protected static function getScout(string $query = '*', ?Closure $callback = null): ScoutBuilder
{
- return static::getModel()
- ->search($query, $callback);
- }
-
- protected static function getLimit(): ?int
- {
- return static::$limit;
+ return static::getModel()->search($query, $callback);
}
}
diff --git a/src/Models/Forms/CreateForm.php b/src/Models/Forms/CreateForm.php
deleted file mode 100644
index de02cb5b..00000000
--- a/src/Models/Forms/CreateForm.php
+++ /dev/null
@@ -1,29 +0,0 @@
-canCreate(static::modelClass());
-
- parent::submit();
- }
-
- protected function handle(): void
- {
- app(static::modelClass())::create(
- $this->all()
- );
- }
-
- protected static function modelClass(): ?string
- {
- return static::$model;
- }
-}
diff --git a/src/Models/Forms/UpdateForm.php b/src/Models/Forms/UpdateForm.php
deleted file mode 100644
index b84c2b4d..00000000
--- a/src/Models/Forms/UpdateForm.php
+++ /dev/null
@@ -1,34 +0,0 @@
-canUpdate($this->model);
-
- parent::submit();
- }
-
- public function delete(): void
- {
- $this->canDelete($this->model);
-
- $this->model->deleteOrFail();
- }
-
- protected function handle(): void
- {
- $this->model->updateOrFail(
- $this->all()
- );
- }
-}
diff --git a/src/Navigation/Components/Tabs.php b/src/Navigation/Components/Tabs.php
new file mode 100644
index 00000000..c5853d13
--- /dev/null
+++ b/src/Navigation/Components/Tabs.php
@@ -0,0 +1,25 @@
+getPropertyValue(
+ $this->getTabPath()
+ );
+
+ return $this->filterTabs($key)->first();
+ }
+
+ protected function tabs(): array
+ {
+ return [];
+ }
+
+ protected function getTabPath(): string
+ {
+ return 'tab';
+ }
+
+ protected function filterTabs(string $key): mixed
+ {
+ return collect($this->tabs())
+ ->where(function (mixed $item) use ($key) {
+ if ($item instanceof Action && $item->getName() === $key) {
+ return $item;
+ }
+ });
+ }
+}
diff --git a/src/States/Concerns/WithState.php b/src/States/Concerns/WithState.php
new file mode 100644
index 00000000..1dc04b62
--- /dev/null
+++ b/src/States/Concerns/WithState.php
@@ -0,0 +1,12 @@
+squish()
- ->split('/[\s,]+/')
- ->sort(fn (string $value) => str($value)->startsWith('!'))
- ->implode(' ');
+ $values ??= static::classAttributes($attributeBag);
+
+ return collect($values)
+ ->map(function (mixed $value = null, int|string $key) use ($attributeBag) {
+ if (is_bool($value) && $value === false) {
+ return;
+ }
+
+ $key = static::classKeys(
+ is_numeric($key) ? $value : $key
+ );
+
+ return $attributeBag->get($key->first(), '');
+ });
}
- public static function cssClassKey(...$keys): Collection
+ public static function classAttributes(ComponentAttributeBag $attributeBag): Collection
+ {
+ return str($attributeBag->whereStartsWith('class:'))->matchAll('/class:(.*?)\=/s');
+ }
+
+ public static function classKeys(...$keys): Collection
{
return collect($keys)
->map(fn (string $value) => str($value)->startsWith('class:') ? $value : "class:{$value}");
}
+
+ public static function sortClass(string $class = ''): string
+ {
+ return str($class)
+ ->squish()
+ ->split('/[\s,]+/')
+ ->sort(fn (string $value) => str($value)->startsWith('!'))
+ ->implode(' ');
+ }
}
diff --git a/src/Support/Components/Component.php b/src/Support/Components/Component.php
new file mode 100644
index 00000000..6445fedc
--- /dev/null
+++ b/src/Support/Components/Component.php
@@ -0,0 +1,24 @@
+ $value) {
+ $this->attributes[$key] = $value;
+ }
+
+ return $this;
+ }
+}
diff --git a/src/Support/Components/Concerns/HasComponent.php b/src/Support/Components/Concerns/HasComponent.php
new file mode 100644
index 00000000..6c2debfd
--- /dev/null
+++ b/src/Support/Components/Concerns/HasComponent.php
@@ -0,0 +1,30 @@
+component = $component;
+
+ return $this;
+ }
+
+ public function componentAttributes(?array $attributes = null): static
+ {
+ $this->componentAttributes = $attributes;
+
+ return $this;
+ }
+
+ public function getComponent(): ?string
+ {
+ return $this->value('component');
+ }
+
+ public function getComponentAttributes(): array
+ {
+ return $this->value('componentAttributes', []);
+ }
+}
diff --git a/src/Support/Components/Concerns/HasIcon.php b/src/Support/Components/Concerns/HasIcon.php
new file mode 100644
index 00000000..78f45105
--- /dev/null
+++ b/src/Support/Components/Concerns/HasIcon.php
@@ -0,0 +1,30 @@
+icon = $icon;
+
+ return $this;
+ }
+
+ public function iconActive(?string $icon = null): static
+ {
+ $this->iconActive = $icon;
+
+ return $this;
+ }
+
+ public function getIcon(): ?string
+ {
+ return $this->value('icon');
+ }
+
+ public function getActiveIcon(): ?string
+ {
+ return $this->value('iconActive', $this->getIcon());
+ }
+}
diff --git a/src/Support/Components/Concerns/HasLabel.php b/src/Support/Components/Concerns/HasLabel.php
new file mode 100644
index 00000000..0cf11796
--- /dev/null
+++ b/src/Support/Components/Concerns/HasLabel.php
@@ -0,0 +1,18 @@
+label = $label;
+
+ return $this;
+ }
+
+ public function getLabel(): ?string
+ {
+ return $this->value('label');
+ }
+}
diff --git a/src/Support/Components/Concerns/HasLivewire.php b/src/Support/Components/Concerns/HasLivewire.php
new file mode 100644
index 00000000..e562e418
--- /dev/null
+++ b/src/Support/Components/Concerns/HasLivewire.php
@@ -0,0 +1,37 @@
+wireModel = $value;
+
+ $this->wireModifier = $modifier;
+
+ return $this;
+ }
+
+ public function wireNavigate(?bool $value = true): static
+ {
+ $this->wireNavigate = $value;
+
+ return $this;
+ }
+
+ public function getWireModel(): ?string
+ {
+ return $this->value('wireModel');
+ }
+
+ public function getWireModifier(): ?string
+ {
+ return $this->value('wireModifier');
+ }
+
+ public function getWireNavigate(): ?bool
+ {
+ return $this->value('wireNavigate');
+ }
+}
diff --git a/src/Support/Components/Concerns/HasName.php b/src/Support/Components/Concerns/HasName.php
new file mode 100644
index 00000000..a6c7505e
--- /dev/null
+++ b/src/Support/Components/Concerns/HasName.php
@@ -0,0 +1,18 @@
+name = $name;
+
+ return $this;
+ }
+
+ public function getName(): ?string
+ {
+ return $this->value('name');
+ }
+}
diff --git a/src/Support/Components/Concerns/HasNodes.php b/src/Support/Components/Concerns/HasNodes.php
new file mode 100644
index 00000000..17bafe3a
--- /dev/null
+++ b/src/Support/Components/Concerns/HasNodes.php
@@ -0,0 +1,55 @@
+nodes;
+ }
+
+ public function getNode(string $key): mixed
+ {
+ return null;
+ }
+
+ public function fillNodes(array $nodes = []): self
+ {
+ $this->validateNodes($nodes);
+
+ $this->nodes = $nodes;
+
+ return $this;
+ }
+
+ public function addNode(mixed $node = null): self
+ {
+ $this->validateNode($node);
+
+ $this->nodes[] = value($node, $this->getNodeArgs());
+
+ return $this;
+ }
+
+ protected function validateNode(mixed $node = null): void
+ {
+ //
+ }
+
+ protected function validateNodes(array $nodes = []): void
+ {
+ collect($nodes)
+ ->each(fn (mixed $node) => $this->validateNode($node));
+ }
+
+ protected function getNodeArgs(): array
+ {
+ return [];
+ }
+}
diff --git a/src/Support/Components/Concerns/HasRequest.php b/src/Support/Components/Concerns/HasRequest.php
new file mode 100644
index 00000000..26285680
--- /dev/null
+++ b/src/Support/Components/Concerns/HasRequest.php
@@ -0,0 +1,30 @@
+url = $url;
+
+ return $this;
+ }
+
+ public function getUrl(): ?string
+ {
+ return $this->value('url');
+ }
+
+ public function isAppUrl(): bool
+ {
+ $url = str($this->value('url', ''))->trim();
+
+ return $url->is('/') || $url->startsWith(config('app.url'));
+ }
+
+ public function fullUrlIs(): bool
+ {
+ return ($url = $this->getUrl()) && request()->fullUrlIs($url);
+ }
+}
diff --git a/src/Support/Components/Concerns/HasRouting.php b/src/Support/Components/Concerns/HasRouting.php
new file mode 100644
index 00000000..693859a9
--- /dev/null
+++ b/src/Support/Components/Concerns/HasRouting.php
@@ -0,0 +1,57 @@
+route = $route;
+
+ $this->routeParameters = $parameters;
+
+ $this->routeAbsolute = $absolute;
+
+ return $this;
+ }
+
+ public function getRoute(): ?string
+ {
+ if (! $this->getRouteName()) {
+ return null;
+ }
+
+ return route(
+ $this->getRouteName(),
+ $this->getRouteParameters(),
+ $this->getRouteAbsolute(),
+ );
+ }
+
+ public function getRouteName(): ?string
+ {
+ return $this->value('route');
+ }
+
+ public function getRouteParameters(): mixed
+ {
+ return $this->value('routeParameters', []);
+ }
+
+ public function getRouteAbsolute(): bool
+ {
+ return $this->value('routeAbsolute', true);
+ }
+
+ public function routeIs(): bool
+ {
+ return ($route = $this->getRouteName()) && request()->routeIs($route);
+ }
+
+ public function routeExist(): bool
+ {
+ return ($route = $this->getRouteName()) && Route::has($route);
+ }
+}
diff --git a/src/Support/Components/Concerns/HasState.php b/src/Support/Components/Concerns/HasState.php
new file mode 100644
index 00000000..75875201
--- /dev/null
+++ b/src/Support/Components/Concerns/HasState.php
@@ -0,0 +1,30 @@
+state = $state;
+
+ return $this;
+ }
+
+ public function default(mixed $default = null): static
+ {
+ $this->default = $default;
+
+ return $this;
+ }
+
+ public function getState(): mixed
+ {
+ return $this->value('state');
+ }
+
+ public function getDefault(): mixed
+ {
+ return $this->value('default');
+ }
+}
diff --git a/src/Support/Components/Concerns/HasVisibility.php b/src/Support/Components/Concerns/HasVisibility.php
new file mode 100644
index 00000000..65724767
--- /dev/null
+++ b/src/Support/Components/Concerns/HasVisibility.php
@@ -0,0 +1,30 @@
+visible = $visible;
+
+ return $this;
+ }
+
+ public function hidden(?bool $hidden = true): static
+ {
+ $this->hidden = $hidden;
+
+ return $this;
+ }
+
+ public function getVisible(): ?bool
+ {
+ return $this->value('visible');
+ }
+
+ public function getHidden(): ?bool
+ {
+ return $this->value('hidden');
+ }
+}
diff --git a/src/Support/Concerns/WithHooks.php b/src/Support/Concerns/WithHooks.php
index 5883b013..5b67b7c6 100644
--- a/src/Support/Concerns/WithHooks.php
+++ b/src/Support/Concerns/WithHooks.php
@@ -4,12 +4,12 @@
trait WithHooks
{
- protected function callHook(string $hook, ...$args): mixed
+ protected function callHook(string $hook, mixed $args = null): mixed
{
if (method_exists($this, $hook)) {
- return $this->{$hook}(...$args);
+ return $this->{$hook}($args);
}
- return value($hook, $args);
+ return value($args);
}
}
diff --git a/src/Support/Discover/ComponentScout.php b/src/Support/Discover/ComponentScout.php
index 6d139fd0..681ee8e9 100644
--- a/src/Support/Discover/ComponentScout.php
+++ b/src/Support/Discover/ComponentScout.php
@@ -35,7 +35,7 @@ public function cacheDriver(): FileDiscoverCacheDriver
public function prefix(string $prefix): static
{
- $this->prefix = $prefix;
+ $this->prefix = trim($prefix, '-');
return $this;
}
diff --git a/src/Support/Livewire/ActionObjects/ActionObjectSynth.php b/src/Support/Livewire/ActionObjects/ActionObjectSynth.php
new file mode 100644
index 00000000..b48256d5
--- /dev/null
+++ b/src/Support/Livewire/ActionObjects/ActionObjectSynth.php
@@ -0,0 +1,37 @@
+toArray(), []];
+ }
+
+ public function hydrate($value)
+ {
+ $action = new Action($value['container'], $value['name']);
+
+ $action->attributes($this->getAttributes($value));
+
+ return $action;
+ }
+
+ protected function getAttributes(array $values): array
+ {
+ return collect($values)
+ ->except('container', 'name')
+ ->toArray();
+ }
+}
diff --git a/src/Support/Livewire/ActionObjects/SupportActionObjects.php b/src/Support/Livewire/ActionObjects/SupportActionObjects.php
new file mode 100644
index 00000000..c2e97897
--- /dev/null
+++ b/src/Support/Livewire/ActionObjects/SupportActionObjects.php
@@ -0,0 +1,15 @@
+propertySynthesizer(
+ ActionObjectSynth::class
+ );
+ }
+}
diff --git a/src/Support/Livewire/StateObjects/State.php b/src/Support/Livewire/StateObjects/State.php
index 83a22eb1..c3590ef4 100644
--- a/src/Support/Livewire/StateObjects/State.php
+++ b/src/Support/Livewire/StateObjects/State.php
@@ -2,7 +2,7 @@
namespace Foxws\WireUse\Support\Livewire\StateObjects;
-use Foxws\WireUse\Auth\Concerns\WithAuthorization;
+use Foxws\WireUse\Support\Concerns\WithHooks;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Database\Eloquent\Model;
use Livewire\Component;
@@ -10,7 +10,7 @@
class State implements Arrayable
{
- use WithAuthorization;
+ use WithHooks;
public function __construct(
protected Component $component,
diff --git a/src/Views/Concerns/WithLayout.php b/src/Views/Concerns/WithLayout.php
new file mode 100644
index 00000000..0589982c
--- /dev/null
+++ b/src/Views/Concerns/WithLayout.php
@@ -0,0 +1,15 @@
+attributes->get(
+ app(Bladeable::class)::classKeys($key)->first(), $default
+ );
+ }
+}
diff --git a/src/Views/Concerns/WithLivewire.php b/src/Views/Concerns/WithLivewire.php
index 79fc21b9..bed878e6 100644
--- a/src/Views/Concerns/WithLivewire.php
+++ b/src/Views/Concerns/WithLivewire.php
@@ -14,7 +14,7 @@ public function wireKey(): string
public function wireModel(): ?string
{
- return $this->attributes->whereStartsWith('wire:model')->first();
+ return $this->attributes->wireModel();
}
public function uuid(): UuidInterface|string
diff --git a/src/Support/Concerns/WithRateLimiting.php b/src/Views/Concerns/WithRateLimiter.php
similarity index 95%
rename from src/Support/Concerns/WithRateLimiting.php
rename to src/Views/Concerns/WithRateLimiter.php
index 2a24cab0..77a04d57 100644
--- a/src/Support/Concerns/WithRateLimiting.php
+++ b/src/Views/Concerns/WithRateLimiter.php
@@ -1,11 +1,11 @@
group(function () {
+ Route::get('/login', LoginController::class)->middleware('guest')->name('login');
+ Route::get('/register', RegisterController::class)->middleware('guest')->name('register');
+ Route::post('/logout', LogoutController::class)->name('logout');
+ });
+ }
+
public static function registerComponents(
string $path,
string $namespace = 'App\\',
diff --git a/src/WireUseServiceProvider.php b/src/WireUseServiceProvider.php
index f407ae71..64802604 100644
--- a/src/WireUseServiceProvider.php
+++ b/src/WireUseServiceProvider.php
@@ -3,6 +3,7 @@
namespace Foxws\WireUse;
use Foxws\WireUse\Support\Blade\Bladeable;
+use Illuminate\Support\Facades\Blade;
use Illuminate\View\ComponentAttributeBag;
use Spatie\LaravelPackageTools\Commands\InstallCommand;
use Spatie\LaravelPackageTools\Package;
@@ -15,6 +16,7 @@ public function configurePackage(Package $package): void
$package
->name('wireuse')
->hasConfigFile()
+ ->hasViews()
->hasInstallCommand(function (InstallCommand $command) {
$command
->publishConfigFile();
@@ -30,13 +32,16 @@ public function bootingPackage(): void
{
$this
->registerFeatures()
- ->registerBladeMacros();
+ ->registerBladeMacros()
+ ->registerAnonymousComponent()
+ ->registerComponents()
+ ->registerLivewire();
}
protected function registerFeatures(): static
{
foreach ([
- \Foxws\WireUse\Support\Livewire\ModelStateObjects\SupportModelStateObjects::class,
+ \Foxws\WireUse\Support\Livewire\ActionObjects\SupportActionObjects::class,
\Foxws\WireUse\Support\Livewire\StateObjects\SupportStateObjects::class,
] as $feature) {
app('livewire')->componentHook($feature);
@@ -54,7 +59,7 @@ protected function registerBladeMacros(): static
ComponentAttributeBag::macro('cssClass', function (array $values = []): ComponentAttributeBag {
/** @var ComponentAttributeBag $this */
foreach ($values as $key => $value) {
- $key = app(Bladeable::class)->cssClassKey($key)->first();
+ $key = app(Bladeable::class)::classKeys($key)->first();
if (! $this->has($key)) {
$this->offsetSet($key, $value);
@@ -66,70 +71,114 @@ protected function registerBladeMacros(): static
ComponentAttributeBag::macro('classMerge', function (?array $values = null): ComponentAttributeBag {
/** @var ComponentAttributeBag $this */
- $values ??= str($this->whereStartsWith('class:'))->matchAll('/class:(.*?)\=/s');
-
- $classList = collect($values)
- ->map(function (mixed $value, int|string $key) {
- if (is_bool($value) && $value === false) {
- return;
- }
-
- $key = app(Bladeable::class)->cssClassKey(
- is_numeric($key) ? $value : $key
- );
-
- return $this->get($key->first(), '');
- })
+ $classes = app(Bladeable::class)::classMerged($this, $values)
->merge($this->get('class'))
->join(' ');
- $this->offsetSet('class', $classList);
+ $this->offsetSet('class', $classes);
return $this
- ->classSort()
- ->classWithout();
+ ->sortClass()
+ ->withoutClass();
});
- ComponentAttributeBag::macro('classFor', function (string $key, ?string $default = null): ComponentAttributeBag {
+ ComponentAttributeBag::macro('sortClass', function (): ComponentAttributeBag {
/** @var ComponentAttributeBag $this */
- $value = $this->get(app(Bladeable::class)->cssClassKey($key)->first(), $default ?? '');
+ $value = app(Bladeable::class)->sortClass(
+ $this->get('class', '')
+ );
$this->offsetSet('class', $value);
- return $this
- ->classSort()
- ->classWithout();
+ return $this;
});
- ComponentAttributeBag::macro('classAny', function (...$keys): ComponentAttributeBag {
+ ComponentAttributeBag::macro('withoutClass', function (): ComponentAttributeBag {
/** @var ComponentAttributeBag $this */
- $value = $this->only(app(Bladeable::class)->cssClassKey($keys));
-
- $this->offsetSet('class', $value->join(' '));
return $this
- ->classSort()
- ->classWithout();
+ ->whereDoesntStartWith('class:');
});
- ComponentAttributeBag::macro('classSort', function (): ComponentAttributeBag {
+ ComponentAttributeBag::macro('withoutWireModel', function (): ComponentAttributeBag {
/** @var ComponentAttributeBag $this */
- $classList = app(Bladeable::class)->classSort(
- $this->get('class', '')
- );
- $this->offsetSet('class', $classList);
+ return $this
+ ->whereDoesntStartWith('wire:model');
+ });
+
+ ComponentAttributeBag::macro('mergeAttributes', function (array $values = []): ComponentAttributeBag {
+ /** @var ComponentAttributeBag $this */
+ foreach ($values as $key => $value) {
+ $this->offsetSet($key, $value);
+ }
return $this;
});
- ComponentAttributeBag::macro('classWithout', function (): ComponentAttributeBag {
+ ComponentAttributeBag::macro('classFor', function (string $key, string $default = ''): string {
/** @var ComponentAttributeBag $this */
+ $class = app(Bladeable::class)::classKeys($key)->first();
- return $this
- ->whereDoesntStartWith('class:');
+ return $this->get($class, $default);
});
+ ComponentAttributeBag::macro('wireModel', function (): mixed {
+ /** @var ComponentAttributeBag $this */
+
+ return $this->whereStartsWith('wire:model')->first();
+ });
+
+ ComponentAttributeBag::macro('wireKey', function (): mixed {
+ /** @var ComponentAttributeBag $this */
+
+ return $this->wireModel() ?: $this->first('id');
+ });
+
+ return $this;
+ }
+
+ protected function registerAnonymousComponent(): static
+ {
+ if (config('wireuse.register_components') === false) {
+ return $this;
+ }
+
+ Blade::anonymousComponentPath(
+ path: __DIR__.'/resources/views/components',
+ prefix: 'wireuse'
+ );
+
+ return $this;
+ }
+
+ protected function registerComponents(): static
+ {
+ if (config('wireuse.register_components') === false) {
+ return $this;
+ }
+
+ WireUse::registerComponents(
+ path: __DIR__,
+ namespace: 'Foxws\\WireUse\\',
+ prefix: config('wireuse.view_prefix'),
+ );
+
+ return $this;
+ }
+
+ protected function registerLivewire(): static
+ {
+ if (config('wireuse.register_components') === false) {
+ return $this;
+ }
+
+ WireUse::registerLivewireComponents(
+ path: __DIR__,
+ namespace: 'Foxws\\WireUse\\',
+ prefix: config('wireuse.view_prefix'),
+ );
+
return $this;
}
}