Skip to content

Commit

Permalink
Fix highlighting selected items after scrolling
Browse files Browse the repository at this point in the history
  • Loading branch information
macocci7 committed Apr 7, 2024
1 parent 3b5e6b0 commit 4cd0c97
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 1 deletion.
22 changes: 22 additions & 0 deletions src/Themes/Default/Concerns/Number.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Laravel\Prompts\Themes\Default\Concerns;

Trait Number
{
/**
* Determine whether the values are consecutive integers.
*
* @param array<int|string, int> $values
* @return bool
*/
protected function isConsecutive(array $values): bool
{
return count($values) > 0 && array_filter($values, 'is_int') === $values
? range(
array_slice($values, 0, 1)[0],
array_slice($values, 0, 1)[0] + count($values) - 1
) === $values
: false;
}
}
3 changes: 2 additions & 1 deletion src/Themes/Default/MultiSearchPromptRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class MultiSearchPromptRenderer extends Renderer implements Scrolling
{
use Concerns\DrawsBoxes;
use Concerns\DrawsScrollbars;
use Concerns\Number;

/**
* Render the suggest prompt.
Expand Down Expand Up @@ -115,7 +116,7 @@ protected function renderOptions(MultiSearchPrompt $prompt): string
->map(function ($label, $key) use ($prompt) {
$index = array_search($key, array_keys($prompt->matches()));
$active = $index === $prompt->highlighted;
$selected = array_is_list($prompt->visible())
$selected = $this->isConsecutive(array_keys($prompt->visible()))
? in_array($label, $prompt->value())
: in_array($key, $prompt->value());

Expand Down
100 changes: 100 additions & 0 deletions tests/Feature/MultiSearchPromptTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,106 @@
],
]);

it('supports scrolled results', function ($options, $expected) {
Prompt::fake([
'B', // Search for "Blue"
Key::UP, // Highlight "Blue"
Key::SPACE, // Select "Blue"
Key::UP, // Highlight "Blue"
Key::UP, // Highlight "Blue"
Key::SPACE, // Select "Blue"
Key::BACKSPACE, // Clear search
'G', // Search for "Green"
Key::UP, // Highlight "Green"
Key::SPACE, // Select "Green"
Key::UP, // Highlight "Green"
Key::UP, // Highlight "Green"
Key::SPACE, // Select "Green"
Key::BACKSPACE, // Clear search
Key::ENTER, // Confirm selection
]);

$result = multisearch(
label: 'What are your favorite colors?',
placeholder: 'Search...',
options: $options,
);

Prompt::assertStrippedOutputContains(<<<'OUTPUT'
┌ What are your favorite colors? ──────────────────────────────┐
│ Search... │
└────────────────────────────────────────────────── 0 selected ┘
OUTPUT);

Prompt::assertStrippedOutputContains(<<<'OUTPUT'
│ Search... │
├──────────────────────────────────────────────────────────────┤
│ ◼ Blue-900 │
│ ◼ Blue-700 │
│ ◼ Green-700 │
│ ◼ Green-500 │
└────────────────────────────────────────────────── 4 selected ┘
OUTPUT);

Prompt::assertStrippedOutputContains(<<<'OUTPUT'
┌ What are your favorite colors? ──────────────────────────────┐
│ Blue-900 │
│ Blue-700 │
│ Green-700 │
│ Green-500 │
└──────────────────────────────────────────────────────────────┘
OUTPUT);

expect($result)->toBe($expected);
})->with([
'associative' => [
fn ($value) => strlen($value) > 0 ? collect([
'red' => 'Red',
'green-100' => 'Green-100',
'green-200' => 'Green-200',
'green-300' => 'Green-300',
'green-400' => 'Green-400',
'green-500' => 'Green-500',
'green-600' => 'Green-600',
'green-700' => 'Green-700',
'blue-100' => 'Blue-100',
'blue-200' => 'Blue-200',
'blue-300' => 'Blue-300',
'blue-400' => 'Blue-400',
'blue-500' => 'Blue-500',
'blue-600' => 'Blue-600',
'blue-700' => 'Blue-700',
'blue-800' => 'Blue-800',
'blue-900' => 'Blue-900',
])->filter(fn ($label) => str_contains(strtolower($label), strtolower($value)))->all() : [],
['blue-900', 'blue-700', 'green-700', 'green-500'],
],
'list' => [
fn ($value) => strlen($value) > 0 ? collect([
'Red',
'Green-100',
'Green-200',
'Green-300',
'Green-400',
'Green-500',
'Green-600',
'Green-700',
'Blue-100',
'Blue-200',
'Blue-300',
'Blue-400',
'Blue-500',
'Blue-600',
'Blue-700',
'Blue-800',
'Blue-900',
])->filter(fn ($label) => str_contains(strtolower($label), strtolower($value)))
->values()
->all() : [],
['Blue-900', 'Blue-700', 'Green-700', 'Green-500'],
],
]);

it('validates', function () {
Prompt::fake(['a', Key::DOWN, Key::SPACE, Key::ENTER, Key::DOWN, Key::SPACE, Key::ENTER]);

Expand Down

0 comments on commit 4cd0c97

Please sign in to comment.