| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | const getBreakpointValue = (variableName: string): number => { |
| | const root = document.documentElement; |
| | const value = getComputedStyle(root).getPropertyValue(variableName).trim(); |
| |
|
| | if (!value) { |
| | throw new Error(`CSS variable ${variableName} is not defined`); |
| | } |
| |
|
| | const parsed = parseInt(value, 10); |
| | if (isNaN(parsed)) { |
| | throw new Error(`CSS variable ${variableName} is not a valid number: ${value}`); |
| | } |
| |
|
| | return parsed; |
| | }; |
| |
|
| | |
| | let mobileBreakpoint: number | null = null; |
| | let mobileMediaQuery: MediaQueryList | null = null; |
| |
|
| | |
| | |
| | |
| | const getMobileMediaQuery = (): MediaQueryList => { |
| | if (mobileMediaQuery === null) { |
| | if (mobileBreakpoint === null) { |
| | mobileBreakpoint = getBreakpointValue('--breakpoint-mobile'); |
| | } |
| | mobileMediaQuery = window.matchMedia(`(max-width: ${mobileBreakpoint}px)`); |
| | } |
| | return mobileMediaQuery; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | export const isNarrowScreen = (): boolean => getMobileMediaQuery().matches; |
| |
|
| | |
| | |
| | |
| | |
| | export const isMobileDevice = (): boolean => { |
| | |
| | const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0; |
| | |
| | |
| | const hasMouse = window.matchMedia('(pointer: fine)').matches; |
| | |
| | |
| | const hasHover = window.matchMedia('(hover: hover)').matches; |
| | |
| | |
| | return hasTouch && (!hasMouse || !hasHover); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export const getVerticalScrollbarWidth = (): number => { |
| | |
| | |
| | const width = window.innerWidth - document.documentElement.clientWidth; |
| | return width > 0 ? width : 0; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | export const isTraditionalScrollbar = (): boolean => getVerticalScrollbarWidth() > 0; |