diff --git a/overlay/src/app/pages/auth/ServerPicker.tsx b/overlay/src/app/pages/auth/ServerPicker.tsx new file mode 100644 index 0000000..4e639e8 --- /dev/null +++ b/overlay/src/app/pages/auth/ServerPicker.tsx @@ -0,0 +1,149 @@ +import React, { + FocusEventHandler, + KeyboardEventHandler, + MouseEventHandler, + useEffect, + useRef, + useState, +} from 'react'; +import { + Header, + Icon, + IconButton, + Icons, + Input, + Menu, + MenuItem, + PopOut, + RectCords, + Text, + config, +} from 'folds'; +import FocusTrap from 'focus-trap-react'; + +import { stopPropagation } from '../../utils/keyboard'; + +export function ServerPicker({ + server, + serverList, + allowCustomServer, + onServerChange, +}: { + server: string; + serverList: string[]; + allowCustomServer?: boolean; + onServerChange: (server: string) => void; +}) { + const [serverMenuAnchor, setServerMenuAnchor] = useState(); + const serverInputRef = useRef(null); + + useEffect(() => { + // Only sync input when server changes externally (e.g., from menu selection) + // and input is not focused to avoid cursor jumping during typing + if ( + serverInputRef.current && + serverInputRef.current.value !== server && + document.activeElement !== serverInputRef.current + ) { + serverInputRef.current.value = server; + } + }, [server]); + + const handleBlur: FocusEventHandler = (evt) => { + const inputServer = evt.target.value.trim(); + if (inputServer && inputServer !== server) { + onServerChange(inputServer); + } + }; + + const handleKeyDown: KeyboardEventHandler = (evt) => { + if (evt.key === 'ArrowDown') { + evt.preventDefault(); + setServerMenuAnchor(undefined); + } + if (evt.key === 'Enter') { + evt.preventDefault(); + const inputServer = evt.currentTarget.value.trim(); + if (inputServer) onServerChange(inputServer); + } + }; + + const handleServerSelect: MouseEventHandler = (evt) => { + const selectedServer = evt.currentTarget.getAttribute('data-server'); + if (selectedServer) { + onServerChange(selectedServer); + } + setServerMenuAnchor(undefined); + }; + + const handleOpenServerMenu: MouseEventHandler = (evt) => { + const target = evt.currentTarget.parentElement ?? evt.currentTarget; + setServerMenuAnchor(target.getBoundingClientRect()); + }; + + return ( + setServerMenuAnchor(undefined), + clickOutsideDeactivates: true, + isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown', + isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp', + escapeDeactivates: stopPropagation, + }} + > + +
+ Homeserver List +
+
+ {serverList?.map((serverName) => ( + + {serverName} + + ))} +
+
+ + } + > + + + + + ) + } + /> + ); +}