fix(editor): Improve touch device detection (#9675)

This commit is contained in:
Milorad FIlipović 2024-06-12 13:49:41 +02:00 committed by GitHub
parent dc17cf3a49
commit 3b86f52b02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 60 additions and 16 deletions

View file

@ -1,5 +1,11 @@
import { useDeviceSupport } from 'n8n-design-system/composables/useDeviceSupport';
const detectPointerType = (query: string) => {
const isCoarse = query === '(any-pointer: coarse)';
const isFine = query === '(any-pointer: fine)';
return { fine: isFine, coarse: isCoarse };
};
describe('useDeviceSupport()', () => {
beforeEach(() => {
global.window = Object.create(window);
@ -7,24 +13,38 @@ describe('useDeviceSupport()', () => {
});
describe('isTouchDevice', () => {
it('should be true if ontouchstart is in window', () => {
Object.defineProperty(window, 'ontouchstart', {});
const { isTouchDevice } = useDeviceSupport();
expect(isTouchDevice).toEqual(true);
});
it('should be true if navigator.maxTouchPoints > 0', () => {
Object.defineProperty(navigator, 'maxTouchPoints', { value: 1 });
const { isTouchDevice } = useDeviceSupport();
expect(isTouchDevice).toEqual(true);
});
it('should be false if no touch support', () => {
delete window.ontouchstart;
Object.defineProperty(navigator, 'maxTouchPoints', { value: 0 });
it('should be false if window matches `any-pointer: fine` and `!any-pointer: coarse`', () => {
Object.defineProperty(window, 'matchMedia', {
value: vi.fn().mockImplementation((query: string) => {
const { fine, coarse } = detectPointerType(query);
return { matches: fine && !coarse };
}),
});
const { isTouchDevice } = useDeviceSupport();
expect(isTouchDevice).toEqual(false);
});
it('should be false if window matches `any-pointer: fine` and `any-pointer: coarse`', () => {
Object.defineProperty(window, 'matchMedia', {
value: vi.fn().mockImplementation((query: string) => {
const { fine, coarse } = detectPointerType(query);
return { matches: fine && coarse };
}),
});
const { isTouchDevice } = useDeviceSupport();
expect(isTouchDevice).toEqual(false);
});
it('should be true if window matches `any-pointer: coarse` and `!any-pointer: fine`', () => {
Object.defineProperty(window, 'matchMedia', {
value: vi.fn().mockImplementation((query: string) => {
const { fine, coarse } = detectPointerType(query);
return { matches: coarse && !fine };
}),
});
const { isTouchDevice } = useDeviceSupport();
expect(isTouchDevice).toEqual(true);
});
});
describe('isMacOs', () => {

View file

@ -1,7 +1,16 @@
import { ref } from 'vue';
export function useDeviceSupport() {
const isTouchDevice = ref(window.hasOwnProperty('ontouchstart') || navigator.maxTouchPoints > 0);
/**
* Check if the device is a touch device but exclude devices that have a fine pointer (mouse or track-pad)
* - `fine` will check for an accurate pointing device. Examples include mice, touch-pads, and drawing styluses
* - `coarse` will check for a pointing device of limited accuracy. Examples include touchscreens and motion-detection sensors
* - `any-pointer` will check for the presence of any pointing device, if there are multiple of them
*/
const isTouchDevice = ref(
window.matchMedia('(any-pointer: coarse)').matches &&
!window.matchMedia('(any-pointer: fine)').matches,
);
const userAgent = ref(navigator.userAgent.toLowerCase());
const isMacOs = ref(
userAgent.value.includes('macintosh') ||

View file

@ -44,3 +44,18 @@ export class IntersectionObserver {
window.IntersectionObserver = IntersectionObserver;
global.IntersectionObserver = IntersectionObserver;
// Mocks for useDeviceSupport
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: vi.fn().mockImplementation((query) => ({
matches: true,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
dispatchEvent: vi.fn(),
})),
});