From f8641be9e28416811f605c79b18cd1e331dffa22 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 12:32:14 +0100 Subject: [PATCH 01/10] Add useTopic hook --- src/hooks/room/useTopic.ts | 40 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/hooks/room/useTopic.ts diff --git a/src/hooks/room/useTopic.ts b/src/hooks/room/useTopic.ts new file mode 100644 index 00000000000..7245a64000a --- /dev/null +++ b/src/hooks/room/useTopic.ts @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import { useEffect, useState } from "react"; +import { EventType } from "matrix-js-sdk/src/@types/event"; +import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; + +import { useTypedEventEmitter } from "../useEventEmitter"; + +export const getTopic = (room: Room) => { + return room?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic; +}; + +export function useTopic(room: Room): string { + const [topic, setTopic] = useState(getTopic(room)); + useTypedEventEmitter(room.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => { + if (ev.getType() !== EventType.RoomTopic) return; + setTopic(getTopic(room)); + }); + useEffect(() => { + setTopic(getTopic(room)); + }, [room]); + + return topic; +} From 6617ea3631953044900d555ed25a902db2a3c359 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 12:32:24 +0100 Subject: [PATCH 02/10] Add useHover hook --- src/hooks/useHover.ts | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/hooks/useHover.ts diff --git a/src/hooks/useHover.ts b/src/hooks/useHover.ts new file mode 100644 index 00000000000..9f7c1012255 --- /dev/null +++ b/src/hooks/useHover.ts @@ -0,0 +1,42 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useEffect, useState } from "react"; + +export default function useHover(ref: React.MutableRefObject) { + const [hovered, setHoverState] = useState(false); + + const handleMouseOver = () => setHoverState(true); + const handleMouseOut = () => setHoverState(false); + + useEffect( + () => { + const node = ref.current; + if (node) { + node.addEventListener("mouseover", handleMouseOver); + node.addEventListener("mouseout", handleMouseOut); + + return () => { + node.removeEventListener("mouseover", handleMouseOver); + node.removeEventListener("mouseout", handleMouseOut); + }; + } + }, + [ref], + ); + + return hovered; +} From 5b047a678b8d226ef080a647648d9b84ea066b74 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 12:33:47 +0100 Subject: [PATCH 03/10] Make long room topic readable Fixes https://github.com/vector-im/element-web/issues/9623 Clicking the room topic now displays a modal showing the full room topic --- res/css/views/rooms/_RoomHeader.scss | 6 ++ src/components/structures/SpaceRoomView.tsx | 8 +- src/components/views/elements/RoomTopic.tsx | 96 ++++++++++++++----- src/components/views/rooms/RoomHeader.tsx | 9 +- .../views/rooms/RoomPreviewCard.tsx | 8 +- src/dispatcher/actions.ts | 5 + src/i18n/strings/en_EN.json | 2 + 7 files changed, 93 insertions(+), 41 deletions(-) diff --git a/res/css/views/rooms/_RoomHeader.scss b/res/css/views/rooms/_RoomHeader.scss index 85c139402be..119bbc90b83 100644 --- a/res/css/views/rooms/_RoomHeader.scss +++ b/res/css/views/rooms/_RoomHeader.scss @@ -140,6 +140,10 @@ limitations under the License. cursor: pointer; } +.mx_RoomTopic { + position: relative; +} + .mx_RoomHeader_topic { $lineHeight: $font-16px; $lines: 2; @@ -209,6 +213,7 @@ limitations under the License. .mx_RoomHeader_appsButton::before { mask-image: url('$(res)/img/element-icons/room/apps.svg'); } + .mx_RoomHeader_appsButton_highlight::before { background-color: $accent; } @@ -239,6 +244,7 @@ limitations under the License. padding: 0; margin: 0; } + .mx_RoomHeader { overflow: hidden; } diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 695fa7a749e..074f82072a5 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -254,13 +254,7 @@ const SpaceLanding = ({ space }: { space: Room }) => { { settingsButton } - - { (topic, ref) => ( -
- { topic } -
- ) } -
+ ; diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index 4120f6780e7..5eaeb92a2ca 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -1,5 +1,5 @@ /* -Copyright 2021 The Matrix.org Foundation C.I.C. +Copyright 2021 - 2022 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -14,35 +14,87 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useEffect, useState } from "react"; -import { EventType } from "matrix-js-sdk/src/@types/event"; +import React, { useCallback, useContext, useRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; -import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state"; -import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import classNames from "classnames"; +import { defer } from "lodash"; -import { useTypedEventEmitter } from "../../../hooks/useEventEmitter"; import { linkifyElement } from "../../../HtmlUtils"; +import { useTopic } from "../../../hooks/room/useTopic"; +import useHover from "../../../hooks/useHover"; +import Tooltip, { Alignment } from "./Tooltip"; +import { _t } from "../../../languageHandler"; +import dis from "../../../dispatcher/dispatcher"; +import { Action } from "../../../dispatcher/actions"; +import Modal from "../../../Modal"; +import InfoDialog from "../dialogs/InfoDialog"; +import { useDispatcher } from "../../../hooks/useDispatcher"; +import MatrixClientContext from "../../../contexts/MatrixClientContext"; +import AccessibleButton from "./AccessibleButton"; -interface IProps { +interface IProps extends React.HTMLProps { room?: Room; - children?(topic: string, ref: (element: HTMLElement) => void): JSX.Element; } -export const getTopic = room => room?.currentState?.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic; +export default function RoomTopic({ + room, + ...props +}: IProps) { + const client = useContext(MatrixClientContext); + const ref = useRef(); + const hovered = useHover(ref); -const RoomTopic = ({ room, children }: IProps): JSX.Element => { - const [topic, setTopic] = useState(getTopic(room)); - useTypedEventEmitter(room.currentState, RoomStateEvent.Events, (ev: MatrixEvent) => { - if (ev.getType() !== EventType.RoomTopic) return; - setTopic(getTopic(room)); + const topic = useTopic(room); + + const onClick = useCallback((e: React.MouseEvent) => { + props.onClick?.(e); + const target = e.target as HTMLElement; + if (target.tagName.toUpperCase() === "A") { + return; + } + + dis.fire(Action.ShowRoomTopic); + }, [props]); + + useDispatcher(dis, (payload) => { + if (payload.action === Action.ShowRoomTopic) { + const canSetTopic = room.currentState.maySendStateEvent('m.room.topic', client.getUserId()); + + const modal = Modal.createDialog(InfoDialog, { + title: room.name, + description:
+

{ topic }

+ { canSetTopic && { + modal.close(); + dis.dispatch({ action: "open_room_settings" }); + }}> + { _t("Edit topic") } + } +
, + hasCloseButton: true, + button: false, + }); + + defer(() => { + const topicNode = document.querySelector(".mx_jsTopicNode") as HTMLParagraphElement; + linkifyElement(topicNode); + }); + } }); - useEffect(() => { - setTopic(getTopic(room)); - }, [room]); - const ref = e => e && linkifyElement(e); - if (children) return children(topic, ref); - return { topic }; -}; + const className = classNames(props.className, "mx_RoomTopic"); -export default RoomTopic; + return
+ { topic } + { hovered && ( + + ) } +
; +} diff --git a/src/components/views/rooms/RoomHeader.tsx b/src/components/views/rooms/RoomHeader.tsx index 9983b6f39c3..ec206b0e369 100644 --- a/src/components/views/rooms/RoomHeader.tsx +++ b/src/components/views/rooms/RoomHeader.tsx @@ -186,11 +186,10 @@ export default class RoomHeader extends React.Component { ); - const topicElement = - { (topic, ref) =>
- { topic } -
} -
; + const topicElement = ; let roomAvatar; if (this.props.room) { diff --git a/src/components/views/rooms/RoomPreviewCard.tsx b/src/components/views/rooms/RoomPreviewCard.tsx index e197a3259c5..71b22765743 100644 --- a/src/components/views/rooms/RoomPreviewCard.tsx +++ b/src/components/views/rooms/RoomPreviewCard.tsx @@ -182,13 +182,7 @@ const RoomPreviewCard: FC = ({ room, onJoinButtonClicked, onRejectButton - - { (topic, ref) => - topic ?
- { topic } -
: null - } -
+ { room.getJoinRule() === "public" && } { notice ?
{ notice } diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 3fdbccb71b9..f2a84d514ca 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -312,4 +312,9 @@ export enum Action { * Opens a dialog to add an existing object to a space. Used with a OpenAddExistingToSpaceDialogPayload. */ OpenAddToExistingSpaceDialog = "open_add_to_existing_space_dialog", + + /** + * Show current room topic + */ + ShowRoomTopic = "show_room_topic" } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 14669a84aae..a8c22542488 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2383,6 +2383,8 @@ "%(count)s members including %(commaSeparatedMembers)s|one": "%(commaSeparatedMembers)s", "%(count)s people you know have already joined|other": "%(count)s people you know have already joined", "%(count)s people you know have already joined|one": "%(count)s person you know has already joined", + "Edit topic": "Edit topic", + "Click to read topic": "Click to read topic", "Server Options": "Server Options", "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.": "You can use the custom server options to sign into other Matrix servers by specifying a different homeserver URL. This allows you to use %(brand)s with an existing Matrix account on a different homeserver.", "Join millions for free on the largest public server": "Join millions for free on the largest public server", From 3fc8dcc1b86d45ccbda7346adfe97dc1a14bcc30 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 12:47:35 +0100 Subject: [PATCH 04/10] Add useTopic tests --- test/useTopic-test.tsx | 69 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 test/useTopic-test.tsx diff --git a/test/useTopic-test.tsx b/test/useTopic-test.tsx new file mode 100644 index 00000000000..2aac69a52a9 --- /dev/null +++ b/test/useTopic-test.tsx @@ -0,0 +1,69 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React from "react"; +import { Room } from "matrix-js-sdk/src/models/room"; +import { mount } from "enzyme"; + +import { act } from "react-dom/test-utils"; +import { useTopic } from "../src/hooks/room/useTopic"; +import { mkEvent, stubClient } from "./test-utils"; +import { MatrixClientPeg } from "../src/MatrixClientPeg"; + +describe("useTopic", () => { + it("should display the room topic", () => { + stubClient(); + const room = new Room("!TESTROOM", MatrixClientPeg.get(), "@alice:example.org"); + const topic = mkEvent({ + type: 'm.room.topic', + room: '!TESTROOM', + user: '@alice:example.org', + content: { + topic: 'Test topic', + }, + ts: 123, + event: true, + }); + + room.addLiveEvents([topic]); + + function RoomTopic() { + const topic = useTopic(room); + return

{ topic }

; + } + + const wrapper = mount(); + + expect(wrapper.text()).toBe("Test topic"); + + const updatedTopic = mkEvent({ + type: 'm.room.topic', + room: '!TESTROOM', + user: '@alice:example.org', + content: { + topic: 'New topic', + }, + ts: 666, + event: true, + }); + + act(() => { + room.addLiveEvents([updatedTopic]); + }); + + expect(wrapper.text()).toBe("New topic"); + }); +}); From cc6468c3efd174f035fe82c2df1f13aa2a92290c Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 12:51:55 +0100 Subject: [PATCH 05/10] Add linkify side-effect for the room topic --- src/components/views/elements/RoomTopic.tsx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index 5eaeb92a2ca..4cf5cd768f3 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { useCallback, useContext, useRef } from "react"; +import React, { useCallback, useContext, useEffect, useRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from "classnames"; import { defer } from "lodash"; @@ -84,6 +84,10 @@ export default function RoomTopic({ } }); + useEffect(() => { + linkifyElement(ref.current); + }, [topic]); + const className = classNames(props.className, "mx_RoomTopic"); return
Date: Fri, 6 May 2022 12:56:47 +0100 Subject: [PATCH 06/10] Lint fix on test file --- test/useTopic-test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/useTopic-test.tsx b/test/useTopic-test.tsx index 2aac69a52a9..75096b43e48 100644 --- a/test/useTopic-test.tsx +++ b/test/useTopic-test.tsx @@ -17,8 +17,8 @@ limitations under the License. import React from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import { mount } from "enzyme"; - import { act } from "react-dom/test-utils"; + import { useTopic } from "../src/hooks/room/useTopic"; import { mkEvent, stubClient } from "./test-utils"; import { MatrixClientPeg } from "../src/MatrixClientPeg"; From 664956b1f8c98a3eb094d1e888022010bb0bd33d Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 13:02:07 +0100 Subject: [PATCH 07/10] Fix getTopic import --- src/components/views/spaces/SpaceSettingsGeneralTab.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx index b572122da1b..8247ee25e93 100644 --- a/src/components/views/spaces/SpaceSettingsGeneralTab.tsx +++ b/src/components/views/spaces/SpaceSettingsGeneralTab.tsx @@ -25,8 +25,8 @@ import AccessibleButton from "../elements/AccessibleButton"; import SpaceBasicSettings from "./SpaceBasicSettings"; import { avatarUrlForRoom } from "../../../Avatar"; import { IDialogProps } from "../dialogs/IDialogProps"; -import { getTopic } from "../elements/RoomTopic"; import { leaveSpace } from "../../../utils/leave-behaviour"; +import { getTopic } from "../../../hooks/room/useTopic"; interface IProps extends IDialogProps { matrixClient: MatrixClient; From 66659bf6a87e0e400ba7ea9eb2c6ec7f1e593125 Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 17:00:30 +0100 Subject: [PATCH 08/10] PR fixes --- src/components/views/elements/RoomTopic.tsx | 3 ++- src/hooks/room/useTopic.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index 4cf5cd768f3..93f486e18a2 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -19,6 +19,7 @@ import { Room } from "matrix-js-sdk/src/models/room"; import classNames from "classnames"; import { defer } from "lodash"; +import { EventType } from "matrix-js-sdk/src/@types/event"; import { linkifyElement } from "../../../HtmlUtils"; import { useTopic } from "../../../hooks/room/useTopic"; import useHover from "../../../hooks/useHover"; @@ -58,7 +59,7 @@ export default function RoomTopic({ useDispatcher(dis, (payload) => { if (payload.action === Action.ShowRoomTopic) { - const canSetTopic = room.currentState.maySendStateEvent('m.room.topic', client.getUserId()); + const canSetTopic = room.currentState.maySendStateEvent(EventType.RoomTopic, client.getUserId()); const modal = Modal.createDialog(InfoDialog, { title: room.name, diff --git a/src/hooks/room/useTopic.ts b/src/hooks/room/useTopic.ts index 7245a64000a..b01065c37ca 100644 --- a/src/hooks/room/useTopic.ts +++ b/src/hooks/room/useTopic.ts @@ -1,5 +1,5 @@ /* -Copyright 2020 The Matrix.org Foundation C.I.C. +Copyright 2022 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. From 5c79da0c49ab3fc0001c76eb2134210111b1e45f Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 6 May 2022 17:03:33 +0100 Subject: [PATCH 09/10] lint fix --- src/components/views/elements/RoomTopic.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index 93f486e18a2..75ed4a3ad19 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -18,8 +18,8 @@ import React, { useCallback, useContext, useEffect, useRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from "classnames"; import { defer } from "lodash"; - import { EventType } from "matrix-js-sdk/src/@types/event"; + import { linkifyElement } from "../../../HtmlUtils"; import { useTopic } from "../../../hooks/room/useTopic"; import useHover from "../../../hooks/useHover"; From a76c1c3aa7bbb34f47d141b2937c5c4b20014e6e Mon Sep 17 00:00:00 2001 From: Germain Souquet Date: Fri, 13 May 2022 09:44:41 +0200 Subject: [PATCH 10/10] Add linkify component --- src/components/views/elements/Linkify.tsx | 39 +++++++++++ src/components/views/elements/RoomTopic.tsx | 9 +-- .../views/elements/Linkify-test.tsx | 64 +++++++++++++++++++ 3 files changed, 105 insertions(+), 7 deletions(-) create mode 100644 src/components/views/elements/Linkify.tsx create mode 100644 test/components/views/elements/Linkify-test.tsx diff --git a/src/components/views/elements/Linkify.tsx b/src/components/views/elements/Linkify.tsx new file mode 100644 index 00000000000..6263df1a121 --- /dev/null +++ b/src/components/views/elements/Linkify.tsx @@ -0,0 +1,39 @@ +/* +Copyright 2022 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useEffect, useRef } from "react"; +import linkifyElement from "linkify-element"; + +interface Props { + as?: string; + children: React.ReactNode; +} + +export function Linkify({ + as = "div", + children, +}: Props): JSX.Element { + const ref = useRef(); + + useEffect(() => { + linkifyElement(ref.current); + }, [children]); + + return React.createElement(as, { + children, + ref, + }); +} diff --git a/src/components/views/elements/RoomTopic.tsx b/src/components/views/elements/RoomTopic.tsx index 75ed4a3ad19..a50d3b33080 100644 --- a/src/components/views/elements/RoomTopic.tsx +++ b/src/components/views/elements/RoomTopic.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { useCallback, useContext, useEffect, useRef } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from "classnames"; -import { defer } from "lodash"; import { EventType } from "matrix-js-sdk/src/@types/event"; import { linkifyElement } from "../../../HtmlUtils"; @@ -32,6 +31,7 @@ import InfoDialog from "../dialogs/InfoDialog"; import { useDispatcher } from "../../../hooks/useDispatcher"; import MatrixClientContext from "../../../contexts/MatrixClientContext"; import AccessibleButton from "./AccessibleButton"; +import { Linkify } from "./Linkify"; interface IProps extends React.HTMLProps { room?: Room; @@ -64,7 +64,7 @@ export default function RoomTopic({ const modal = Modal.createDialog(InfoDialog, { title: room.name, description:
-

{ topic }

+ { topic } { canSetTopic && { @@ -77,11 +77,6 @@ export default function RoomTopic({ hasCloseButton: true, button: false, }); - - defer(() => { - const topicNode = document.querySelector(".mx_jsTopicNode") as HTMLParagraphElement; - linkifyElement(topicNode); - }); } }); diff --git a/test/components/views/elements/Linkify-test.tsx b/test/components/views/elements/Linkify-test.tsx new file mode 100644 index 00000000000..7224c543736 --- /dev/null +++ b/test/components/views/elements/Linkify-test.tsx @@ -0,0 +1,64 @@ +/* +Copyright 2021 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +import React, { useState } from "react"; +import { mount } from "enzyme"; + +import { Linkify } from "../../../../src/components/views/elements/Linkify"; + +describe("Linkify", () => { + it("linkifies the context", () => { + const wrapper = mount( + https://perdu.com + ); + expect(wrapper.html()).toBe(''); + }); + + it("changes the root tag name", () => { + const TAG_NAME = "p"; + + const wrapper = mount( + Hello world! + ); + + expect(wrapper.find("p")).toHaveLength(1); + }); + + it("relinkifies on update", () => { + function DummyTest() { + const [n, setN] = useState(0); + function onClick() { + setN(n + 1); + } + + // upon clicking the element, change the content, and expect + // linkify to update + return
+ + { n % 2 === 0 + ? "https://perdu.com" + : "https://matrix.org" } + +
; + } + + const wrapper = mount(); + + expect(wrapper.html()).toBe(''); + + wrapper.find('div').at(0).simulate('click'); + + expect(wrapper.html()).toBe(''); + }); +});