Add option group support

This commit is contained in:
Dan Harrin
2023-07-30 00:52:38 +01:00
parent e6b9909063
commit 88ec9e9ba0
16 changed files with 107 additions and 44 deletions
@@ -196,6 +196,26 @@ class FieldsDemo extends Component implements HasForms
'livewire' => 'Laravel Livewire',
]),
]),
Group::make()
->id('groupedSelect')
->extraAttributes([
'class' => 'px-16 pt-16 pb-96 max-w-xl',
])
->schema([
Select::make('groupedSelect')
->label('Status')
->searchable()
->options([
'In Process' => [
'draft' => 'Draft',
'reviewing' => 'Reviewing',
],
'Reviewed' => [
'published' => 'Published',
'rejected' => 'Rejected',
],
]),
]),
Group::make()
->id('createSelectOption')
->extraAttributes([
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

+14
View File
@@ -425,6 +425,20 @@ export default {
await new Promise((resolve) => setTimeout(resolve, 500))
},
},
'forms/fields/select/grouped': {
url: 'forms/fields',
selector: '#groupedSelect',
viewport: {
width: 1920,
height: 640,
deviceScaleFactor: 3,
},
before: async (page) => {
await page.click('#groupedSelect .choices')
await new Promise((resolve) => setTimeout(resolve, 500))
},
},
'forms/fields/select/create-option': {
url: 'forms/fields',
selector: '#createSelectOption',
+1 -1
View File
File diff suppressed because one or more lines are too long
+23 -16
View File
@@ -18,22 +18,6 @@ Select::make('status')
])
```
You can optionally also add groups by adding an array instead of a label in the options:
```php
use Filament\Forms\Components\Select;
Select::make('status')
->options([
'In Process' => [
'draft' => 'Draft',
'reviewing' => 'Reviewing',
],
'published' => 'Published',
])
```
<AutoScreenshot name="forms/fields/select/simple" alt="Select" version="3.x" />
## Searching options
@@ -112,6 +96,29 @@ Select::make('technologies')
->getOptionLabelsUsing(fn (array $values): array => Technology::whereIn('id', $values)->pluck('name', 'id')->toArray()),
```
## Grouping options
You can group options together under a label, to organize them better. To do this, you can pass an array of groups to `options()` or wherever you would normally pass an array of options. The keys of the array are used as group labels, and the values are arrays of options in that group:
```php
use Filament\Forms\Components\Select;
Select::make('status')
->searchable()
->options([
'In Process' => [
'draft' => 'Draft',
'reviewing' => 'Reviewing',
],
'Reviewed' => [
'published' => 'Published',
'rejected' => 'Rejected',
],
])
```
<AutoScreenshot name="forms/fields/select/grouped" alt="Grouped select" version="3.x" />
## Integrating with an Eloquent relationship
> If you're building a form inside your Livewire component, make sure you have set up the [form's model](../adding-a-form-to-a-livewire-component#setting-a-form-model). Otherwise, Filament doesn't know which model to use to retrieve the relationship from.
@@ -170,5 +170,6 @@ select:not(.choices) {
}
.choices__group {
@apply p-2 pt-6 text-gray-400 first:pt-2 dark:text-gray-500;
@apply p-2 text-gray-400 first:pt-2 dark:text-gray-500;
@apply pt-4 first:pt-2 !important;
}
@@ -57,15 +57,15 @@
@foreach ($getOptions() as $value => $label)
@if (is_array($label))
<optgroup label="{{ $value }}">
@foreach ($label as $v => $l)
@foreach ($label as $groupedValue => $groupedLabel)
<option
@disabled($isOptionDisabled($v, $l))
value="{{ $v }}"
@disabled($isOptionDisabled($groupedValue, $groupedLabel))
value="{{ $groupedValue }}"
>
@if ($isHtmlAllowed)
{!! $l !!}
{!! $groupedLabel !!}
@else
{{ $l }}
{{ $groupedLabel }}
@endif
</option>
@endforeach
@@ -10,12 +10,12 @@ use Illuminate\Support\Collection;
trait HasOptions
{
/**
* @var array<string> | Arrayable | string | Closure | null
* @var array<string | array<string>> | Arrayable | string | Closure | null
*/
protected array | Arrayable | string | Closure | null $options = null;
/**
* @param array<string> | Arrayable | string | Closure | null $options
* @param array<string | array<string>> | Arrayable | string | Closure | null $options
*/
public function options(array | Arrayable | string | Closure | null $options): static
{
@@ -25,7 +25,7 @@ trait HasOptions
}
/**
* @return array<string>
* @return array<string | array<string>>
*/
public function getOptions(): array
{
+31 -10
View File
@@ -18,7 +18,6 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\Relation;
use Illuminate\Database\Query\JoinClause;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Illuminate\Validation\Rules\Exists;
@@ -119,11 +118,25 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
});
$this->getOptionLabelUsing(static function (Select $component, $value): ?string {
if (array_key_exists($value, $options = $component->getOptions())) {
return $options[$value];
$options = $component->getOptions();
foreach ($options as $groupedOptions) {
if (! is_array($groupedOptions)) {
continue;
}
if (! array_key_exists($value, $groupedOptions)) {
continue;
}
return $groupedOptions[$value];
}
return $value;
if (! array_key_exists($value, $options)) {
return $value;
}
return $options[$value];
});
$this->getOptionLabelsUsing(static function (Select $component, array $values): array {
@@ -132,12 +145,20 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
$labels = [];
foreach ($values as $value) {
foreach ($options as $group => $option) {
if (is_array($option) && Arr::has($option, $value)) {
Arr::set($labels, "$group.$value", $option[$value]);
continue 2;
foreach ($options as $groupedOptions) {
if (! is_array($groupedOptions)) {
continue;
}
if (! array_key_exists($value, $groupedOptions)) {
continue;
}
$labels[$value] = $groupedOptions[$value];
continue 2;
}
$labels[$value] = $options[$value] ?? $value;
}
@@ -610,8 +631,8 @@ class Select extends Field implements Contracts\HasAffixActions, Contracts\HasNe
}
/**
* @param array<string> $options
* @return array<array{'label': string, 'value': string}>
* @param array<string | array<string>> $options
* @return array<array<string, mixed>>
*/
protected function transformOptionsForJs(array $options): array
{
@@ -10,7 +10,7 @@ use Illuminate\Support\Collection;
trait HasOptions
{
/**
* @var array<string> | Arrayable | class-string | Closure | null
* @var array<string | array<string>> | Arrayable | class-string | Closure | null
*/
protected array | Arrayable | string | Closure | null $options = null;
@@ -21,7 +21,7 @@ trait HasOptions
protected ?Closure $getSearchResultsUsing = null;
/**
* @param array<string> | Arrayable | class-string | Closure | null $options
* @param array<string | array<string>> | Arrayable | class-string | Closure | null $options
*/
public function options(array | Arrayable | string | Closure | null $options): static
{
@@ -31,7 +31,7 @@ trait HasOptions
}
/**
* @return array<string>
* @return array<string | array<string>>
*/
public function getOptions(): array
{