Compare commits

..

No commits in common. "4945204b7b37b213a57e2309e7fe30b73997682a" and "5e5bf92afb7a2bc465a33e6584e193d778fd12fb" have entirely different histories.

View file

@ -30,13 +30,6 @@
let serverHits: { name: string; usage_count: number }[] = $state([]);
let privateHits: { name: string; count: number }[] = $state([]);
let timer: ReturnType<typeof setTimeout> | undefined;
// True while the soft keyboard is composing (IME predictive text on
// Android, hangul/kana/pinyin elsewhere). During composition keydown
// fires with e.key === 'Unidentified' and e.keyCode === 229, so a naive
// `e.key === 'Enter'` check misses the user's commit-and-press-enter
// gesture. We commit on compositionend Enter via the addCurrent button
// instead — see the keydown handler.
let composing = $state(false);
function add(name: string) {
const n = name.trim().toLowerCase();
@ -55,19 +48,7 @@
}
function onKey(e: KeyboardEvent) {
// Detect "commit" intent across desktop and mobile soft keyboards.
// Android Chrome with predictive text fires keydown with key
// 'Unidentified' + keyCode 229 during composition; Enter committed
// afterwards still has keyCode 13 (or 'Enter'), so we accept either.
// Comma is the same.
if (composing) return;
const isEnter = e.key === 'Enter' || e.keyCode === 13;
const isComma = e.key === ',' || e.keyCode === 188;
if (isEnter || isComma) {
// Always preventDefault on Enter — without it the parent <form>
// submits the whole activity when the user is just trying to add a
// tag (especially noticeable on mobile where the soft keyboard's
// "Done" key triggers form submit).
if (e.key === 'Enter' || e.key === ',') {
e.preventDefault();
add(input);
} else if (e.key === 'Backspace' && !input && tags.length) {
@ -75,31 +56,6 @@
}
}
/** Called by the "Legg til"-button. The button is the foolproof mobile
* path — IME composition can swallow Enter, but a tap is a tap. */
function addCurrent() {
add(input);
}
/**
* beforeinput fires before the browser commits a value change. We use it
* to catch Enter on platforms where keydown doesn't deliver a usable
* Enter event — notably Firefox on Android, which treats the soft-
* keyboard Enter as "advance to next form field" at the input layer
* (no keydown for us to intercept). InputEvent.inputType === 'insertLineBreak'
* still fires here, so we get to preventDefault before focus moves.
* Idempotent with onKey: keydown's preventDefault on Chrome cancels
* the would-be insertion, so beforeinput never fires there.
*/
function onBeforeInput(e: Event) {
const ie = e as InputEvent;
if (composing) return;
if (ie.inputType === 'insertLineBreak') {
e.preventDefault();
add(input);
}
}
function onType(e: Event) {
input = (e.target as HTMLInputElement).value;
clearTimeout(timer);
@ -131,29 +87,14 @@
{/each}
</div>
<div class="row" style="gap: 0.4rem; align-items: stretch;">
<input
type="text"
value={input}
oninput={onType}
onkeydown={onKey}
onbeforeinput={onBeforeInput}
oncompositionstart={() => (composing = true)}
oncompositionend={() => (composing = false)}
placeholder="Skriv etikett, trykk Enter eller «Legg til»"
aria-label="Ny etikett"
enterkeyhint="done"
autocapitalize="none"
autocorrect="off"
spellcheck="false"
style="flex: 1 1 auto; min-width: 0;"
/>
<button type="button" onclick={addCurrent} disabled={!input.trim()}
aria-label="Legg til etikett"
style="flex: 0 0 auto;">
Legg til
</button>
</div>
<input
type="text"
value={input}
oninput={onType}
onkeydown={onKey}
placeholder="Legg til etikett, trykk Enter"
aria-label="Ny etikett"
/>
{#if serverHits.length || privateHits.length}
<div class="card" style="margin-top: 0.25rem;" role="listbox" aria-label="Forslag">