mirror of
https://github.com/vector-im/element-call.git
synced 2026-03-31 07:00:26 +00:00
Add keyboard shortcuts for reaction sending.
This commit is contained in:
@@ -1,15 +1,24 @@
|
||||
import { act, render } from "@testing-library/react";
|
||||
/*
|
||||
Copyright 2024 New Vector Ltd.
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
Please see LICENSE in the repository root for full details.
|
||||
*/
|
||||
|
||||
import { act, fireEvent, render } from "@testing-library/react";
|
||||
import { expect, test } from "vitest";
|
||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
||||
import { TooltipProvider } from "@vector-im/compound-web";
|
||||
import { userEvent } from "@testing-library/user-event";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import {
|
||||
MockRoom,
|
||||
MockRTCSession,
|
||||
TestReactionsWrapper,
|
||||
} from "../utils/testReactions";
|
||||
import { ReactionToggleButton } from "./ReactionToggleButton";
|
||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc";
|
||||
import { TooltipProvider } from "@vector-im/compound-web";
|
||||
import { ElementCallReactionEventType } from "../reactions";
|
||||
import { userEvent } from "@testing-library/user-event";
|
||||
|
||||
const memberUserIdAlice = "@alice:example.org";
|
||||
const memberEventAlice = "$membership-alice:example.org";
|
||||
@@ -24,20 +33,20 @@ function TestComponent({
|
||||
}: {
|
||||
rtcSession: MockRTCSession;
|
||||
room: MockRoom;
|
||||
}) {
|
||||
}): ReactNode {
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<TestReactionsWrapper rtcSession={rtcSession}>
|
||||
<ReactionToggleButton
|
||||
rtcSession={rtcSession as unknown as MatrixRTCSession}
|
||||
client={room.client}
|
||||
></ReactionToggleButton>
|
||||
/>
|
||||
</TestReactionsWrapper>
|
||||
</TooltipProvider>
|
||||
);
|
||||
}
|
||||
|
||||
test("Can open menu", async () => {
|
||||
test("Can open menu", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, container } = render(
|
||||
@@ -47,7 +56,7 @@ test("Can open menu", async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("Can close menu", async () => {
|
||||
test("Can close menu", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, container } = render(
|
||||
@@ -60,7 +69,7 @@ test("Can close menu", async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("Can raise hand", async () => {
|
||||
test("Can raise hand", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, getByText, container } = render(
|
||||
@@ -88,7 +97,7 @@ test("Can raise hand", async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("Can can lower hand", async () => {
|
||||
test("Can can lower hand", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, getByText, container } = render(
|
||||
@@ -105,7 +114,7 @@ test("Can can lower hand", async () => {
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("Can react with emoji", async () => {
|
||||
test("Can react with emoji", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, getByText } = render(
|
||||
@@ -172,7 +181,47 @@ test("Can search for and send emoji", async () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("Can close search", async () => {
|
||||
test("Can search for and send emoji with the keyboard", async () => {
|
||||
const user = userEvent.setup();
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByText, getByRole, getByPlaceholderText, container } = render(
|
||||
<TestComponent rtcSession={rtcSession} room={room} />,
|
||||
);
|
||||
act(() => {
|
||||
getByRole("button").click();
|
||||
});
|
||||
act(() => {
|
||||
getByRole("button", {
|
||||
name: "Search",
|
||||
}).click();
|
||||
});
|
||||
const searchField = getByPlaceholderText("Search reactions…");
|
||||
await act(async () => {
|
||||
searchField.focus();
|
||||
await user.keyboard("crickets");
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
act(() => {
|
||||
fireEvent.keyDown(searchField, { key: "Enter" });
|
||||
});
|
||||
expect(room.testSentEvents).toEqual([
|
||||
[
|
||||
undefined,
|
||||
ElementCallReactionEventType,
|
||||
{
|
||||
"m.relates_to": {
|
||||
event_id: memberEventAlice,
|
||||
rel_type: "m.reference",
|
||||
},
|
||||
name: "crickets",
|
||||
emoji: "🦗",
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test("Can close search", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, container } = render(
|
||||
@@ -193,3 +242,24 @@ test("Can close search", async () => {
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test("Can close search with the escape key", () => {
|
||||
const room = new MockRoom(memberUserIdAlice);
|
||||
const rtcSession = new MockRTCSession(room, membership);
|
||||
const { getByRole, container, getByPlaceholderText } = render(
|
||||
<TestComponent rtcSession={rtcSession} room={room} />,
|
||||
);
|
||||
act(() => {
|
||||
getByRole("button").click();
|
||||
});
|
||||
act(() => {
|
||||
getByRole("button", {
|
||||
name: "Search",
|
||||
}).click();
|
||||
});
|
||||
const searchField = getByPlaceholderText("Search reactions…");
|
||||
act(() => {
|
||||
fireEvent.keyDown(searchField, { key: "Escape" });
|
||||
});
|
||||
expect(container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
@@ -21,8 +21,12 @@ import {
|
||||
ChangeEventHandler,
|
||||
ComponentPropsWithoutRef,
|
||||
FC,
|
||||
FormEventHandler,
|
||||
KeyboardEvent,
|
||||
KeyboardEventHandler,
|
||||
ReactNode,
|
||||
useCallback,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useState,
|
||||
} from "react";
|
||||
@@ -31,6 +35,7 @@ import { logger } from "matrix-js-sdk/src/logger";
|
||||
import { EventType, RelationType } from "matrix-js-sdk/src/matrix";
|
||||
import { MatrixClient } from "matrix-js-sdk/src/client";
|
||||
import { MatrixRTCSession } from "matrix-js-sdk/src/matrixrtc/MatrixRTCSession";
|
||||
import classNames from "classnames";
|
||||
|
||||
import { useReactions } from "../useReactions";
|
||||
import { useMatrixRTCSessionMemberships } from "../useMatrixRTCSessionMemberships";
|
||||
@@ -40,7 +45,6 @@ import {
|
||||
ReactionSet,
|
||||
ElementCallReactionEventType,
|
||||
} from "../reactions";
|
||||
import classNames from "classnames";
|
||||
|
||||
interface InnerButtonProps extends ComponentPropsWithoutRef<"button"> {
|
||||
raised: boolean;
|
||||
@@ -64,12 +68,12 @@ const InnerButton: FC<InnerButtonProps> = ({ raised, ...props }) => {
|
||||
};
|
||||
|
||||
export function ReactionPopupMenu({
|
||||
sendRelation,
|
||||
sendReaction,
|
||||
toggleRaisedHand,
|
||||
isHandRaised,
|
||||
canReact,
|
||||
}: {
|
||||
sendRelation: (reaction: ReactionOption) => void;
|
||||
sendReaction: (reaction: ReactionOption) => void;
|
||||
toggleRaisedHand: () => void;
|
||||
isHandRaised: boolean;
|
||||
canReact: boolean;
|
||||
@@ -94,6 +98,26 @@ export function ReactionPopupMenu({
|
||||
[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],
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.reactionPopupMenu}>
|
||||
<section className={styles.handRaiseSection}>
|
||||
@@ -114,15 +138,17 @@ export function ReactionPopupMenu({
|
||||
<section>
|
||||
{isSearching ? (
|
||||
<>
|
||||
<Form.Root
|
||||
className={styles.searchForm}
|
||||
onSubmit={(e) => e.preventDefault()}
|
||||
>
|
||||
<Form.Root className={styles.searchForm}>
|
||||
<Search
|
||||
required
|
||||
value={searchText}
|
||||
name="reactionSearch"
|
||||
placeholder="Search reactions…"
|
||||
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
|
||||
@@ -144,7 +170,7 @@ export function ReactionPopupMenu({
|
||||
kind="secondary"
|
||||
className={styles.reactionButton}
|
||||
disabled={!canReact}
|
||||
onClick={() => sendRelation(reaction)}
|
||||
onClick={() => sendReaction(reaction)}
|
||||
>
|
||||
{reaction.emoji}
|
||||
</CpdButton>
|
||||
@@ -287,7 +313,7 @@ export function ReactionToggleButton({
|
||||
<ReactionPopupMenu
|
||||
isHandRaised={isHandRaised}
|
||||
canReact={canReact}
|
||||
sendRelation={(reaction) => void sendRelation(reaction)}
|
||||
sendReaction={(reaction) => void sendRelation(reaction)}
|
||||
toggleRaisedHand={toggleRaisedHand}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -204,7 +204,7 @@ exports[`Can close search 1`] = `
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
aria-labelledby=":rba:"
|
||||
aria-labelledby=":rfg:"
|
||||
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
@@ -232,7 +232,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-label="Toggle hand raised"
|
||||
aria-labelledby=":rbg:"
|
||||
aria-labelledby=":rfm:"
|
||||
aria-pressed="false"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
@@ -253,7 +253,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rd2:"
|
||||
aria-labelledby=":rh8:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -268,7 +268,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rd7:"
|
||||
aria-labelledby=":rhd:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -283,7 +283,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rdc:"
|
||||
aria-labelledby=":rhi:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -298,7 +298,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rdh:"
|
||||
aria-labelledby=":rhn:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -313,7 +313,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rdm:"
|
||||
aria-labelledby=":rhs:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -328,7 +328,7 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rdr:"
|
||||
aria-labelledby=":ri1:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
@@ -343,7 +343,178 @@ exports[`Can close search 1`] = `
|
||||
>
|
||||
<button
|
||||
aria-label="Open reactions search"
|
||||
aria-labelledby=":re0:"
|
||||
aria-labelledby=":ri6:"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||
data-kind="tertiary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414l-3.244-3.244ZM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</li>
|
||||
</menu>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Can close search with the escape key 1`] = `
|
||||
<div>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
aria-labelledby=":rii:"
|
||||
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11 3a1 1 0 1 1 2 0v8.5a.5.5 0 0 0 1 0V4a1 1 0 1 1 2 0v10.2l3.284-2.597a1.081 1.081 0 0 1 1.47 1.577c-.613.673-1.214 1.367-1.818 2.064-1.267 1.463-2.541 2.934-3.944 4.235A6 6 0 0 1 5 15V7a1 1 0 0 1 2 0v5.5a.5.5 0 0 0 1 0V4a1 1 0 0 1 2 0v7.5a.5.5 0 0 0 1 0V3Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="reactionPopupMenu"
|
||||
>
|
||||
<section
|
||||
class="handRaiseSection"
|
||||
>
|
||||
<button
|
||||
aria-label="Toggle hand raised"
|
||||
aria-labelledby=":rio:"
|
||||
aria-pressed="false"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🖐️
|
||||
</button>
|
||||
</section>
|
||||
<div
|
||||
class="verticalSeperator"
|
||||
/>
|
||||
<section>
|
||||
<menu>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rka:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
👍
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rkf:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🎉
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rkk:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
👏
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rkp:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🐶
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rku:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🐱
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rl3:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
💡
|
||||
</button>
|
||||
</li>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-label="Open reactions search"
|
||||
aria-labelledby=":rl8:"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||
data-kind="tertiary"
|
||||
data-size="lg"
|
||||
@@ -784,6 +955,7 @@ exports[`Can search for and send emoji 1`] = `
|
||||
id=":ra4:"
|
||||
name="reactionSearch"
|
||||
placeholder="Search reactions…"
|
||||
required=""
|
||||
type="search"
|
||||
value="crickets"
|
||||
/>
|
||||
@@ -837,3 +1009,130 @@ exports[`Can search for and send emoji 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`Can search for and send emoji with the keyboard 1`] = `
|
||||
<div>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-expanded="true"
|
||||
aria-labelledby=":rba:"
|
||||
class="_button_i91xf_17 raisedButton _has-icon_i91xf_66 _icon-only_i91xf_59"
|
||||
data-kind="primary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
width="24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M11 3a1 1 0 1 1 2 0v8.5a.5.5 0 0 0 1 0V4a1 1 0 1 1 2 0v10.2l3.284-2.597a1.081 1.081 0 0 1 1.47 1.577c-.613.673-1.214 1.367-1.818 2.064-1.267 1.463-2.541 2.934-3.944 4.235A6 6 0 0 1 5 15V7a1 1 0 0 1 2 0v5.5a.5.5 0 0 0 1 0V4a1 1 0 0 1 2 0v7.5a.5.5 0 0 0 1 0V3Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
<div
|
||||
class="reactionPopupMenu"
|
||||
>
|
||||
<section
|
||||
class="handRaiseSection"
|
||||
>
|
||||
<button
|
||||
aria-label="Toggle hand raised"
|
||||
aria-labelledby=":rbg:"
|
||||
aria-pressed="false"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🖐️
|
||||
</button>
|
||||
</section>
|
||||
<div
|
||||
class="verticalSeperator"
|
||||
/>
|
||||
<section>
|
||||
<form
|
||||
class="_root_dgy0u_24 searchForm"
|
||||
>
|
||||
<label
|
||||
class="_label_dgy0u_67 _field_dgy0u_34 _search_qztja_17"
|
||||
for=":rd0:"
|
||||
>
|
||||
<svg
|
||||
class="_icon_qztja_46"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M15.05 16.463a7.5 7.5 0 1 1 1.414-1.414l3.243 3.244a1 1 0 0 1-1.414 1.414l-3.244-3.244ZM16 10.5a5.5 5.5 0 1 0-11 0 5.5 5.5 0 0 0 11 0Z"
|
||||
/>
|
||||
</svg>
|
||||
<input
|
||||
class="_input_qztja_61"
|
||||
id=":rd0:"
|
||||
name="reactionSearch"
|
||||
placeholder="Search reactions…"
|
||||
required=""
|
||||
type="search"
|
||||
value="crickets"
|
||||
/>
|
||||
</label>
|
||||
<button
|
||||
aria-label="close search"
|
||||
class="_button_i91xf_17 _has-icon_i91xf_66 _destructive_i91xf_116"
|
||||
data-kind="secondary"
|
||||
data-size="sm"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
fill="currentColor"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
width="20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M6.293 6.293a1 1 0 0 1 1.414 0L12 10.586l4.293-4.293a1 1 0 1 1 1.414 1.414L13.414 12l4.293 4.293a1 1 0 0 1-1.414 1.414L12 13.414l-4.293 4.293a1 1 0 0 1-1.414-1.414L10.586 12 6.293 7.707a1 1 0 0 1 0-1.414Z"
|
||||
/>
|
||||
</svg>
|
||||
</button>
|
||||
</form>
|
||||
<div
|
||||
class="_separator_144s5_17"
|
||||
data-kind="primary"
|
||||
data-orientation="horizontal"
|
||||
role="separator"
|
||||
/>
|
||||
<menu>
|
||||
<li
|
||||
class="reactionPopupMenuItem"
|
||||
>
|
||||
<button
|
||||
aria-disabled="false"
|
||||
aria-labelledby=":rdc:"
|
||||
class="_button_i91xf_17 reactionButton"
|
||||
data-kind="secondary"
|
||||
data-size="lg"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
>
|
||||
🦗
|
||||
</button>
|
||||
</li>
|
||||
</menu>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
Reference in New Issue
Block a user