Skip to content

Instantly share code, notes, and snippets.

@cednore
Created September 20, 2021 00:53
Show Gist options
  • Save cednore/3fd0f777704106dd0a3c658020d11fbe to your computer and use it in GitHub Desktop.
Save cednore/3fd0f777704106dd0a3c658020d11fbe to your computer and use it in GitHub Desktop.
<div
x-data="{
query: '',
showDropdown: false,
currentHighlightedKey: Infinity,
options: {},
wireProp: @entangle($name).defer,
flags: {},
initFlags() {
for (const key of Object.keys(this.options)) {
this.flags[key] = this.wireProp.split(',').includes(key);
}
},
onClickOption(key) {
this.flags[key] = ! this.flags[key];
this.updateInputValue();
},
onBackspace() {
if (! this.query) {
const lastTrueFlagKey = Object.keys(this.flags).reverse().find(key => this.flags[key]);
this.flags[lastTrueFlagKey] = false;
this.updateInputValue();
}
},
updateInputValue() {
this.wireProp = this.trueKeys().join();
},
filteredKeys() {
return Object.keys(this.options)
.filter(key => this.options[key].label.toLowerCase().includes(this.query.toLowerCase()));
},
trueKeys() {
return Object.keys(this.flags).filter(key => this.flags[key]);
},
}"
x-init='options = @json($options); initFlags();'
>
@if($label)
<div class="flex items-center space-x-1">
<label for="{{ $name }}" class="{{ style('inputs.label') }}">{{ $label }}</label>
@if($required)
<x-app.inputs.required-dot />
@endif
</div>
@endif
<div class="{{ style('inputs.input_div_wrapper') }}">
<input
{{ $attributes }}
x-model="wireProp"
name="{{ $name }}"
type="hidden"
id="{{ $id }}"
{{ $disabled ? 'disabled' : '' }}
{{ $disabled ? 'readonly' : '' }}
>
<div class="flex flex-wrap space-x-2 space-y-1 items-center w-full rounded border border-gray-300 px-1 py-2">
<template x-for="key in trueKeys()" :key="key">
<div
class="flex items-center space-x-1 px-2 py-1 rounded bg-green-100 text-sm text-green-800 cursor-pointer"
@if(! $disabled) @click="onClickOption(key)" @endif
>
<span x-text="options[key].label"></span>
<span class="px-1 font-bold">X</span>
</div>
</template>
<input
class="flex-1 border-0 focus:outline-none focus:border-0 focus:ring-0 p-0"
type="text"
x-model="query"
x-ref="tagquery"
@if(! $disabled)
@click="showDropdown = ! showDropdown;"
@click.away="showDropdown = false;"
@keydown="showDropdown = true;"
@keydown.escape.stop="showDropdown = false;"
@keydown.backspace="onBackspace"
@endif
{{ $disabled ? 'disabled' : '' }}
{{ $disabled ? 'readonly' : '' }}
{!! $placeholder ? "placeholder='$placeholder'" : '' !!}
>
</div>
<div x-show="showDropdown" class="absolute mt-1 w-full rounded-md bg-white shadow-lg z-50">
<ul tabindex="-1" role="listbox" class="max-h-56 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
<template
x-show="filteredKeys().length"
x-for="key in filteredKeys()"
:key="key"
>
<li
@if(! $disabled) @click.prevent.stop="onClickOption(key)" @endif
x-bind:id="'tag-option-' + key"
role="option"
class="text-gray-900 cursor-default select-none relative py-2 pl-3 pr-9 hover:text-white hover:bg-blue-500"
>
<div class="flex items-center">
<img
x-bind:src="options[key].image"
alt=""
class="flex-shrink-0 h-6 w-6 rounded-full"
>
<span
x-text="options[key].label"
class="ml-3 block font-normal truncate hover:font-semibold"
></span>
</div>
<span
class="absolute inset-y-0 right-0 flex items-center pr-4"
x-show="flags[key]"
>
<svg class="h-5 w-5" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
</svg>
</span>
</li>
</template>
<li
x-show="! filteredKeys().length"
class="text-gray-600 select-none py-2 pl-3 pr-9"
><span>{{ __('general.no-matching-results') }}</span></li>
</ul>
</div>
@error($name)
<div class="absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-red-500" fill="currentColor" viewBox="0 0 20 20">
<path fill-rule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z"
clip-rule="evenodd"></path>
</svg>
</div>
@enderror
</div>
@error($name)
<p class="{!! style('inputs.input_error_text') !!}">{{ $message }}</p>
@enderror
</div>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment