personal web client for Bluesky
typescript solidjs bluesky atcute

fix: use closewatcher on search

mary.my.id e514580b 18a607f1

verified
Changed files
+57 -42
src
lib
views
+40 -32
src/lib/hooks/modal-close.ts
··· 4 4 5 5 const isCloseWatcherAvailable = typeof CloseWatcher !== 'undefined'; 6 6 7 - export const useModalClose = (container: HTMLElement, callback: () => void, enabled: () => boolean) => { 7 + export const useModalClose = ( 8 + container: HTMLElement | null, 9 + callback: () => void, 10 + enabled: () => boolean, 11 + ) => { 8 12 createEffect(() => { 9 13 if (!enabled()) { 10 14 return; 11 15 } 12 16 13 - // Close modal if clicks happen outside of container 14 - let initialTarget: HTMLElement | null = null; 17 + if (container !== null) { 18 + // Close modal if clicks happen outside of container 19 + let initialTarget: HTMLElement | null = null; 15 20 16 - createEventListener(document, 'pointerdown', (ev) => { 17 - // We'd like to know where the click initially started from, not where the 18 - // click ended up, this prevents closing the modal prematurely from the 19 - // user (accidentally) overshooting their mouse cursor. 21 + createEventListener(document, 'pointerdown', (ev) => { 22 + // We'd like to know where the click initially started from, not where the 23 + // click ended up, this prevents closing the modal prematurely from the 24 + // user (accidentally) overshooting their mouse cursor. 20 25 21 - initialTarget = ev.target as HTMLElement | null; 22 - }); 26 + initialTarget = ev.target as HTMLElement | null; 27 + }); 23 28 24 - createEventListener( 25 - document, 26 - 'click', 27 - () => { 28 - // Don't do anything if `initialTarget` is somehow missing 29 - if (!initialTarget) { 30 - return; 31 - } 29 + createEventListener( 30 + document, 31 + 'click', 32 + () => { 33 + // Don't do anything if `initialTarget` is somehow missing 34 + if (!initialTarget) { 35 + return; 36 + } 32 37 33 - // Unset `initialTarget` now that we're here 34 - const target = initialTarget; 35 - initialTarget = null; 38 + // Unset `initialTarget` now that we're here 39 + const target = initialTarget; 40 + initialTarget = null; 36 41 37 - // Don't do anything if `target` is inside `container` 38 - if (container.contains(target)) { 39 - return; 40 - } 42 + // Don't do anything if `target` is inside `container` 43 + if (container.contains(target)) { 44 + return; 45 + } 41 46 42 - // Call back since this click happened outside `container`. 43 - callback(); 44 - }, 45 - true, 46 - ); 47 + // Call back since this click happened outside `container`. 48 + callback(); 49 + }, 50 + true, 51 + ); 52 + } 47 53 48 54 // Start a close watcher if available, otherwise, listen to Escape key only 49 55 if (isCloseWatcherAvailable) { ··· 59 65 if (ev.key === 'Escape' && !ev.defaultPrevented) { 60 66 ev.preventDefault(); 61 67 62 - const focused = document.activeElement; 63 - if (focused !== null && focused !== document.body) { 64 - (focused as any).blur(); 68 + if (container !== null) { 69 + const focused = document.activeElement; 70 + if (focused !== null && focused !== document.body) { 71 + (focused as any).blur(); 72 + } 65 73 } 66 74 67 75 callback();
+8 -5
src/views/main/explore.tsx
··· 2 2 3 3 import { Freeze } from '@mary/solid-freeze'; 4 4 5 + import { hasModals } from '~/globals/modals'; 5 6 import { history } from '~/globals/navigation'; 6 7 8 + import { useModalClose } from '~/lib/hooks/modal-close'; 7 9 import { createFocusEffect, useTitle } from '~/lib/navigation/router'; 8 10 9 11 import MyFeedsSection from '~/components/explore/my-feeds-section'; ··· 28 30 createEffect(() => { 29 31 if (isInputFocused()) { 30 32 window.scrollTo({ top: 0, behavior: 'instant' }); 33 + 34 + useModalClose( 35 + null, 36 + () => setIsInputFocused(false), 37 + () => !hasModals(), 38 + ); 31 39 } 32 40 }); 33 41 ··· 59 67 setIsInputFocused(true); 60 68 }} 61 69 onClick={() => setIsInputFocused(true)} 62 - onKeyDown={(ev) => { 63 - if (ev.key === 'Escape') { 64 - setIsInputFocused(false); 65 - } 66 - }} 67 70 onSubmit={() => { 68 71 const $query = query(); 69 72 if ($query.trim() === '') {
+9 -5
src/views/search.tsx
··· 2 2 3 3 import { Freeze, ShowFreeze } from '@mary/solid-freeze'; 4 4 5 + import { hasModals } from '~/globals/modals'; 6 + 5 7 import { tokenizeSearchQuery } from '~/lib/bsky/search'; 6 8 import { createDerivedSignal } from '~/lib/hooks/derived-signal'; 9 + import { useModalClose } from '~/lib/hooks/modal-close'; 7 10 import { asString, asStringUnion, useSearchParams } from '~/lib/hooks/search-params'; 8 11 import { createFocusEffect, useTitle } from '~/lib/navigation/router'; 9 12 ··· 39 42 createEffect(() => { 40 43 if (isInputFocused()) { 41 44 window.scrollTo({ top: 0, behavior: 'instant' }); 45 + 46 + useModalClose( 47 + null, 48 + () => setIsInputFocused(false), 49 + () => !hasModals(), 50 + ); 42 51 } 43 52 }); 44 53 ··· 70 79 setIsInputFocused(true); 71 80 }} 72 81 onClick={() => setIsInputFocused(true)} 73 - onKeyDown={(ev) => { 74 - if (ev.key === 'Escape') { 75 - setIsInputFocused(false); 76 - } 77 - }} 78 82 onSubmit={() => { 79 83 const $query = query(); 80 84 if ($query.trim() === '') {