Bluesky app fork with some witchin' additions 💫
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 71 lines 1.9 kB view raw
1import {useEffect} from 'react' 2 3import {IS_WEB_MOBILE_IOS} from '#/env' 4 5const ZOOM_LOCKED_VIEWPORT = 6 'width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, viewport-fit=cover' 7 8/** 9 * iOS Safari zooms in when a text input with `font-size < 16px` gains focus. 10 * To avoid that while still allowing users to pinch-zoom for accessibility, we 11 * only pin `maximum-scale=1` while a text input is focused and restore the 12 * original viewport on blur. 13 * 14 * Listeners run in the capture phase so we update the viewport before iOS 15 * commits to auto-zooming the input. 16 */ 17export function useViewportZoomLock({enabled} = {enabled: true}) { 18 useEffect(() => { 19 if (!IS_WEB_MOBILE_IOS) return 20 if (!enabled) return 21 22 const meta = document.querySelector('meta[name="viewport"]') 23 if (!(meta instanceof HTMLMetaElement)) return 24 25 const originalContent = meta.content 26 27 const onFocus = (e: FocusEvent) => { 28 if (isTextInput(e.target)) { 29 meta.content = ZOOM_LOCKED_VIEWPORT 30 } 31 } 32 33 const onBlur = (e: FocusEvent) => { 34 if (isTextInput(e.target)) { 35 meta.content = originalContent 36 } 37 } 38 39 document.addEventListener('focus', onFocus, true) 40 document.addEventListener('blur', onBlur, true) 41 42 return () => { 43 document.removeEventListener('focus', onFocus, true) 44 document.removeEventListener('blur', onBlur, true) 45 meta.content = originalContent 46 } 47 }, [enabled]) 48} 49 50const NON_TEXT_INPUT_TYPES = new Set([ 51 'button', 52 'checkbox', 53 'color', 54 'file', 55 'hidden', 56 'image', 57 'radio', 58 'range', 59 'reset', 60 'submit', 61]) 62 63function isTextInput(target: EventTarget | null): boolean { 64 if (!(target instanceof HTMLElement)) return false 65 if (target.isContentEditable) return true 66 if (target instanceof HTMLTextAreaElement) return true 67 if (target instanceof HTMLInputElement) { 68 return !NON_TEXT_INPUT_TYPES.has(target.type) 69 } 70 return false 71}