diff --git a/packages/admin/src/Resources/Resource.php b/packages/admin/src/Resources/Resource.php index 7e00ae3ea4..30b5ed6f57 100644 --- a/packages/admin/src/Resources/Resource.php +++ b/packages/admin/src/Resources/Resource.php @@ -17,9 +17,14 @@ use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Route; use Illuminate\Support\Str; use Illuminate\Support\Stringable; +use Illuminate\Support\Traits\Macroable; class Resource { + use Macroable { + __call as dynamicMacroCall; + } + protected static ?string $breadcrumb = null; protected static bool $isGloballySearchable = true; diff --git a/packages/forms/docs/03-fields.md b/packages/forms/docs/03-fields.md index d9ba3a749e..ee3d2d2764 100644 --- a/packages/forms/docs/03-fields.md +++ b/packages/forms/docs/03-fields.md @@ -316,6 +316,30 @@ TextInput::make('password') For more complex autocomplete options, text inputs also support [datalists](#datalists). +#### Phone number validation + +When using a `tel()` field, the value will be validated using: `/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\.\/0-9]*$/`. + +If you wish to change that, then you can use the `telRegex()` method: + +```php +use Filament\Forms\Components\TextInput; + +TextInput::make('phone') + ->tel() + ->telRegex('/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\.\/0-9]*$/') +``` + +Alternatively, to customize the `telRegex()` across all fields, use a service provider: + +```php +use Filament\Forms\Components\TextInput; + +TextInput::configureUsing(function (TextInput $component): void { + $component->telRegex('/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\.\/0-9]*$/'); +}); +``` + ### Affixes You may place text before and after the input using the `prefix()` and `suffix()` methods: diff --git a/packages/forms/src/Components/TextInput.php b/packages/forms/src/Components/TextInput.php index 4a61edd7d3..e4465aeb8c 100644 --- a/packages/forms/src/Components/TextInput.php +++ b/packages/forms/src/Components/TextInput.php @@ -40,6 +40,8 @@ class TextInput extends Field implements Contracts\CanBeLengthConstrained, CanHa protected $minValue = null; + protected string | Closure | null $telRegex = null; + protected string | Closure | null $type = null; public function currentPassword(bool | Closure $condition = true): static @@ -129,7 +131,14 @@ class TextInput extends Field implements Contracts\CanBeLengthConstrained, CanHa { $this->isTel = $condition; - $this->regex(static fn (TextInput $component) => $component->evaluate($condition) ? '/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\.\/0-9]*$/' : null); + $this->regex(static fn (TextInput $component) => $component->evaluate($condition) ? $component->getTelRegex() : null); + + return $this; + } + + public function telRegex(string | Closure | null $regex): static + { + $this->telRegex = $regex; return $this; } @@ -206,6 +215,11 @@ class TextInput extends Field implements Contracts\CanBeLengthConstrained, CanHa return 'text'; } + public function getTelRegex(): string + { + return $this->evaluate($this->telRegex) ?? '/^[+]*[(]{0,1}[0-9]{1,4}[)]{0,1}[-\s\.\/0-9]*$/'; + } + public function hasMask(): bool { return $this->configureMaskUsing !== null; diff --git a/packages/forms/src/Concerns/InteractsWithForms.php b/packages/forms/src/Concerns/InteractsWithForms.php index 93ca726ac8..1277e35f5f 100644 --- a/packages/forms/src/Concerns/InteractsWithForms.php +++ b/packages/forms/src/Concerns/InteractsWithForms.php @@ -7,6 +7,7 @@ use Filament\Forms\ComponentContainer; use Illuminate\Contracts\View\View; use Illuminate\Database\Eloquent\Model; use Illuminate\Validation\ValidationException; +use Livewire\Exceptions\PropertyNotFoundException; use Livewire\TemporaryUploadedFile; use Livewire\WithFileUploads; @@ -27,15 +28,19 @@ trait InteractsWithForms public function __get($property) { - if ((! $this->isCachingForms) && $form = $this->getCachedForm($property)) { - return $form; - } + try { + return parent::__get($property); + } catch (PropertyNotFoundException $exception) { + if ((! $this->isCachingForms) && $form = $this->getCachedForm($property)) { + return $form; + } - if ($property === 'modal') { - return $this->getModalViewOnce(); - } + if ($property === 'modal') { + return $this->getModalViewOnce(); + } - return parent::__get($property); + throw $exception; + } } protected function getModalViewOnce(): ?View diff --git a/tests/src/Forms/ComputedPropertyTest.php b/tests/src/Forms/ComputedPropertyTest.php new file mode 100644 index 0000000000..c40f67252f --- /dev/null +++ b/tests/src/Forms/ComputedPropertyTest.php @@ -0,0 +1,37 @@ +getSchema() + ->toBeArray() + ->sequence( + fn (Expectation $expect) => $expect->toBeInstanceOf(TextInput::class) + ); +}); + +class ComputedPropertySchema extends Livewire +{ + public function getFormSchema(): array + { + return $this->schema; + } + + public function getSchemaProperty() + { + return [ + TextInput::make(''), + ]; + } + + public function getSchema() + { + return $this->schema; + } +}