Skip to content

Commit 1d5b084

Browse files
committed
more improvements to user agent logic
1 parent d4c2d93 commit 1d5b084

2 files changed

Lines changed: 28 additions & 79 deletions

File tree

src/shared/useragent/detect.ts

Lines changed: 12 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ const PATTERNS = {
2121
GENERIC_VERSION: /version\/(\d+(?:\.\d+)?)/i,
2222
} as const;
2323

24-
// Ordered from most specific to least specific
2524
const BROWSER_CONFIGS: BrowserConfig[] = [
2625
{
2726
name: 'Opera',
@@ -55,8 +54,8 @@ const BROWSER_CONFIGS: BrowserConfig[] = [
5554
},
5655
{
5756
name: 'Microsoft Edge',
58-
pattern: /(edge|edgios|edga|edg)/i,
59-
versionPattern: /(edge|edgios|edga|edg)[\s\/](\d+(?:\.\d+)?)/i,
57+
pattern: /(?:edge|edgios|edga|edg)/i,
58+
versionPattern: /(?:edge|edgios|edga|edg)[\s\/](\d+(?:\.\d+)?)/i,
6059
},
6160
{
6261
name: 'Firefox',
@@ -84,33 +83,16 @@ const matchUserAgent = (
8483
userAgent: string,
8584
position: number,
8685
pattern: RegExp,
87-
): string => {
88-
const match = userAgent.match(pattern);
89-
return match?.[position] || '';
90-
};
91-
92-
const safeNavigator = () =>
93-
typeof navigator !== 'undefined' ? navigator : null;
94-
const safeWindow = () => (typeof window !== 'undefined' ? window : null);
86+
): string => userAgent.match(pattern)?.[position] || '';
9587

9688
function extractVersion(userAgent: string, config: BrowserConfig): string {
97-
if (config.versionPattern) {
98-
const match = userAgent.match(config.versionPattern);
99-
if (match) {
100-
const index = config.versionPattern.source.includes('(')
101-
? config.name === 'Microsoft Edge'
102-
? 2
103-
: 1
104-
: 1;
105-
return match[index] || '';
106-
}
107-
}
108-
return matchUserAgent(userAgent, 1, PATTERNS.GENERIC_VERSION);
89+
if (!config.versionPattern)
90+
return matchUserAgent(userAgent, 1, PATTERNS.GENERIC_VERSION);
91+
const match = userAgent.match(config.versionPattern);
92+
return match?.[1] || '';
10993
}
11094

11195
export function getBrowser(userAgent: string): IBrowserResult {
112-
if (!userAgent) return { name: 'Unknown', version: '' };
113-
11496
for (const config of BROWSER_CONFIGS) {
11597
if (config.pattern.test(userAgent)) {
11698
return { name: config.name, version: extractVersion(userAgent, config) };
@@ -122,44 +104,30 @@ export function getBrowser(userAgent: string): IBrowserResult {
122104
};
123105
}
124106

125-
function isAndroidDevice(userAgent: string): boolean {
126-
return (
127-
!!userAgent &&
128-
!PATTERNS.LIKE_ANDROID.test(userAgent) &&
129-
PATTERNS.ANDROID.test(userAgent)
130-
);
131-
}
107+
const isAndroidDevice = (userAgent: string): boolean =>
108+
!PATTERNS.LIKE_ANDROID.test(userAgent) && PATTERNS.ANDROID.test(userAgent);
132109

133110
export function getIOSDeviceType(userAgent: string): string {
134-
if (!userAgent) return '';
135-
136111
let deviceType = matchUserAgent(
137112
userAgent,
138113
1,
139114
PATTERNS.IOS_DEVICES,
140115
).toLowerCase();
141116

142-
// iPadOS workaround
143-
const nav = safeNavigator();
144-
const win = safeWindow();
145117
if (
146118
!deviceType &&
147-
nav?.platform === 'MacIntel' &&
148-
nav?.maxTouchPoints > 2 &&
149-
!(win as { MSStream?: unknown })?.MSStream
119+
navigator.platform === 'MacIntel' &&
120+
navigator.maxTouchPoints > 2 &&
121+
!(window as { MSStream?: unknown })?.MSStream
150122
) {
151123
deviceType = 'ipad';
152124
}
153-
154125
return deviceType;
155126
}
156127

157128
export function isTablet(userAgent: string): boolean {
158-
if (!userAgent) return false;
159-
160129
const isAndroid = isAndroidDevice(userAgent);
161130
const iOSDevice = getIOSDeviceType(userAgent);
162-
163131
return (
164132
(PATTERNS.TABLET.test(userAgent) && !PATTERNS.TABLET_PC.test(userAgent)) ||
165133
iOSDevice === 'ipad' ||
@@ -170,12 +138,9 @@ export function isTablet(userAgent: string): boolean {
170138
}
171139

172140
export function isMobile(userAgent: string): boolean {
173-
if (!userAgent) return false;
174-
175141
const isTabletDevice = isTablet(userAgent);
176142
const isAndroid = isAndroidDevice(userAgent);
177143
const iOSDevice = getIOSDeviceType(userAgent);
178-
179144
return (
180145
!isTabletDevice &&
181146
(PATTERNS.MOBILE.test(userAgent) ||

src/shared/useragent/useragent.ts

Lines changed: 16 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,33 @@ import { Browser } from './constants';
22
import { getBrowser, isMobile, isTablet } from './detect';
33
import type { BrowserValue } from './types';
44

5-
// Reference: https://github.com/TimvanScherpenzeel/detect-ua/blob/master/src/index.ts
5+
const BROWSER_MAP: Record<string, BrowserValue> = {
6+
Chrome: Browser.Chrome,
7+
Chromium: Browser.Chrome,
8+
Firefox: Browser.Firefox,
9+
'Microsoft Edge': Browser.Edge,
10+
Safari: Browser.Safari,
11+
};
612

713
export function getBrowserName(): BrowserValue {
8-
const name = getBrowser(navigator.userAgent).name;
9-
switch (name) {
10-
case 'Chrome':
11-
case 'Chromium':
12-
return Browser.Chrome;
13-
case 'Firefox':
14-
return Browser.Firefox;
15-
case 'Microsoft Edge':
16-
return Browser.Edge;
17-
case 'Safari':
18-
return Browser.Safari;
19-
default:
20-
return Browser.Other;
21-
}
14+
return BROWSER_MAP[getBrowser(navigator.userAgent).name] || Browser.Other;
2215
}
2316

24-
export function getBrowserVersion(): number {
17+
export const getBrowserVersion = (): number => {
2518
const version = getBrowser(navigator.userAgent).version;
2619
if (!version) return -1;
2720
const [major, minor = '0'] = version.split('.');
2821
return +`${major}.${minor}`;
29-
}
30-
31-
export function isMobileBrowser(): boolean {
32-
return isMobile(navigator.userAgent);
33-
}
22+
};
3423

35-
export function isTabletBrowser(): boolean {
36-
return isTablet(navigator.userAgent);
37-
}
24+
export const isMobileBrowser = (): boolean => isMobile(navigator.userAgent);
25+
export const isTabletBrowser = (): boolean => isTablet(navigator.userAgent);
3826

3927
export function requiresUserInteraction(): boolean {
4028
const browserName = getBrowserName();
4129
const version = getBrowserVersion();
42-
43-
// Firefox 72+ requires user-interaction
44-
if (browserName === Browser.Firefox && version >= 72) return true;
45-
46-
// Safari 12.1+ requires user-interaction
47-
if (browserName === Browser.Safari && version >= 12.1) return true;
48-
49-
return false;
30+
return (
31+
(browserName === Browser.Firefox && version >= 72) ||
32+
(browserName === Browser.Safari && version >= 12.1)
33+
);
5034
}

0 commit comments

Comments
 (0)