Add expander for reactions view

This commit is contained in:
Will Hunt 2024-11-11 12:53:25 +00:00
parent 543f656548
commit 2c889f9b45
2 changed files with 11 additions and 80 deletions

View File

@ -22,6 +22,8 @@
display: flex;
flex-wrap: wrap;
gap: var(--cpd-separator-spacing);
max-height: 10em;
max-width: 22.5em;
}
.reactionPopupMenu section {
@ -63,18 +65,6 @@
margin-left: var(--cpd-separator-spacing);
margin-right: var(--cpd-separator-spacing);
}
.searchForm {
display: flex;
flex-direction: row;
gap: var(--cpd-separator-spacing);
margin-bottom: var(--cpd-space-3x);
}
.searchForm > label {
flex: auto;
}
.alert {
margin-bottom: var(--cpd-space-3x);
animation: grow-in 200ms;

View File

@ -13,16 +13,14 @@ import {
Alert,
} from "@vector-im/compound-web";
import {
SearchIcon,
CloseIcon,
RaisedHandSolidIcon,
ReactionIcon,
ChevronDownIcon,
ChevronUpIcon,
} from "@vector-im/compound-design-tokens/assets/web/icons";
import {
ChangeEventHandler,
ComponentPropsWithoutRef,
FC,
KeyboardEventHandler,
ReactNode,
useCallback,
useEffect,
@ -84,44 +82,14 @@ export function ReactionPopupMenu({
canReact: boolean;
}): ReactNode {
const { t } = useTranslation();
const [searchText, setSearchText] = useState("");
const [isSearching, setIsSearching] = useState(false);
const onSearch = useCallback<ChangeEventHandler<HTMLInputElement>>((ev) => {
ev.preventDefault();
setSearchText(ev.target.value.trim().toLocaleLowerCase());
}, []);
const [isFullyExpanded, setExpanded] = useState(false);
const filteredReactionSet = useMemo(
() =>
ReactionSet.filter(
(reaction) =>
!isSearching ||
(!!searchText &&
(reaction.name.startsWith(searchText) ||
reaction.alias?.some((a) => a.startsWith(searchText)))),
).slice(0, 6),
[searchText, isSearching],
isFullyExpanded ? ReactionSet : ReactionSet.slice(0, 6),
[isFullyExpanded],
);
const onSearchKeyDown = useCallback<KeyboardEventHandler<never>>(
(ev) => {
if (ev.key === "Enter") {
ev.preventDefault();
if (!canReact) {
return;
}
if (filteredReactionSet.length !== 1) {
return;
}
sendReaction(filteredReactionSet[0]);
setIsSearching(false);
} else if (ev.key === "Escape") {
ev.preventDefault();
setIsSearching(false);
}
},
[sendReaction, filteredReactionSet, canReact, setIsSearching],
);
const label = isHandRaised ? t("action.lower_hand") : t("action.raise_hand");
return (
<>
@ -149,31 +117,6 @@ export function ReactionPopupMenu({
</section>
<div className={styles.verticalSeperator} />
<section>
{isSearching ? (
<>
<Form.Root className={styles.searchForm}>
<Search
required
value={searchText}
name="reactionSearch"
placeholder={t("reaction_search")}
onChange={onSearch}
onKeyDown={onSearchKeyDown}
// This is a reasonable use of autofocus, we are focusing when
// the search button is clicked (which matches the Element Web reaction picker)
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
/>
<CpdButton
Icon={CloseIcon}
aria-label={t("action.close_search")}
size="sm"
kind="destructive"
onClick={() => setIsSearching(false)}
/>
</Form.Root>
</>
) : null}
<menu className={styles.reactionsMenu}>
{filteredReactionSet.map((reaction) => (
<li className={styles.reactionPopupMenuItem} key={reaction.name}>
@ -191,21 +134,19 @@ export function ReactionPopupMenu({
))}
</menu>
</section>
{!isSearching ? (
<section style={{ marginLeft: "var(--cpd-separator-spacing)" }}>
<li key="search" className={styles.reactionPopupMenuItem}>
<Tooltip label={t("common.search")}>
<Tooltip label={isFullyExpanded ? t("action.show_less") : t("action.show_more")}>
<CpdButton
iconOnly
aria-label={t("action.open_search")}
Icon={SearchIcon}
aria-label={isFullyExpanded ? t("action.show_less") : t("action.show_more")}
Icon={isFullyExpanded ? ChevronUpIcon : ChevronDownIcon}
kind="tertiary"
onClick={() => setIsSearching(true)}
onClick={() => setExpanded(!isFullyExpanded)}
/>
</Tooltip>
</li>
</section>
) : null}
</div>
</>
);