Decouple TagInput from TagAutocomplete completely
This commit is contained in:
parent
8d95503189
commit
808d01c4fb
@ -11,7 +11,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
export { className as class };
|
||||
|
||||
export let tooltip: string | undefined = undefined;
|
||||
export let tabbable: boolean = true;
|
||||
export let tabbable: boolean = false;
|
||||
|
||||
let buttonRef: HTMLButtonElement;
|
||||
|
||||
@ -54,7 +54,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
.btn-day {
|
||||
color: black;
|
||||
|
||||
&:active {
|
||||
&:active,
|
||||
&.active {
|
||||
background-color: button.$focus-color;
|
||||
color: white;
|
||||
}
|
||||
@ -64,11 +65,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
color: white;
|
||||
|
||||
&:hover,
|
||||
&:focus {
|
||||
&:focus,
|
||||
&.focus {
|
||||
@include button.btn-night-base;
|
||||
}
|
||||
|
||||
&:active {
|
||||
&:active,
|
||||
&.active {
|
||||
background-color: button.$focus-color;
|
||||
color: white;
|
||||
}
|
||||
|
51
ts/components/WithDropdownMenu.svelte
Normal file
51
ts/components/WithDropdownMenu.svelte
Normal file
@ -0,0 +1,51 @@
|
||||
<!--
|
||||
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;
|
||||
|
||||
setContext(dropdownKey, {
|
||||
dropdown: true,
|
||||
"data-bs-toggle": "dropdown",
|
||||
"aria-expanded": "false",
|
||||
});
|
||||
|
||||
const menuId = Math.random().toString(36).substring(2);
|
||||
let dropdown: Dropdown;
|
||||
|
||||
function activateDropdown(): void {
|
||||
if (!disabled) {
|
||||
dropdown.toggle();
|
||||
}
|
||||
}
|
||||
|
||||
/* 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 });
|
||||
|
||||
const menu = (element.getRootNode() as Document) /* or shadow root */
|
||||
.getElementById(menuId);
|
||||
|
||||
if (!menu) {
|
||||
console.log(`Could not find menu "${menuId}" for dropdown menu.`);
|
||||
} else {
|
||||
dropdown = new Dropdown(element);
|
||||
|
||||
/* Set custom menu without using common element with .dropdown */
|
||||
(dropdown as any)._menu = menu;
|
||||
}
|
||||
|
||||
return dropdown;
|
||||
}
|
||||
</script>
|
||||
|
||||
<slot {createDropdown} {activateDropdown} {menuId} />
|
@ -4,10 +4,11 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
-->
|
||||
<script lang="typescript">
|
||||
import ButtonToolbar from "components/ButtonToolbar.svelte";
|
||||
import WithDropdownMenu from "components/WithDropdownMenu.svelte";
|
||||
import DropdownMenu from "components/DropdownMenu.svelte";
|
||||
import DropdownItem from "components/DropdownItem.svelte";
|
||||
|
||||
export const suggestions = ["en::idioms", "anki::functionality", "math"];
|
||||
export let suggestions: string[];
|
||||
export let size: number;
|
||||
|
||||
let className: string = "";
|
||||
@ -29,22 +30,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function updateActiveItem(event: FocusEvent): void {
|
||||
event.preventDefault();
|
||||
}
|
||||
</script>
|
||||
|
||||
<ButtonToolbar class={`dropup ${className}`} {size}>
|
||||
<slot />
|
||||
<WithDropdownMenu let:menuId let:createDropdown let:activateDropdown>
|
||||
<slot {createDropdown} {activateDropdown} />
|
||||
|
||||
<DropdownMenu class="d-flex flex-column-reverse">
|
||||
{#each suggestions as tag}
|
||||
<DropdownItem
|
||||
tabbable={false}
|
||||
on:focus={updateActiveItem}
|
||||
on:keydown={switchUpDown}>{tag}</DropdownItem
|
||||
>
|
||||
{/each}
|
||||
</DropdownMenu>
|
||||
<DropdownMenu id={menuId} class="d-flex flex-column-reverse">
|
||||
{#each suggestions as tag}
|
||||
<DropdownItem on:keydown={switchUpDown}>{tag}</DropdownItem>
|
||||
{/each}
|
||||
</DropdownMenu>
|
||||
</WithDropdownMenu>
|
||||
</ButtonToolbar>
|
||||
|
@ -12,6 +12,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { attachId, getName } from "./tags";
|
||||
|
||||
export let initialNames = ["en::foobar", "test", "def"];
|
||||
export let suggestions = ["en::idioms", "anki::functionality", "math"];
|
||||
|
||||
export let size = isApplePlatform() ? 1.6 : 2.0;
|
||||
|
||||
let tags = initialNames.map(attachId);
|
||||
@ -90,7 +92,13 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
<StickyBottom>
|
||||
<div class="row-gap">
|
||||
<TagAutocomplete class="d-flex flex-wrap align-items-center" {size}>
|
||||
<TagAutocomplete
|
||||
class="d-flex flex-wrap align-items-center"
|
||||
{suggestions}
|
||||
{size}
|
||||
let:createDropdown
|
||||
let:activateDropdown
|
||||
>
|
||||
<AddTagBadge on:click={focusNewInput} />
|
||||
|
||||
{#each tags as tag, index (tag.id)}
|
||||
@ -107,6 +115,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
<TagInput
|
||||
bind:input={newInput}
|
||||
bind:name={newName}
|
||||
on:focus={(event) => createDropdown(event.currentTarget)}
|
||||
on:tagupdate={appendTag}
|
||||
on:tagadd={appendTag}
|
||||
on:tagjoinprevious={joinWithLastTag}
|
||||
|
@ -6,27 +6,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
import { createEventDispatcher, onMount } from "svelte";
|
||||
import { normalizeTagname } from "./tags";
|
||||
|
||||
import TagAutocomplete from "./TagAutocomplete.svelte";
|
||||
|
||||
export let name: string;
|
||||
export let input: HTMLInputElement;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
function onFocus(): void {
|
||||
/* dropdown.show(); */
|
||||
}
|
||||
|
||||
function onAccept(): void {
|
||||
name = normalizeTagname(name);
|
||||
dispatch("tagupdate", { name });
|
||||
}
|
||||
|
||||
function dropdownBlur(): void {
|
||||
onAccept();
|
||||
/* dropdown.hide(); */
|
||||
}
|
||||
|
||||
function onBackspace(event: KeyboardEvent) {
|
||||
if (input.selectionStart === 0 && input.selectionEnd === 0) {
|
||||
dispatch("tagjoinprevious");
|
||||
@ -99,21 +88,16 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
onMount(() => dispatch("mount", { input }));
|
||||
</script>
|
||||
|
||||
<label
|
||||
class="ps-2 pe-1"
|
||||
data-value={name}
|
||||
data-bs-toggle="dropdown"
|
||||
aria-expanded="false"
|
||||
>
|
||||
<label class="ps-2 pe-1" data-value={name}>
|
||||
<input
|
||||
bind:this={input}
|
||||
type="text"
|
||||
tabindex="-1"
|
||||
size="1"
|
||||
bind:value={name}
|
||||
on:focus={onFocus}
|
||||
on:blur={dropdownBlur}
|
||||
on:focus
|
||||
on:focusout
|
||||
on:blur={onAccept}
|
||||
on:keydown={onKeydown}
|
||||
on:paste={onPaste}
|
||||
on:click
|
||||
|
Loading…
Reference in New Issue
Block a user