Skip to content

Commit

Permalink
Added AlpineJs support for keyboard events
Browse files Browse the repository at this point in the history
- Arrow key navigation between options
- Enter key for selection
- Enter/Space keys for reset
- Tab for navigation
- Added focus on search reset
  • Loading branch information
asantibanez committed Jun 5, 2020
1 parent 5a46a7a commit 00d5389
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 12 deletions.
11 changes: 10 additions & 1 deletion resources/views/search-input.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@
id="{{ $name }}"
name="{{ $name }}"
type="text"
wire:model.debounce.300ms="searchTerm"
placeholder="{{ $placeholder }}"
class="{{ $styles['searchInput'] }}"

wire:keydown.enter.prevent=""
wire:model.debounce.300ms="searchTerm"

x-on:click="isOpen = true"
x-on:keydown="isOpen = true"

x-on:keydown.arrow-up="selectUp(@this)"
x-on:keydown.arrow-down="selectDown(@this)"
x-on:keydown.enter.prevent="confirmSelection(@this)"
/>
4 changes: 4 additions & 0 deletions resources/views/search-option-item.blade.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<div
class="{{ $styles['searchOptionItem'] }}"

wire:click.stop="selectValue('{{ $option['value'] }}')"

x-bind:class="{ 'bg-gray-100': selectedIndex === {{ $index }} }"
x-on:mouseover="selectedIndex = {{ $index }}"
>
{{ $option['description'] }}
</div>
7 changes: 6 additions & 1 deletion resources/views/search-options-container.blade.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
<div class="{{ $styles['searchOptionsContainer'] }}">
<div
class="{{ $styles['searchOptionsContainer'] }}"

x-show="isOpen"
>
@if(!$emptyOptions)
@foreach($options as $option)
@include($searchOptionItem, [
'option' => $option,
'index' => $loop->index,
'styles' => $styles,
])
@endforeach
Expand Down
20 changes: 12 additions & 8 deletions resources/views/search-selected-option.blade.php
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
<div
id="selected-value"
<button
id="{{ $name }}-selected"
type="button"
class="{{ $styles['searchSelectedOption'] }}"

x-on:keydown.enter.prevent="removeSelection(@this)"
x-on:keydown.space.prevent="removeSelection(@this)"
>
<p class="{{ $styles['searchSelectedOptionTitle'] }}">
<span class="{{ $styles['searchSelectedOptionTitle'] }}">
{{ data_get($selectedOption, 'title', 'Override selectedOption method for a meaningful description') }}
</p>
</span>

<button
<span
type="button"
wire:click.stop="selectValue(null)"
wire:click.prevent="selectValue(null)"
>
<svg class="{{ $styles['searchSelectedOptionReset'] }}" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clip-rule="evenodd"
/>
</svg>
</button>
</span>

<input type="hidden" value="{{ $value }}" name="{{ $name }}">

</div>
</button>
41 changes: 40 additions & 1 deletion resources/views/select.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,46 @@
@endif
</div>

<div>
<div x-data="{
isOpen: true,
selectedIndex: -1,
selectUp(component) {
if (this.selectedIndex === 0) {
return
}
this.selectedIndex--
},
selectDown(component) {
if (component.data.optionsValues.length - 1 === this.selectedIndex) {
return
}
this.selectedIndex++
},
selectIndex(index) {
this.selectedIndex = index
this.isOpen = true
},
confirmSelection(component) {
const value = component.data.optionsValues.length === 1
? component.data.optionsValues[0]
: component.data.optionsValues[this.selectedIndex]
if (!value) {
return
}
component.set('value', value)
this.selectedIndex = -1
this.isOpen = true
},
removeSelection(component) {
component.set('value', null)
this.selectedIndex = -1
this.isOpen = true
}
}" x-on:click.away="isOpen = false">
@if($searchable && $shouldShow)
<div>
@if(!empty($value))
Expand Down
10 changes: 9 additions & 1 deletion src/LivewireSelect.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ class LivewireSelect extends Component
public $placeholder;

public $value;
public $optionsValues;

public $searchable;
public $searchTerm;
Expand Down Expand Up @@ -131,6 +132,10 @@ public function selectValue($value)
$this->emit('livewire-select-focus-search', ['name' => $this->name]);
}

if ($this->searchable && $this->value != null) {
$this->emit('livewire-select-focus-selected', ['name' => $this->name]);
}

$this->notifyValueChanged();
}

Expand Down Expand Up @@ -161,6 +166,7 @@ public function updateDependingValue($data)

if ($oldValue != null && $oldValue != $value) {
$this->value = null;
$this->searchTerm = null;
$this->notifyValueChanged();
}
}
Expand Down Expand Up @@ -195,7 +201,7 @@ public function styles()
'default' => 'p-2 rounded border w-full appearance-none',

'searchSelectedOption' => 'p-2 rounded border w-full bg-white flex items-center',
'searchSelectedOptionTitle' => 'w-full text-gray-900',
'searchSelectedOptionTitle' => 'w-full text-gray-900 text-left',
'searchSelectedOptionReset' => 'h-4 w-4 text-gray-500',

'search' => 'relative',
Expand All @@ -218,6 +224,8 @@ public function render()
$options = $this->options($this->searchTerm);
}

$this->optionsValues = $options->pluck('value')->toArray();

if ($this->value != null) {
$selectedOption = $this->selectedOption($this->value);
}
Expand Down
10 changes: 10 additions & 0 deletions src/LivewireSelectServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,16 @@ public function register()
el.focus();
});
window.livewire.on('livewire-select-focus-selected', (data) => {
const el = document.getElementById(`${data.name || 'invalid'}-selected`);
if (!el) {
return;
}
el.focus();
});
</script>
HTML;
});
Expand Down

0 comments on commit 00d5389

Please sign in to comment.