mirror of
https://github.com/vector-im/element-call.git
synced 2024-11-24 00:38:31 +08:00
Add expander for reactions view
This commit is contained in:
parent
543f656548
commit
2c889f9b45
@ -22,6 +22,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
gap: var(--cpd-separator-spacing);
|
gap: var(--cpd-separator-spacing);
|
||||||
|
max-height: 10em;
|
||||||
|
max-width: 22.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reactionPopupMenu section {
|
.reactionPopupMenu section {
|
||||||
@ -63,18 +65,6 @@
|
|||||||
margin-left: var(--cpd-separator-spacing);
|
margin-left: var(--cpd-separator-spacing);
|
||||||
margin-right: 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 {
|
.alert {
|
||||||
margin-bottom: var(--cpd-space-3x);
|
margin-bottom: var(--cpd-space-3x);
|
||||||
animation: grow-in 200ms;
|
animation: grow-in 200ms;
|
||||||
|
@ -13,16 +13,14 @@ import {
|
|||||||
Alert,
|
Alert,
|
||||||
} from "@vector-im/compound-web";
|
} from "@vector-im/compound-web";
|
||||||
import {
|
import {
|
||||||
SearchIcon,
|
|
||||||
CloseIcon,
|
|
||||||
RaisedHandSolidIcon,
|
RaisedHandSolidIcon,
|
||||||
ReactionIcon,
|
ReactionIcon,
|
||||||
|
ChevronDownIcon,
|
||||||
|
ChevronUpIcon,
|
||||||
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
} from "@vector-im/compound-design-tokens/assets/web/icons";
|
||||||
import {
|
import {
|
||||||
ChangeEventHandler,
|
|
||||||
ComponentPropsWithoutRef,
|
ComponentPropsWithoutRef,
|
||||||
FC,
|
FC,
|
||||||
KeyboardEventHandler,
|
|
||||||
ReactNode,
|
ReactNode,
|
||||||
useCallback,
|
useCallback,
|
||||||
useEffect,
|
useEffect,
|
||||||
@ -84,44 +82,14 @@ export function ReactionPopupMenu({
|
|||||||
canReact: boolean;
|
canReact: boolean;
|
||||||
}): ReactNode {
|
}): ReactNode {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [searchText, setSearchText] = useState("");
|
const [isFullyExpanded, setExpanded] = useState(false);
|
||||||
const [isSearching, setIsSearching] = useState(false);
|
|
||||||
const onSearch = useCallback<ChangeEventHandler<HTMLInputElement>>((ev) => {
|
|
||||||
ev.preventDefault();
|
|
||||||
setSearchText(ev.target.value.trim().toLocaleLowerCase());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const filteredReactionSet = useMemo(
|
const filteredReactionSet = useMemo(
|
||||||
() =>
|
() =>
|
||||||
ReactionSet.filter(
|
isFullyExpanded ? ReactionSet : ReactionSet.slice(0, 6),
|
||||||
(reaction) =>
|
[isFullyExpanded],
|
||||||
!isSearching ||
|
|
||||||
(!!searchText &&
|
|
||||||
(reaction.name.startsWith(searchText) ||
|
|
||||||
reaction.alias?.some((a) => a.startsWith(searchText)))),
|
|
||||||
).slice(0, 6),
|
|
||||||
[searchText, isSearching],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
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");
|
const label = isHandRaised ? t("action.lower_hand") : t("action.raise_hand");
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@ -149,31 +117,6 @@ export function ReactionPopupMenu({
|
|||||||
</section>
|
</section>
|
||||||
<div className={styles.verticalSeperator} />
|
<div className={styles.verticalSeperator} />
|
||||||
<section>
|
<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}>
|
<menu className={styles.reactionsMenu}>
|
||||||
{filteredReactionSet.map((reaction) => (
|
{filteredReactionSet.map((reaction) => (
|
||||||
<li className={styles.reactionPopupMenuItem} key={reaction.name}>
|
<li className={styles.reactionPopupMenuItem} key={reaction.name}>
|
||||||
@ -191,21 +134,19 @@ export function ReactionPopupMenu({
|
|||||||
))}
|
))}
|
||||||
</menu>
|
</menu>
|
||||||
</section>
|
</section>
|
||||||
{!isSearching ? (
|
|
||||||
<section style={{ marginLeft: "var(--cpd-separator-spacing)" }}>
|
<section style={{ marginLeft: "var(--cpd-separator-spacing)" }}>
|
||||||
<li key="search" className={styles.reactionPopupMenuItem}>
|
<li key="search" className={styles.reactionPopupMenuItem}>
|
||||||
<Tooltip label={t("common.search")}>
|
<Tooltip label={isFullyExpanded ? t("action.show_less") : t("action.show_more")}>
|
||||||
<CpdButton
|
<CpdButton
|
||||||
iconOnly
|
iconOnly
|
||||||
aria-label={t("action.open_search")}
|
aria-label={isFullyExpanded ? t("action.show_less") : t("action.show_more")}
|
||||||
Icon={SearchIcon}
|
Icon={isFullyExpanded ? ChevronUpIcon : ChevronDownIcon}
|
||||||
kind="tertiary"
|
kind="tertiary"
|
||||||
onClick={() => setIsSearching(true)}
|
onClick={() => setExpanded(!isFullyExpanded)}
|
||||||
/>
|
/>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</li>
|
</li>
|
||||||
</section>
|
</section>
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user