diff --git a/apps/web/src/components/views/rooms/MessageComposer.tsx b/apps/web/src/components/views/rooms/MessageComposer.tsx index 06c843f190..f7509b0dea 100644 --- a/apps/web/src/components/views/rooms/MessageComposer.tsx +++ b/apps/web/src/components/views/rooms/MessageComposer.tsx @@ -54,6 +54,8 @@ import { type MatrixClientProps, withMatrixClientHOC } from "../../../contexts/M import { UIFeature } from "../../../settings/UIFeature"; import { formatTimeLeft } from "../../../DateUtils"; import RoomReplacedSvg from "../../../../res/img/room_replaced.svg"; +import { Type } from "../../../editor/parts"; +import { MessageComposorUrlPreview } from "./MessageComposorUrlPreview"; // The prefix used when persisting editor drafts to localstorage. export const WYSIWYG_EDITOR_STATE_STORAGE_PREFIX = "mx_wysiwyg_state_"; @@ -418,7 +420,13 @@ export class MessageComposer extends React.Component { }; private onChange = (model: EditorModel): void => { + model.serializeParts(); this.setState({ + composerContent: model + .serializeParts() + .filter((p) => p.type === Type.Plain) + .map((p) => p.text) + .join(" "), isComposerEmpty: model.isEmpty, }); }; @@ -680,6 +688,7 @@ export class MessageComposer extends React.Component { replyToEvent={this.props.replyToEvent} permalinkCreator={this.props.permalinkCreator} /> +
{leftIcon} {composer} diff --git a/apps/web/src/components/views/rooms/MessageComposorUrlPreview.tsx b/apps/web/src/components/views/rooms/MessageComposorUrlPreview.tsx new file mode 100644 index 0000000000..c7b080a2ad --- /dev/null +++ b/apps/web/src/components/views/rooms/MessageComposorUrlPreview.tsx @@ -0,0 +1,23 @@ +/* +Copyright 2024 New Vector Ltd. +Copyright 2015-2022 The Matrix.org Foundation C.I.C. + +SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial +Please see LICENSE files in the repository root for full details. +*/ + +import React, { useCallback, useMemo, useRef, type ReactNode } from "react"; +import { useDebouncedCallback } from "../../../hooks/spotlight/useDebouncedCallback"; +import { debounce } from "lodash"; + +export function MessageComposorUrlPreview({ content }: { content: string }): ReactNode | null { + const debounceFn = useRef(debounce((c: string) => c.split(" ").filter((word) => URL.canParse(word.trim())), 1500)); + + const determineLinks = useMemo(() => debounceFn.current(content), [content]); + + return ( +
+ {determineLinks} +
+ ); +}