Enable keyboard navigation in member invite list (#7102)

* feat: keyboard nav in share popover

* fix: memoize
This commit is contained in:
Apoorv Mishra
2024-06-22 06:05:05 +05:30
committed by GitHub
parent 5ddc36555d
commit 0f1f0e82c2
13 changed files with 274 additions and 63 deletions

View File

@@ -18,6 +18,7 @@ import useBoolean from "~/hooks/useBoolean";
import useCurrentTeam from "~/hooks/useCurrentTeam";
import useKeyDown from "~/hooks/useKeyDown";
import usePolicy from "~/hooks/usePolicy";
import usePrevious from "~/hooks/usePrevious";
import useStores from "~/hooks/useStores";
import { Permission } from "~/types";
import { documentPath, urlify } from "~/utils/routeHelpers";
@@ -64,6 +65,11 @@ function SharePopover({
DocumentPermission.Read
);
const prevPendingIds = usePrevious(pendingIds);
const suggestionsRef = React.useRef<HTMLDivElement | null>(null);
const searchInputRef = React.useRef<HTMLInputElement | null>(null);
useKeyDown(
"Escape",
(ev) => {
@@ -107,6 +113,19 @@ function SharePopover({
}
}, [picker]);
React.useEffect(() => {
if (prevPendingIds && pendingIds.length > prevPendingIds.length) {
setQuery("");
searchInputRef.current?.focus();
} else if (prevPendingIds && pendingIds.length < prevPendingIds.length) {
const firstPending = suggestionsRef.current?.firstElementChild;
if (firstPending) {
(firstPending as HTMLAnchorElement).focus();
}
}
}, [pendingIds, prevPendingIds]);
const inviteAction = React.useMemo(
() =>
createAction({
@@ -202,6 +221,39 @@ function SharePopover({
[setPendingIds]
);
const handleKeyDown = React.useCallback(
(ev: React.KeyboardEvent<HTMLInputElement>) => {
if (ev.nativeEvent.isComposing) {
return;
}
if (ev.key === "ArrowDown" && !ev.shiftKey) {
ev.preventDefault();
if (ev.currentTarget.value) {
const length = ev.currentTarget.value.length;
const selectionStart = ev.currentTarget.selectionStart || 0;
if (selectionStart < length) {
ev.currentTarget.selectionStart = length;
ev.currentTarget.selectionEnd = length;
return;
}
}
const firstSuggestion = suggestionsRef.current?.firstElementChild;
if (firstSuggestion) {
(firstSuggestion as HTMLAnchorElement).focus();
}
}
},
[]
);
const handleEscape = React.useCallback(
() => searchInputRef.current?.focus(),
[]
);
const permissions = React.useMemo(
() =>
[
@@ -266,8 +318,10 @@ function SharePopover({
<Wrapper>
{can.manageUsers && (
<SearchInput
ref={searchInputRef}
onChange={handleQuery}
onClick={showPicker}
onKeyDown={handleKeyDown}
query={query}
back={backButton}
action={rightButton}
@@ -275,15 +329,15 @@ function SharePopover({
)}
{picker && (
<div>
<Suggestions
document={document}
query={query}
pendingIds={pendingIds}
addPendingId={handleAddPendingId}
removePendingId={handleRemovePendingId}
/>
</div>
<Suggestions
ref={suggestionsRef}
document={document}
query={query}
pendingIds={pendingIds}
addPendingId={handleAddPendingId}
removePendingId={handleRemovePendingId}
onEscape={handleEscape}
/>
)}
<div style={{ display: picker ? "none" : "block" }}>