diff --git a/source/php/Component/Select/Select.php b/source/php/Component/Select/Select.php index d35dd03d..1b21117d 100644 --- a/source/php/Component/Select/Select.php +++ b/source/php/Component/Select/Select.php @@ -4,6 +4,8 @@ class Select extends \ComponentLibrary\Component\BaseController { + public const AUTO_ENABLE_SEARCH_THRESHOLD = 7; + public function init() { //Extract array for eazy access (fetch only) @@ -106,6 +108,19 @@ public function init() } return $boolean ? false : ''; }; + + $this->data = $this->mapSearch($this->data); + } + + private function mapSearch(array $data): array { + + if(!isset($data['search']) || is_null($data['search'])) { + if(count($data['options']) > static::AUTO_ENABLE_SEARCH_THRESHOLD) { + $data['search'] = true; + } + } + + return $data; } private function getIconSize($fieldSize = 'md'): string diff --git a/source/php/Component/Select/SelectTest.php b/source/php/Component/Select/SelectTest.php new file mode 100644 index 00000000..f8e0e5cf --- /dev/null +++ b/source/php/Component/Select/SelectTest.php @@ -0,0 +1,68 @@ +assertInstanceOf(Select::class, $select); + } + + /** + * @testdox auto enables search when options exceed threshold + */ + public function testAutoEnablesSearchWhenOptionsExceedThreshold(): void { + $createOption = fn(int $i) => [ 'value' => "option_{$i}", 'label' => "Option {$i}" ]; + $options = array_map($createOption, range(0, Select::AUTO_ENABLE_SEARCH_THRESHOLD)); + + $select = new Select( + static::getData(['options' => $options]), + static::createCache(), + static::createTagSanitizer() + ); + + $this->assertTrue($select->getData()['search']); + } + + static function getData(array $merge = []): array { + return array_merge([ + 'size' => 'md', + 'options' => [], + 'preselected' => false + ], $merge); + } + + private static function createCache():CacheInterface { + return new class implements CacheInterface { + public function get(string $key, ?string $group = null): mixed + { + return null; + } + public function set(string $key, mixed $data, ?string $group = null): void + { + } + }; + } + + private static function createTagSanitizer() { + return new class implements TagSanitizerInterface{ + public function removeATags(string $string): string + { + return $string; + } + }; + } +} + \ No newline at end of file diff --git a/source/php/Component/Select/partials/action.blade.php b/source/php/Component/Select/partials/action.blade.php index 969fe7e4..0ecd2c83 100644 --- a/source/php/Component/Select/partials/action.blade.php +++ b/source/php/Component/Select/partials/action.blade.php @@ -1,5 +1,5 @@
-
- {{ $placeholder && $isMultiSelect ? $placeholder : '' }} -
+
+ {{ $placeholder && $isMultiSelect ? $placeholder : '' }} +
\ No newline at end of file diff --git a/source/php/Component/Select/partials/dropdown.blade.php b/source/php/Component/Select/partials/dropdown.blade.php index a8d59eb8..c70359b0 100644 --- a/source/php/Component/Select/partials/dropdown.blade.php +++ b/source/php/Component/Select/partials/dropdown.blade.php @@ -5,4 +5,5 @@ @include('Select.partials.dropdown_item') @endforeach + @includeWhen($search, 'Select.partials.searchNoResults') \ No newline at end of file diff --git a/source/php/Component/Select/partials/search.blade.php b/source/php/Component/Select/partials/search.blade.php new file mode 100644 index 00000000..0f8d8314 --- /dev/null +++ b/source/php/Component/Select/partials/search.blade.php @@ -0,0 +1,8 @@ +@field([ + 'type' => 'search', + 'icon' => ['icon' => 'search'], + 'placeholder' => "Search", + 'classList' => [ $baseClass . '__search-field' ], + 'attributeList' => [ 'data-js-select-search-input' => true ], + 'size' => 'sm', +]) @endfield \ No newline at end of file diff --git a/source/php/Component/Select/partials/searchNoResults.blade.php b/source/php/Component/Select/partials/searchNoResults.blade.php new file mode 100644 index 00000000..03462496 --- /dev/null +++ b/source/php/Component/Select/partials/searchNoResults.blade.php @@ -0,0 +1,7 @@ +@typography([ + 'element' => 'div', + 'classList' => [ $baseClass . '__search-no-results' ], + 'attributeList' => ['aria-hidden' => 'true'] +]) + {{ $searchNoResultsText }} +@endtypography diff --git a/source/php/Component/Select/select.blade.php b/source/php/Component/Select/select.blade.php index 71eb8764..6aa18d38 100644 --- a/source/php/Component/Select/select.blade.php +++ b/source/php/Component/Select/select.blade.php @@ -53,6 +53,7 @@ @includeWhen($clearButtonEnabled, 'Select.partials.clear') @include('Select.partials.action') + @includeWhen($search, 'Select.partials.search') @include('Select.partials.dropdown') @include('Select.partials.error') diff --git a/source/php/Component/Select/select.json b/source/php/Component/Select/select.json index bf127fe2..d32cb305 100644 --- a/source/php/Component/Select/select.json +++ b/source/php/Component/Select/select.json @@ -16,7 +16,9 @@ "size": "md", "maxSelections": false, "hidePlaceholder": false, - "selectAttributeList": [] + "selectAttributeList": [], + "search": null, + "searchNoResultsText": "No results found" }, "description": { "label": "The placeholder of the dropdown", @@ -33,7 +35,9 @@ "size": "The size of the select component (sm, md, lg)", "maxSelections": "The maximum number of selections allowed. Will only be applied if \"multiple\" is true.", "hidePlaceholder": "Hides the placeholder but keeps the label", - "selectAttributeList": "Ann array with attributes that will be set on the actual select element." + "selectAttributeList": "Ann array with attributes that will be set on the actual select element.", + "search": "Enables a search input within the select dropdown.", + "searchNoResultsText": "The text to show when no results are found in the search." }, "view": "select.blade.php", "dependency": {