leap: portalled menu for less dupe

This commit is contained in:
Hunter Miller 2021-08-16 10:59:52 -05:00
parent d89cfc7291
commit edde5e3ec4

View File

@ -1,4 +1,5 @@
import { DialogContent } from '@radix-ui/react-dialog'; import { DialogContent } from '@radix-ui/react-dialog';
import * as Portal from '@radix-ui/react-portal';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { import React, {
ChangeEvent, ChangeEvent,
@ -80,8 +81,11 @@ export const Nav: FunctionComponent<NavProps> = ({ menu = 'closed' }) => {
const { push } = useHistory(); const { push } = useHistory();
const location = useLocation(); const location = useLocation();
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const navRef = useRef<HTMLDivElement>(null);
const dialogNavRef = useRef<HTMLDivElement>(null);
const { searchInput, setSearchInput, selection, select } = useNavStore(); const { searchInput, setSearchInput, selection, select } = useNavStore();
const [systemMenuOpen, setSystemMenuOpen] = useState(false); const [systemMenuOpen, setSystemMenuOpen] = useState(false);
const [delayedOpen, setDelayedOpen] = useState(false);
const isOpen = menu !== 'closed'; const isOpen = menu !== 'closed';
const eitherOpen = isOpen || systemMenuOpen; const eitherOpen = isOpen || systemMenuOpen;
@ -90,8 +94,11 @@ export const Nav: FunctionComponent<NavProps> = ({ menu = 'closed' }) => {
(event: Event) => { (event: Event) => {
event.preventDefault(); event.preventDefault();
setDelayedOpen(true);
if (menu === 'search' && inputRef.current) { if (menu === 'search' && inputRef.current) {
inputRef.current.focus(); setTimeout(() => {
inputRef.current?.focus();
}, 0);
} }
}, },
[menu] [menu]
@ -119,6 +126,7 @@ export const Nav: FunctionComponent<NavProps> = ({ menu = 'closed' }) => {
const onDialogClose = useCallback((open: boolean) => { const onDialogClose = useCallback((open: boolean) => {
if (!open) { if (!open) {
select(null); select(null);
setDelayedOpen(false);
push('/'); push('/');
} }
}, []); }, []);
@ -156,91 +164,75 @@ export const Nav: FunctionComponent<NavProps> = ({ menu = 'closed' }) => {
}, []); }, []);
return ( return (
<menu className="w-full max-w-3xl my-6 px-4 text-gray-400 font-semibold"> <>
<div className={classNames('flex space-x-2', isOpen && 'invisible')}> <Portal.Root containerRef={delayedOpen ? dialogNavRef : navRef} className="flex space-x-2">
{!isOpen && ( <SystemMenu
<SystemMenu open={systemMenuOpen}
showOverlay setOpen={setSystemMenuOpen}
open={systemMenuOpen} className={classNames('relative z-50 flex-none', eitherOpen ? 'bg-white' : 'bg-gray-100')}
setOpen={setSystemMenuOpen} />
className={classNames(
'relative z-50 flex-none',
eitherOpen ? 'bg-white' : 'bg-gray-100'
)}
/>
)}
<Link <Link
to="/leap/notifications" to="/leap/notifications"
className="relative z-50 flex-none circle-button bg-blue-400 text-white default-ring" className="relative z-50 flex-none circle-button bg-blue-400 text-white"
> >
3 3
</Link> </Link>
<input <form
onClick={toggleSearch} className={classNames(
onFocus={onFocus} 'relative z-50 flex items-center w-full px-2 rounded-full bg-white default-ring focus-within:ring-4',
type="text" !isOpen && 'bg-gray-100'
className="relative z-50 rounded-full w-full pl-4 h4 bg-gray-100 default-ring" )}
placeholder="Search Landscape" onSubmit={() => {}}
/> >
</div> <label
htmlFor="leap"
className={classNames(
'inline-block flex-none p-2 h4 text-blue-400',
!selection && 'sr-only'
)}
>
{selection || 'Search Landscape'}
</label>
<input
id="leap"
type="text"
ref={inputRef}
placeholder={selection ? '' : 'Search Landscape'}
className="flex-1 w-full h-full px-2 h4 rounded-full bg-transparent outline-none"
value={searchInput}
onClick={toggleSearch}
onFocus={onFocus}
onChange={onChange}
role="combobox"
aria-controls="leap-items"
aria-expanded
/>
{(selection || searchInput) && (
<Link
to="/"
className="circle-button w-8 h-8 text-gray-400 bg-gray-100 default-ring"
onClick={() => select(null)}
>
<Cross className="w-3 h-3 fill-current" />
<span className="sr-only">Close</span>
</Link>
)}
</form>
</Portal.Root>
<menu
ref={navRef}
className={classNames(
'w-full max-w-3xl my-6 px-4 text-gray-400 font-semibold',
delayedOpen && 'h-12'
)}
/>
<Dialog open={isOpen} onOpenChange={onDialogClose}> <Dialog open={isOpen} onOpenChange={onDialogClose}>
<DialogContent <DialogContent
onOpenAutoFocus={onOpen} onOpenAutoFocus={onOpen}
className="fixed top-0 left-[calc(50%-7.5px)] w-[calc(100%-15px)] max-w-3xl px-4 text-gray-400 -translate-x-1/2 outline-none" className="fixed top-0 left-[calc(50%-7.5px)] w-[calc(100%-15px)] max-w-3xl px-4 text-gray-400 -translate-x-1/2 outline-none"
> >
<div tabIndex={-1} onKeyDown={onDialogKey} role="presentation"> <div tabIndex={-1} onKeyDown={onDialogKey} role="presentation">
<header className="flex my-6 space-x-2"> <header ref={dialogNavRef} className="my-6" />
<SystemMenu
open={systemMenuOpen}
setOpen={setSystemMenuOpen}
className={classNames(
'relative z-50 flex-none',
eitherOpen ? 'bg-white' : 'bg-gray-100'
)}
/>
<Link
to="/leap/notifications"
className="relative z-50 flex-none circle-button bg-blue-400 text-white"
>
3
</Link>
<div className="relative z-50 flex items-center w-full px-2 rounded-full bg-white default-ring focus-within:ring-4">
<label
htmlFor="leap"
className={classNames(
'inline-block flex-none p-2 h4 text-blue-400',
!selection && 'sr-only'
)}
>
{selection || 'Search Landscape'}
</label>
<input
id="leap"
type="text"
ref={inputRef}
placeholder={selection ? '' : 'Search Landscape'}
className="flex-1 w-full h-full px-2 h4 rounded-full bg-transparent outline-none"
value={searchInput}
onClick={toggleSearch}
onFocus={onFocus}
onChange={onChange}
role="combobox"
aria-controls="leap-items"
aria-expanded
/>
{(selection || searchInput) && (
<Link
to="/"
className="circle-button w-8 h-8 text-gray-400 bg-gray-100 default-ring"
onClick={() => select(null)}
>
<Cross className="w-3 h-3 fill-current" />
<span className="sr-only">Close</span>
</Link>
)}
</div>
</header>
<div <div
id="leap-items" id="leap-items"
className="grid grid-rows-[fit-content(calc(100vh-7.5rem))] bg-white rounded-3xl overflow-hidden" className="grid grid-rows-[fit-content(calc(100vh-7.5rem))] bg-white rounded-3xl overflow-hidden"
@ -256,6 +248,6 @@ export const Nav: FunctionComponent<NavProps> = ({ menu = 'closed' }) => {
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
</menu> </>
); );
}; };