Compare commits
2 commits
5e5bf92afb
...
4945204b7b
| Author | SHA1 | Date | |
|---|---|---|---|
| 4945204b7b | |||
| a94a38071b |
1 changed files with 68 additions and 9 deletions
|
|
@ -30,6 +30,13 @@
|
|||
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();
|
||||
|
|
@ -48,7 +55,19 @@
|
|||
}
|
||||
|
||||
function onKey(e: KeyboardEvent) {
|
||||
if (e.key === 'Enter' || e.key === ',') {
|
||||
// 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).
|
||||
e.preventDefault();
|
||||
add(input);
|
||||
} else if (e.key === 'Backspace' && !input && tags.length) {
|
||||
|
|
@ -56,6 +75,31 @@
|
|||
}
|
||||
}
|
||||
|
||||
/** 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);
|
||||
|
|
@ -87,14 +131,29 @@
|
|||
{/each}
|
||||
</div>
|
||||
|
||||
<input
|
||||
type="text"
|
||||
value={input}
|
||||
oninput={onType}
|
||||
onkeydown={onKey}
|
||||
placeholder="Legg til etikett, trykk Enter"
|
||||
aria-label="Ny etikett"
|
||||
/>
|
||||
<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>
|
||||
|
||||
{#if serverHits.length || privateHits.length}
|
||||
<div class="card" style="margin-top: 0.25rem;" role="listbox" aria-label="Forslag">
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue