diff --git a/.memory/state.md b/.memory/state.md index 2c2862d..4b67148 100644 --- a/.memory/state.md +++ b/.memory/state.md @@ -5,5 +5,5 @@ - Public API: `push`, `pop`, `clear`, `swap`, `remove`, `edit`, `isValidIndex`, `input`, `command`, `getOperationsByCategory`, `getConstants` - Config: `maxSize`, `base`, `angleMode`, `enabledCommands` - Commands: arithmetic, stack, trigonometry, constants `pi` and `e` -- Demo actions: paste now parses clipboard text as a number before pushing it to the stack; Ctrl+V is supported via the hidden input paste event; backspace is ignored when the stack is empty; operation errors are shown as an overlay bar on top of the calculator with a shorter timeout and darker red +- Demo actions: keyboard focus is kept on the hidden input as much as possible so typing keeps working; paste parses clipboard text as a number before pushing it to the stack; Ctrl+V is supported via the hidden input paste event; backspace is ignored when the stack is empty; operation errors are shown as an overlay bar on top of the calculator with a shorter timeout and darker red - Exports: browser `window.RpnCalculator`, CommonJS `module.exports` diff --git a/samples/calc-02/index.js b/samples/calc-02/index.js index 8cfab34..7b366d3 100644 --- a/samples/calc-02/index.js +++ b/samples/calc-02/index.js @@ -72,8 +72,19 @@ const trigoKeys = [ ]; +const isTouchDevice = window.matchMedia('(pointer: coarse)').matches || 'ontouchstart' in window; + function focusInput() { - hiddenInput.focus(); + if (!hiddenInput || isTouchDevice) return; + hiddenInput.focus({ preventScroll: true }); + window.requestAnimationFrame(() => { + if (document.activeElement !== hiddenInput) { + hiddenInput.focus({ preventScroll: true }); + } + if (typeof hiddenInput.select === 'function') { + hiddenInput.select(); + } + }); } let statusTimer = null; @@ -218,7 +229,6 @@ function createKeyButton({ label, input, action, spacer, className }) { button.textContent = label; button.className = className; button.addEventListener('click', () => { - focusInput(); if (input) { inputToX(input); render(); @@ -235,7 +245,7 @@ function buildGrid(container, keys) { } function handleKeyboard(event) { - if (event.target === hiddenInput) return; + if (event.defaultPrevented) return; const key = event.key; if (/^[0-9.]$/.test(key)) { event.preventDefault(); @@ -405,17 +415,28 @@ rightButton.addEventListener('click', () => { }); -window.addEventListener('keydown', handleKeyboard); +window.addEventListener('keydown', handleKeyboard, { capture: true }); window.addEventListener('load', focusInput); +window.addEventListener('pageshow', focusInput); +window.addEventListener('focus', focusInput); +window.addEventListener('pointerdown', focusInput, true); +window.addEventListener('mousedown', focusInput, true); +window.addEventListener('click', focusInput, true); +hiddenInput.setAttribute('inputmode', 'none'); +hiddenInput.setAttribute('readonly', 'readonly'); hiddenInput.addEventListener('focus', () => { + if (isTouchDevice) { + hiddenInput.blur(); + return; + } window.requestAnimationFrame(() => { hiddenInput.select(); }); }); document.addEventListener('click', (event) => { - if (!event.target.closest('.calculator')) { + if (!isTouchDevice && !event.target.closest('.mode-menu')) { focusInput(); } }); @@ -424,3 +445,4 @@ buildGrid(keypadGrid, keypadKeys); buildGrid(functionsGrid, functionKeys); buildGrid(trigoGrid, trigoKeys); render(); +focusInput();