This commit is contained in:
seb
2026-10-15 00:45:05 +02:00
parent 6e0b72b34b
commit bcd61fcf5e
5 changed files with 145 additions and 73 deletions

55
src/utils/touch.js Normal file
View File

@@ -0,0 +1,55 @@
/**
* Detects if the primary pointing device or environment is a touch device
* (e.g. tablet, phone, POS touchscreen terminal).
* Returns false on desktop devices with mice/trackpads even if they have touchscreens.
*/
export function isTouchDevice() {
if (typeof window === 'undefined') return false;
if (window.matchMedia) {
if (window.matchMedia('(pointer: coarse)').matches) {
return true;
}
if (window.matchMedia('(pointer: fine)').matches) {
return false;
}
}
return 'ontouchstart' in window || (navigator.maxTouchPoints > 0);
}
/**
* Globally disables autofocus on touch devices to prevent virtual keyboard popups.
* Physical taps on inputs still focus and open the keyboard normally.
*/
export function disableTouchAutofocus() {
if (!isTouchDevice()) return;
// 1. Intercept programmatic focus called during mount/render on autofocus elements
const originalFocus = HTMLElement.prototype.focus;
HTMLElement.prototype.focus = function (options) {
if (this.hasAttribute?.('autofocus') || this.autofocus) {
this.removeAttribute?.('autofocus');
try {
this.autofocus = false;
} catch {
// ignore
}
return;
}
const stack = new Error().stack || '';
if (stack.includes('commitMount') || stack.includes('commitHostUpdate')) {
return;
}
return originalFocus.call(this, options);
};
// 2. Prevent browser from honoring native autofocus attribute on dynamically inserted elements
const originalSetAttribute = Element.prototype.setAttribute;
Element.prototype.setAttribute = function (name, value) {
if (typeof name === 'string' && name.toLowerCase() === 'autofocus') {
return;
}
return originalSetAttribute.call(this, name, value);
};
}