lynxkite / web /src /NodeSearch.svelte
darabos's picture
Save workspaces.
05acf81
raw
history blame
2.35 kB
<script lang="ts">
import { createEventDispatcher, onMount } from 'svelte';
import Fuse from 'fuse.js'
const dispatch = createEventDispatcher();
export let pos;
export let boxes;
let searchBox: HTMLInputElement;
let hits = [];
let selectedIndex = 0;
onMount(() => searchBox.focus());
$: fuse = new Fuse(boxes, {
keys: ['data.title']
})
function onInput() {
hits = fuse.search(searchBox.value);
selectedIndex = Math.max(0, Math.min(selectedIndex, hits.length - 1));
}
function onKeyDown(e) {
if (e.key === 'ArrowDown') {
e.preventDefault();
selectedIndex = Math.min(selectedIndex + 1, hits.length - 1);
} else if (e.key === 'ArrowUp') {
e.preventDefault();
selectedIndex = Math.max(selectedIndex - 1, 0);
} else if (e.key === 'Enter') {
addSelected();
} else if (e.key === 'Escape') {
dispatch('cancel');
}
}
function addSelected() {
const node = {...hits[selectedIndex].item};
node.position = {x: pos.left, y: pos.top};
dispatch('add', node);
}
async function lostFocus(e) {
// If it's a click on a result, let the click handler handle it.
if (e.relatedTarget && e.relatedTarget.closest('.node-search')) return;
dispatch('cancel');
}
</script>
<div class="node-search"
style="top: {pos.top}px; left: {pos.left}px; right: {pos.right}px; bottom: {pos.bottom}px;">
<input
bind:this={searchBox}
on:input={onInput}
on:keydown={onKeyDown}
on:focusout={lostFocus}
placeholder="Search for box">
{#each hits as box, index}
<div
tabindex="0"
on:focus={() => selectedIndex = index}
on:mouseenter={() => selectedIndex = index}
on:click={addSelected}
class="search-result"
class:selected={index == selectedIndex}>
{box.item.data.title}
</div>
{/each}
</div>
<style>
input {
width: calc(100% - 26px);
font-size: 20px;
padding: 8px;
border-radius: 4px;
border: 1px solid #eee;
margin: 4px;
}
.search-result {
padding: 4px;
cursor: pointer;
}
.search-result.selected {
background-color: #f80;
border-radius: 4px;
}
.node-search {
position: absolute;
width: 300px;
z-index: 5;
padding: 4px;
border-radius: 4px;
border: 1px solid #888;
background-color: white;
}
</style>