Introduce AutocompleteItem

* needs too much custom styling / behavior to be done with DropdownItem
This commit is contained in:
Henrik Giesel 2021-06-29 01:37:23 +02:00
parent b2d2cb8715
commit b93646209a
5 changed files with 147 additions and 67 deletions

View File

@ -50,10 +50,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
background: none;
box-shadow: none !important;
border: none;
}
.btn-day {
color: black;
&:active,
&.active {
@ -62,19 +58,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
}
.btn-day {
color: black;
}
.btn-night {
color: white;
&:hover,
&:focus,
&.focus {
&:focus {
@include button.btn-night-base;
}
&:active,
&.active {
background-color: button.$focus-color;
color: white;
}
}
</style>

View File

@ -0,0 +1,81 @@
<!--
Copyright: Ankitects Pty Ltd and contributors
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
-->
<script lang="typescript">
import { onMount, createEventDispatcher, getContext } from "svelte";
import { nightModeKey } from "components/contextKeys";
export let id: string | undefined = undefined;
let className = "";
export { className as class };
export let selected = false;
export let active = false;
const nightMode = getContext<boolean>(nightModeKey);
const dispatch = createEventDispatcher();
let buttonRef: HTMLButtonElement;
onMount(() => dispatch("mount", { button: buttonRef }));
</script>
<button
{id}
tabindex="-1"
bind:this={buttonRef}
class={`btn ${className}`}
class:btn-day={!nightMode}
class:btn-night={nightMode}
class:selected
class:active
on:mouseup
on:mouseenter
on:mousedown|preventDefault
>
<slot />
</button>
<style lang="scss">
@use 'ts/sass/button_mixins' as button;
button {
display: flex;
justify-content: space-between;
font-size: calc(var(--buttons-size) / 2.3);
background: none;
box-shadow: none !important;
border: none;
&.active {
background-color: button.$focus-color;
color: white;
}
}
/* reset global CSS from buttons.scss */
:global(.nightMode) button:hover {
background-color: inherit;
}
/* extra specificity bc of global CSS reset above */
button.btn-day {
color: black;
&.selected {
background-color: #e9ecef;
border-color: #e9ecef;
}
}
button.btn-night {
color: white;
&.selected {
@include button.btn-night-base;
}
}
</style>

View File

@ -245,6 +245,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
break;
case "Enter":
console.log("choose");
autocomplete.chooseSelected();
event.preventDefault();
break;

View File

@ -9,7 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
import DropdownMenu from "components/DropdownMenu.svelte";
import DropdownItem from "components/DropdownItem.svelte";
import AutocompleteItem from "./AutocompleteItem.svelte";
let className: string = "";
export { className as class };
@ -26,8 +26,9 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
const dispatch = createEventDispatcher();
function selectNext() {
suggestionsPromise.then((suggestions) => {
async function selectNext() {
const suggestions = await suggestionsPromise;
if (selected === null) {
selected = 0;
} else if (selected >= suggestions.length - 1) {
@ -37,11 +38,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
dispatch("autocomplete", { selected: suggestions[selected ?? -1] });
});
}
function selectPrevious() {
suggestionsPromise.then((suggestions) => {
async function selectPrevious() {
const suggestions = await suggestionsPromise;
if (selected === null) {
selected = suggestions.length - 1;
} else if (selected === 0) {
@ -51,7 +52,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
}
dispatch("autocomplete", { selected: suggestions[selected ?? -1] });
});
}
function chooseSelected() {
@ -63,9 +63,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
dropdown.update();
dispatch("update");
await tick();
const [, suggestions] = await Promise.all([tick(), suggestionsPromise]);
suggestionsPromise.then((suggestions) => {
if (suggestions.length > 0) {
dropdown.show();
// disabled class will tell Bootstrap not to show menu on clicking
@ -74,7 +73,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
dropdown.hide();
target.classList.add("disabled");
}
});
}
const createAutocomplete =
@ -97,6 +95,21 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
};
onDestroy(() => dropdown?.dispose());
function setSelected(index: number): void {
selected = index;
}
async function chooseIndex(index: number): Promise<void> {
const suggestions = await suggestionsPromise;
dispatch("autocomplete", { selected: suggestions[index] });
}
function selectIfMousedown(event: MouseEvent, index: number): void {
if (event.buttons === 1) {
setSelected(index);
}
}
</script>
<WithDropdownMenu let:menuId let:createDropdown>
@ -104,27 +117,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
<DropdownMenu id={menuId} class={className}>
{#await suggestionsPromise}
<div class="suggestion-item">
<DropdownItem>...</DropdownItem>
</div>
<AutocompleteItem>...</AutocompleteItem>
{:then suggestions}
{#each suggestions as suggestion, i}
<div class="suggestion-item">
<DropdownItem
class={i === selected ? (active ? "active" : "focus") : ""}
on:click>{suggestion}</DropdownItem
{#each suggestions as suggestion, index}
<AutocompleteItem
selected={index === selected}
active={index === selected && active}
on:mousedown={() => setSelected(index)}
on:mouseenter={(event) => selectIfMousedown(event, index)}
on:mouseup={() => chooseIndex(index)}>{suggestion}</AutocompleteItem
>
</div>
{/each}
{/await}
</DropdownMenu>
</WithDropdownMenu>
<style lang="scss">
.suggestion-item {
:global(.dropdown-item:hover) {
background-color: inherit !important;
border-color: inherit !important;
}
}
</style>

View File

@ -28,7 +28,8 @@ $btn-base-color-day: white;
@content ($btn-base-color-day);
@if ($with-hover) {
&:hover {
&:hover,
&.hover {
background-color: darken($btn-base-color-day, 8%);
}
}
@ -76,7 +77,8 @@ $btn-base-color-night: #666;
@content ($btn-base-color-night);
@if ($with-hover) {
&:hover {
&:hover,
&.hover {
background-color: lighten($btn-base-color-night, 8%);
border-color: lighten($btn-base-color-night, 8%);
}