mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
fix: Strip characters for numeric input (#19454)
This commit is contained in:
@@ -6,6 +6,7 @@ use Closure;
|
||||
use Filament\Schemas\Components\Concerns\CanStripCharactersFromState;
|
||||
use Filament\Schemas\Components\Concerns\CanTrimState;
|
||||
use Filament\Schemas\Components\Contracts\HasAffixActions;
|
||||
use Filament\Schemas\Components\StateCasts\StripCharactersStateCast;
|
||||
use Filament\Support\Concerns\HasColor;
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes;
|
||||
use Filament\Support\Concerns\HasReorderAnimationDuration;
|
||||
@@ -175,17 +176,21 @@ class TagsInput extends Field implements Contracts\HasNestedRecursiveValidationR
|
||||
return (bool) $this->evaluate($this->isReorderable);
|
||||
}
|
||||
|
||||
public function getDefaultStateCasts(): array
|
||||
{
|
||||
return [
|
||||
...parent::getDefaultStateCasts(),
|
||||
...($this->hasStripCharacters() ? [app(StripCharactersStateCast::class, ['characters' => $this->getStripCharacters()])] : []),
|
||||
];
|
||||
}
|
||||
|
||||
public function mutateDehydratedState(mixed $state): mixed
|
||||
{
|
||||
if (is_array($state)) {
|
||||
$state = array_map(function (mixed $value): mixed {
|
||||
$value = $this->stripCharactersFromState($value);
|
||||
$value = $this->trimState($value);
|
||||
|
||||
return $value;
|
||||
return $this->trimState($value);
|
||||
}, $state);
|
||||
} else {
|
||||
$state = $this->stripCharactersFromState($state);
|
||||
$state = $this->trimState($state);
|
||||
}
|
||||
|
||||
@@ -211,7 +216,7 @@ class TagsInput extends Field implements Contracts\HasNestedRecursiveValidationR
|
||||
|
||||
public function mutatesDehydratedState(): bool
|
||||
{
|
||||
return parent::mutatesDehydratedState() || $this->hasStripCharacters() || $this->isTrimmed();
|
||||
return parent::mutatesDehydratedState() || $this->isTrimmed();
|
||||
}
|
||||
|
||||
public function mutatesStateForValidation(): bool
|
||||
|
||||
@@ -9,6 +9,7 @@ use Filament\Schemas\Components\Concerns\CanTrimState;
|
||||
use Filament\Schemas\Components\Contracts\HasAffixActions;
|
||||
use Filament\Schemas\Components\StateCasts\Contracts\StateCast;
|
||||
use Filament\Schemas\Components\StateCasts\NumberStateCast;
|
||||
use Filament\Schemas\Components\StateCasts\StripCharactersStateCast;
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes;
|
||||
use Filament\Support\RawJs;
|
||||
use LogicException;
|
||||
@@ -302,13 +303,13 @@ class TextInput extends Field implements CanHaveNumericState, Contracts\CanBeLen
|
||||
{
|
||||
return [
|
||||
...parent::getDefaultStateCasts(),
|
||||
...($this->hasStripCharacters() ? [app(StripCharactersStateCast::class, ['characters' => $this->getStripCharacters()])] : []),
|
||||
...($this->isNumeric() ? [app(NumberStateCast::class, ['isNullable' => true])] : []),
|
||||
];
|
||||
}
|
||||
|
||||
public function mutateDehydratedState(mixed $state): mixed
|
||||
{
|
||||
$state = $this->stripCharactersFromState($state);
|
||||
$state = $this->trimState($state);
|
||||
|
||||
return parent::mutateDehydratedState($state);
|
||||
@@ -324,7 +325,7 @@ class TextInput extends Field implements CanHaveNumericState, Contracts\CanBeLen
|
||||
|
||||
public function mutatesDehydratedState(): bool
|
||||
{
|
||||
return parent::mutatesDehydratedState() || $this->hasStripCharacters() || $this->isTrimmed();
|
||||
return parent::mutatesDehydratedState() || $this->isTrimmed();
|
||||
}
|
||||
|
||||
public function mutatesStateForValidation(): bool
|
||||
|
||||
@@ -6,6 +6,7 @@ use Closure;
|
||||
use Filament\Forms\Components\Concerns\CanDisableGrammarly;
|
||||
use Filament\Schemas\Components\Concerns\CanStripCharactersFromState;
|
||||
use Filament\Schemas\Components\Concerns\CanTrimState;
|
||||
use Filament\Schemas\Components\StateCasts\StripCharactersStateCast;
|
||||
use Filament\Support\Concerns\HasExtraAlpineAttributes;
|
||||
|
||||
class Textarea extends Field implements Contracts\CanBeLengthConstrained
|
||||
@@ -67,9 +68,16 @@ class Textarea extends Field implements Contracts\CanBeLengthConstrained
|
||||
return (bool) $this->evaluate($this->shouldAutosize);
|
||||
}
|
||||
|
||||
public function getDefaultStateCasts(): array
|
||||
{
|
||||
return [
|
||||
...parent::getDefaultStateCasts(),
|
||||
...($this->hasStripCharacters() ? [app(StripCharactersStateCast::class, ['characters' => $this->getStripCharacters()])] : []),
|
||||
];
|
||||
}
|
||||
|
||||
public function mutateDehydratedState(mixed $state): mixed
|
||||
{
|
||||
$state = $this->stripCharactersFromState($state);
|
||||
$state = $this->trimState($state);
|
||||
|
||||
return parent::mutateDehydratedState($state);
|
||||
@@ -85,7 +93,7 @@ class Textarea extends Field implements Contracts\CanBeLengthConstrained
|
||||
|
||||
public function mutatesDehydratedState(): bool
|
||||
{
|
||||
return parent::mutatesDehydratedState() || $this->hasStripCharacters() || $this->isTrimmed();
|
||||
return parent::mutatesDehydratedState() || $this->isTrimmed();
|
||||
}
|
||||
|
||||
public function mutatesStateForValidation(): bool
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace Filament\Schemas\Components\StateCasts;
|
||||
|
||||
use Filament\Schemas\Components\StateCasts\Contracts\StateCast;
|
||||
|
||||
class StripCharactersStateCast implements StateCast
|
||||
{
|
||||
/**
|
||||
* @param array<string> $characters
|
||||
*/
|
||||
public function __construct(
|
||||
protected array $characters = [],
|
||||
) {}
|
||||
|
||||
public function get(mixed $state): mixed
|
||||
{
|
||||
if (empty($this->characters)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
if (is_array($state)) {
|
||||
return array_map(fn (mixed $value): mixed => is_string($value) ? str_replace($this->characters, '', $value) : $value, $state);
|
||||
}
|
||||
|
||||
if (! is_string($state)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
return str_replace($this->characters, '', $state);
|
||||
}
|
||||
|
||||
public function set(mixed $state): mixed
|
||||
{
|
||||
if (empty($this->characters)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
if (is_array($state)) {
|
||||
return array_map(fn (mixed $value): mixed => is_string($value) ? str_replace($this->characters, '', $value) : $value, $state);
|
||||
}
|
||||
|
||||
if (! is_string($state)) {
|
||||
return $state;
|
||||
}
|
||||
|
||||
return str_replace($this->characters, '', $state);
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,40 @@ it('can trim whitespace from TextInput', function (mixed $input, mixed $expected
|
||||
[123, 123],
|
||||
]);
|
||||
|
||||
it('can strip characters before applying `numeric()` state cast', function (mixed $input, mixed $expected): void {
|
||||
livewire(TestComponentWithNumericAndStripCharacters::class)
|
||||
->fillForm(['price' => $input])
|
||||
->call('save')
|
||||
->assertSet('data.price', $expected);
|
||||
})->with([
|
||||
['1,234.56', 1234.56],
|
||||
['1,234,567.89', 1234567.89],
|
||||
['999.99', 999.99],
|
||||
['1,000', 1000.0],
|
||||
[null, null],
|
||||
]);
|
||||
|
||||
class TestComponentWithNumericAndStripCharacters extends Livewire
|
||||
{
|
||||
public $data = [];
|
||||
|
||||
public function form(Schema $form): Schema
|
||||
{
|
||||
return $form
|
||||
->schema([
|
||||
TextInput::make('price')
|
||||
->numeric()
|
||||
->stripCharacters(','),
|
||||
])
|
||||
->statePath('data');
|
||||
}
|
||||
|
||||
public function save(): void
|
||||
{
|
||||
$this->data = $this->form->getState();
|
||||
}
|
||||
}
|
||||
|
||||
class TestComponentWithTextInputTrim extends Livewire
|
||||
{
|
||||
public $data = [];
|
||||
|
||||
Reference in New Issue
Block a user