mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-11-13 15:51:00 +00:00
d06168d94a
After a tap, WebKit and Chrome keep :hover on what was tapped and send a
made-up mouseover, so buttons and rows stayed tinted until the next tap.
While a finger drives the app <html> carries data-touch-input: a PostCSS
step guards every :hover rule with it (no specificity change), and the
made-up mouseover and mouseout stop before any handler. A trackpad or mouse
clears the mark and gets hover back; a browser never sets it.
A control without a press of its own dims the moment a finger lands on it,
after a 60 ms wait so a scroll does not flash rows, and only the innermost
pressed control. A focus: ring no longer stays round a tapped button.
Fields get a fitting return key ("done", "go" in a form, "search" on the
search fields), and addresses, codes and numbers are no longer capitalised
or corrected. Ticking off packing items and tasks, a picker chip, a select
option, a picked date and dragging a plan row now give the haptics a native
list gives.
Confirmations ask through the system where the binary has the new
@capacitor/action-sheet and @capacitor/dialog plugins: a sheet with the
action in red when it destroys something, an alert otherwise, also for
"discard changes" in a sheet. An older app, a browser and a question with a
list under it keep the HTML dialog, as does a system that could not ask.
iOS no longer lifts a page preview on a long press on a link.
59 lines
2.7 KiB
TypeScript
59 lines
2.7 KiB
TypeScript
/**
|
|
* Whether a finger or a pointer drives the app right now, for the styles that
|
|
* only make sense with one of them.
|
|
*
|
|
* After a tap, iOS and Android send the mouse events a mouse would have sent:
|
|
* mouseover first, which React reads as onMouseEnter, and WebKit sets :hover on
|
|
* the tapped element. Neither is ever taken back by a mouseout, so the tint a
|
|
* hover gives stays on the button until the next tap lands elsewhere, and on a
|
|
* phone that reads as a web page. While a finger is in use <html> carries
|
|
* data-touch-input: the build guards every :hover rule with it
|
|
* (postcss/touchHover.js), and the made-up mouseover and mouseout stop here
|
|
* before any handler sees them. A real pointer (an iPad trackpad or mouse)
|
|
* clears the mark on its first move, and hover works as on a computer.
|
|
*
|
|
* Only the app calls this. In a browser a tablet keeps tap-to-hover, which is
|
|
* how its users reach controls that show on hover.
|
|
*/
|
|
|
|
export const TOUCH_INPUT_ATTR = 'data-touch-input';
|
|
|
|
export function trackTouchInput(root: HTMLElement = document.documentElement, win: Window = window): () => void {
|
|
const setTouch = (on: boolean) => {
|
|
if (on === root.hasAttribute(TOUCH_INPUT_ATTR)) return;
|
|
if (on) root.setAttribute(TOUCH_INPUT_ATTR, '');
|
|
else root.removeAttribute(TOUCH_INPUT_ATTR);
|
|
};
|
|
// A phone starts with a finger; a trackpad says otherwise as soon as it moves.
|
|
setTouch(true);
|
|
|
|
const onPointerDown = (e: PointerEvent) => setTouch(e.pointerType !== 'mouse');
|
|
const onPointerMove = (e: PointerEvent) => {
|
|
if (e.pointerType === 'mouse') setTouch(false);
|
|
};
|
|
// Captured on the window, ahead of React's listener on the root and of every element's.
|
|
const swallow = (e: Event) => {
|
|
if (root.hasAttribute(TOUCH_INPUT_ATTR)) e.stopImmediatePropagation();
|
|
};
|
|
// WebKit applies :active on a phone only where a touchstart listener exists.
|
|
const noop = () => {};
|
|
|
|
const opts = { capture: true, passive: true } as const;
|
|
win.addEventListener('pointerdown', onPointerDown, opts);
|
|
win.addEventListener('pointerover', onPointerMove, opts);
|
|
win.addEventListener('pointermove', onPointerMove, opts);
|
|
win.addEventListener('mouseover', swallow, true);
|
|
win.addEventListener('mouseout', swallow, true);
|
|
win.document.addEventListener('touchstart', noop, { passive: true });
|
|
|
|
return () => {
|
|
win.removeEventListener('pointerdown', onPointerDown, opts);
|
|
win.removeEventListener('pointerover', onPointerMove, opts);
|
|
win.removeEventListener('pointermove', onPointerMove, opts);
|
|
win.removeEventListener('mouseover', swallow, true);
|
|
win.removeEventListener('mouseout', swallow, true);
|
|
win.document.removeEventListener('touchstart', noop);
|
|
root.removeAttribute(TOUCH_INPUT_ATTR);
|
|
};
|
|
}
|