Switch WithAutocomplete to WithDropdown and fix SelectedTagBadge
This commit is contained in:
parent
874a315f83
commit
3dff89fda5
@ -19,12 +19,19 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
});
|
||||
|
||||
let dropdown: Dropdown;
|
||||
let dropdownObject: Dropdown;
|
||||
let api: Dropdown & { isVisible: () => boolean };
|
||||
|
||||
function isVisible() {
|
||||
return (dropdown as any)._menu
|
||||
? (dropdown as any)._menu.classList.contains("show")
|
||||
: false;
|
||||
}
|
||||
|
||||
const noop = () => {};
|
||||
function createDropdown(toggle: HTMLElement): Dropdown {
|
||||
/* avoid focusing element toggle on menu activation */
|
||||
toggle.focus = noop;
|
||||
|
||||
dropdown = new Dropdown(toggle, {
|
||||
autoClose,
|
||||
popperConfig: (defaultConfig: Record<string, any>) => ({
|
||||
@ -37,22 +44,23 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
dropdown.show();
|
||||
}
|
||||
|
||||
dropdownObject = {
|
||||
let api = {
|
||||
show: dropdown.show.bind(dropdown),
|
||||
toggle: dropdown.toggle.bind(dropdown),
|
||||
hide: dropdown.hide.bind(dropdown),
|
||||
update: dropdown.update.bind(dropdown),
|
||||
dispose: dropdown.dispose.bind(dropdown),
|
||||
isVisible,
|
||||
};
|
||||
|
||||
return dropdownObject;
|
||||
return api;
|
||||
}
|
||||
|
||||
onDestroy(() => dropdown?.dispose());
|
||||
</script>
|
||||
|
||||
<div class="dropdown">
|
||||
<slot {createDropdown} {dropdownObject} />
|
||||
<slot {createDropdown} dropdownObject={api} />
|
||||
</div>
|
||||
|
||||
<style lang="scss">
|
||||
|
@ -1,60 +0,0 @@
|
||||
<!--
|
||||
Copyright: Ankitects Pty Ltd and contributors
|
||||
License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="typescript">
|
||||
import Dropdown from "bootstrap/js/dist/dropdown";
|
||||
|
||||
import { setContext } from "svelte";
|
||||
import { dropdownKey } from "./contextKeys";
|
||||
|
||||
export let disabled = false;
|
||||
export let toggleOnClick = true;
|
||||
|
||||
setContext(dropdownKey, {
|
||||
dropdown: true,
|
||||
"data-bs-toggle": "dropdown",
|
||||
"aria-expanded": "false",
|
||||
});
|
||||
|
||||
const menuId = Math.random().toString(36).substring(2);
|
||||
let dropdown: Dropdown | undefined;
|
||||
|
||||
function activateDropdown(): void {
|
||||
if (dropdown && !disabled) {
|
||||
dropdown.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
function isVisible(): boolean {
|
||||
return (dropdown as any)._menu.classList.contains("show");
|
||||
}
|
||||
|
||||
/* Normally dropdown and trigger are associated with a
|
||||
/* common ancestor with .dropdown class */
|
||||
function createDropdown(element: HTMLElement): Dropdown {
|
||||
/* Prevent focus on menu activation */
|
||||
const noop = () => {};
|
||||
Object.defineProperty(element, "focus", { value: noop, configurable: true });
|
||||
|
||||
const menu = (element.getRootNode() as Document | ShadowRoot).getElementById(
|
||||
menuId
|
||||
);
|
||||
|
||||
if (!menu) {
|
||||
throw Error(`Could not find menu "${menuId}" for dropdown menu.`);
|
||||
}
|
||||
|
||||
if (!toggleOnClick) {
|
||||
(Dropdown.prototype as any)._addEventListeners = noop;
|
||||
}
|
||||
dropdown = new Dropdown(element);
|
||||
|
||||
/* Set custom menu without using common element with .dropdown */
|
||||
(dropdown as any)._menu = menu;
|
||||
Object.defineProperty(dropdown, "isVisible", { value: isVisible });
|
||||
return dropdown as Dropdown;
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot {createDropdown} {activateDropdown} {menuId} />
|
@ -6,7 +6,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
import Badge from "components/Badge.svelte";
|
||||
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
||||
import WithDropdown from "components/WithDropdown.svelte";
|
||||
import WithShortcut from "components/WithShortcut.svelte";
|
||||
import DropdownMenu from "components/DropdownMenu.svelte";
|
||||
import DropdownItem from "components/DropdownItem.svelte";
|
||||
@ -20,15 +20,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
const removeLabel = "Remove tags";
|
||||
</script>
|
||||
|
||||
<WithDropdownMenu let:menuId let:createDropdown>
|
||||
<div class="dropdown">
|
||||
<div class="more-icon">
|
||||
<Badge class="me-1" on:mount={withSpan(createDropdown)}
|
||||
>{@html dotsIcon}</Badge
|
||||
>
|
||||
</div>
|
||||
<WithDropdown let:createDropdown>
|
||||
<div class="more-icon">
|
||||
<Badge class="me-1" on:mount={withSpan(createDropdown)}>{@html dotsIcon}</Badge>
|
||||
|
||||
<DropdownMenu id={menuId}>
|
||||
<DropdownMenu>
|
||||
<WithShortcut shortcut="C" let:createShortcut let:shortcutLabel>
|
||||
<DropdownItem
|
||||
on:click={() => dispatch("tagcopy")}
|
||||
@ -45,7 +41,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
</WithShortcut>
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
</WithDropdownMenu>
|
||||
</WithDropdown>
|
||||
|
||||
<style lang="scss">
|
||||
.more-icon {
|
||||
|
@ -33,6 +33,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
let activeName = "";
|
||||
let activeInput: HTMLInputElement;
|
||||
|
||||
let autocomplete: any;
|
||||
let suggestionsPromise: Promise<string[]> = Promise.resolve([]);
|
||||
|
||||
function updateSuggestions(): void {
|
||||
@ -104,8 +105,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
async function enterBehavior(
|
||||
index: number,
|
||||
start: number,
|
||||
end: number,
|
||||
autocomplete: any
|
||||
end: number
|
||||
): Promise<void> {
|
||||
if (autocomplete.isVisible()) {
|
||||
autocomplete.chooseSelected();
|
||||
@ -227,7 +227,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
return event.code === "Backspace" || event.code === "Delete";
|
||||
}
|
||||
|
||||
function onKeydown(event: KeyboardEvent, autocomplete: any): void {
|
||||
function onKeydown(event: KeyboardEvent): void {
|
||||
const visible = autocomplete.isVisible();
|
||||
const printable = isPrintableKey(event);
|
||||
const deletion = isDeletionKey(event);
|
||||
@ -274,7 +274,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
}
|
||||
}
|
||||
|
||||
function onKeyup(_event: KeyboardEvent, autocomplete: any): void {
|
||||
function onKeyup(_event: KeyboardEvent): void {
|
||||
if (activeName.length === 0) {
|
||||
autocomplete.hide();
|
||||
}
|
||||
@ -384,7 +384,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
onAutocomplete(detail.selected)}
|
||||
on:choose={({ detail }) => onChosen(detail.chosen)}
|
||||
let:createAutocomplete
|
||||
let:autocomplete
|
||||
>
|
||||
<TagInput
|
||||
id={tag.id}
|
||||
@ -392,18 +391,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
bind:input={activeInput}
|
||||
on:focus={() => {
|
||||
activeName = tag.name;
|
||||
createAutocomplete(activeInput);
|
||||
autocomplete = createAutocomplete(activeInput);
|
||||
}}
|
||||
on:keydown={(event) => onKeydown(event, autocomplete)}
|
||||
on:keyup={(event) => onKeyup(event, autocomplete)}
|
||||
on:keydown={onKeydown}
|
||||
on:keyup={onKeyup}
|
||||
on:input={() => updateTagName(tag)}
|
||||
on:tagsplit={({ detail }) =>
|
||||
enterBehavior(
|
||||
index,
|
||||
detail.start,
|
||||
detail.end,
|
||||
autocomplete
|
||||
)}
|
||||
enterBehavior(index, detail.start, detail.end)}
|
||||
on:tagadd={() => insertTag(index)}
|
||||
on:tagdelete={() => deleteTagAt(index)}
|
||||
on:tagjoinprevious={() => joinWithPreviousTag(index)}
|
||||
|
@ -7,7 +7,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import type Dropdown from "bootstrap/js/dist/dropdown";
|
||||
|
||||
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
||||
import WithDropdown from "components/WithDropdown.svelte";
|
||||
import DropdownMenu from "components/DropdownMenu.svelte";
|
||||
import AutocompleteItem from "./AutocompleteItem.svelte";
|
||||
|
||||
@ -18,7 +18,6 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
let target: HTMLElement;
|
||||
let dropdown: Dropdown;
|
||||
let autocomplete: any;
|
||||
|
||||
let selected: number | null = null;
|
||||
let active: boolean = false;
|
||||
@ -82,10 +81,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
(element: HTMLElement): any => {
|
||||
target = element;
|
||||
dropdown = createDropdown(element);
|
||||
autocomplete = {
|
||||
hide: dropdown.hide.bind(dropdown),
|
||||
show: dropdown.show.bind(dropdown),
|
||||
toggle: dropdown.toggle.bind(dropdown),
|
||||
|
||||
const api = {
|
||||
hide: dropdown.hide,
|
||||
show: dropdown.show,
|
||||
toggle: dropdown.toggle,
|
||||
isVisible: (dropdown as any).isVisible,
|
||||
selectPrevious,
|
||||
selectNext,
|
||||
@ -93,7 +93,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
update,
|
||||
};
|
||||
|
||||
return autocomplete;
|
||||
return api;
|
||||
};
|
||||
|
||||
onDestroy(() => dropdown?.dispose());
|
||||
@ -114,10 +114,10 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
}
|
||||
</script>
|
||||
|
||||
<WithDropdownMenu toggleOnClick={false} let:menuId let:createDropdown>
|
||||
<slot createAutocomplete={createAutocomplete(createDropdown)} {autocomplete} />
|
||||
<WithDropdown let:createDropdown>
|
||||
<slot createAutocomplete={createAutocomplete(createDropdown)} />
|
||||
|
||||
<DropdownMenu id={menuId} class={className}>
|
||||
<DropdownMenu class={className}>
|
||||
{#await suggestionsPromise}
|
||||
<AutocompleteItem>...</AutocompleteItem>
|
||||
{:then suggestions}
|
||||
@ -132,4 +132,4 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
{/each}
|
||||
{/await}
|
||||
</DropdownMenu>
|
||||
</WithDropdownMenu>
|
||||
</WithDropdown>
|
||||
|
Loading…
Reference in New Issue
Block a user