From c647c8ee3dba202f0068670a0bb2bcc2264278bc Mon Sep 17 00:00:00 2001 From: Zack Date: Wed, 4 Feb 2026 14:25:36 +0100 Subject: [PATCH] Refactor Timeline Seperator (#31937) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor TimelineSeparator to shared-components package • New TimelineSeparator component in packages/shared-components/ • Updated MessagePanel.tsx to import from shared-components * Fix copyright text * Timeline Unit Tests + Timeline Snapshot Tests * Imported correct timeline seperator * Update snapshots because of css update * Apply suggestion from @florianduros Co-authored-by: Florian Duros * Created className prop * Removal of element x unused css * Update snapshot because of Flex * Update snapshots because of Flex * Update css to correct values and compund name * Added letter spacing to timelineseperator * rremoval of letter spacing * added align center to flex to apply correct css changes * Update snapshots to reflect new css changes * Update snapshots to reflect css changes * Added letter-spacing to timeline seperator * Update snapshots after css update * update snapshots --------- Co-authored-by: Florian Duros --- .../default-auto.png | Bin 0 -> 18955 bytes .../with-date-event-auto.png | Bin 0 -> 18626 bytes .../with-html-child-auto.png | Bin 0 -> 17932 bytes .../with-late-event-auto.png | Bin 0 -> 18721 bytes .../without-children-auto.png | Bin 0 -> 3629 bytes packages/shared-components/src/index.ts | 1 + .../TimelineSeparator.module.css | 21 ++++ .../TimelineSeparator.stories.tsx | 54 ++++++++++ .../TimelineSeparator.test.tsx | 48 +++++++++ .../TimelineSeparator/TimelineSeparator.tsx | 54 ++++++++++ .../TimelineSeparator.test.tsx.snap | 100 ++++++++++++++++++ .../message-body/TimelineSeparator/index.ts | 8 ++ res/css/_components.pcss | 1 - .../views/messages/_TimelineSeparator.pcss | 23 ---- src/components/structures/MessagePanel.tsx | 16 ++- .../structures/grouper/CreationGrouper.tsx | 3 +- .../structures/grouper/MainGrouper.tsx | 3 +- .../views/messages/DateSeparator.tsx | 8 +- .../views/messages/TimelineSeparator.tsx | 39 ------- .../__snapshots__/MessagePanel-test.tsx.snap | 3 +- .../MessageEditHistoryDialog-test.tsx.snap | 6 +- .../__snapshots__/DateSeparator-test.tsx.snap | 9 +- .../__snapshots__/HTMLExport-test.ts.snap | 2 +- 23 files changed, 321 insertions(+), 78 deletions(-) create mode 100644 packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/default-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/with-date-event-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/with-html-child-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/with-late-event-auto.png create mode 100644 packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/without-children-auto.png create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.module.css create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.stories.tsx create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.test.tsx create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.tsx create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/__snapshots__/TimelineSeparator.test.tsx.snap create mode 100644 packages/shared-components/src/message-body/TimelineSeparator/index.ts delete mode 100644 res/css/views/messages/_TimelineSeparator.pcss delete mode 100644 src/components/views/messages/TimelineSeparator.tsx diff --git a/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/default-auto.png b/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/default-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..9830d14901a261ff7cff285aae433d9a2ee41011 GIT binary patch literal 18955 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 WHh%1TZbzE literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/with-late-event-auto.png b/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/with-late-event-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..9cb04d975778234f0d3720e0e04335c231a4e1fd GIT binary patch literal 18721 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 )X($95joXBx#|ntf043W;;zH< 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 WK4*2&5Jy;HEL&=`Bz2MdKmP;&ppZ2H literal 0 HcmV?d00001 diff --git a/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/without-children-auto.png b/packages/shared-components/__vis__/linux/__baselines__/message-body/TimelineSeparator/TimelineSeparator.stories.tsx/without-children-auto.png new file mode 100644 index 0000000000000000000000000000000000000000..2e132bb28b03d378b09f73896707a47acc128999 GIT binary patch literal 3629 zcmeAS@N?(olHy`uVBq!ia0y~yU_QXWz;uCw2`F+wwC^!c{E?@NV@SoEH+MF29(E96 zxhNd-f2kCYpAPGCv42nAhZ-K-^n1=`28M>2dx3-@BQFC(V*?vQgM$MzgM-2XMh1l& z^WWz)GB6ll|6eD@z+h1Pvk@q5DV@Q hr { + flex: 1 1 0; + height: 0; + border: none; + border-bottom: 1px solid var(--cpd-color-gray-400); +} diff --git a/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.stories.tsx b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.stories.tsx new file mode 100644 index 0000000000..cf067f4ecd --- /dev/null +++ b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.stories.tsx @@ -0,0 +1,54 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * 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 from "react"; + +import type { Meta, StoryFn } from "@storybook/react-vite"; +import TimelineSeparator from "./TimelineSeparator"; +import styles from "./TimelineSeparator.module.css"; + +export default { + title: "MessageBody/TimelineSeparator", + component: TimelineSeparator, + tags: ["autodocs"], + args: { + label: "Label Separator", + children: "Timeline Separator", + }, +} as Meta; + +const Template: StoryFn = (args) => ; + +export const Default = Template.bind({}); + +export const WithHtmlChild = Template.bind({}); +WithHtmlChild.args = { + label: "Custom Label", + children: ( + + ), +}; + +export const WithDateEvent = Template.bind({}); +WithDateEvent.args = { + label: "Date Event Separator", + children: "Wednesday", +}; + +export const WithLateEvent = Template.bind({}); +WithLateEvent.args = { + label: "Late Event Separator", + children: "Fri, Jan 9, 2026", +}; + +export const WithoutChildren = Template.bind({}); +WithoutChildren.args = { + children: undefined, + label: "Separator without children", +}; diff --git a/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.test.tsx b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.test.tsx new file mode 100644 index 0000000000..859142b49c --- /dev/null +++ b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.test.tsx @@ -0,0 +1,48 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * 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 { render } from "@test-utils"; +import { composeStories } from "@storybook/react-vite"; +import React from "react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import * as stories from "./TimelineSeparator.stories.tsx"; + +const { Default, WithHtmlChild, WithoutChildren, WithDateEvent, WithLateEvent } = composeStories(stories); + +describe("TimelineSeparator", () => { + afterEach(() => { + vi.clearAllMocks(); + }); + + describe("Snapshot tests", () => { + it("renders the timeline separator in default state", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders the timeline separator with HTML child", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders the timeline separator with date event", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders the timeline separator with late event", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + + it("renders the timeline separator without children", () => { + const { container } = render(); + expect(container).toMatchSnapshot(); + }); + }); +}); diff --git a/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.tsx b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.tsx new file mode 100644 index 0000000000..cd3af1c1a7 --- /dev/null +++ b/packages/shared-components/src/message-body/TimelineSeparator/TimelineSeparator.tsx @@ -0,0 +1,54 @@ +/* +Copyright 2026 Element Creations Ltd. + +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, { type PropsWithChildren } from "react"; +import classNames from "classnames"; + +import styles from "./TimelineSeparator.module.css"; +import { Flex } from "../.."; + +/** + * Timeline separator props + */ +export interface TimelineSeparatorProps { + /** + * Accessible label for the separator (for example: "Today", "Yesterday", or a date). + */ + label: string; + /** + * The CSS class name. + */ + className?: string; + /** + * Optional children to render inside the timeline separator + */ + children?: PropsWithChildren["children"]; +} + +/** + * Generic timeline separator component to render within a MessagePanel + * + * @param label the accessible label string describing the separator + * @param children the children to draw within the timeline separator + */ +const TimelineSeparator: React.FC = ({ label, className, children }) => { + // ARIA treats
s as separators, here we abuse them slightly so manually treat this entire thing as one + return ( + +
+ {children} +
+
+ ); +}; + +export default TimelineSeparator; diff --git a/packages/shared-components/src/message-body/TimelineSeparator/__snapshots__/TimelineSeparator.test.tsx.snap b/packages/shared-components/src/message-body/TimelineSeparator/__snapshots__/TimelineSeparator.test.tsx.snap new file mode 100644 index 0000000000..e45501e14d --- /dev/null +++ b/packages/shared-components/src/message-body/TimelineSeparator/__snapshots__/TimelineSeparator.test.tsx.snap @@ -0,0 +1,100 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`TimelineSeparator > Snapshot tests > renders the timeline separator in default state 1`] = ` +
+ +
+`; + +exports[`TimelineSeparator > Snapshot tests > renders the timeline separator with HTML child 1`] = ` +
+ +
+`; + +exports[`TimelineSeparator > Snapshot tests > renders the timeline separator with date event 1`] = ` +
+ +
+`; + +exports[`TimelineSeparator > Snapshot tests > renders the timeline separator with late event 1`] = ` +
+ +
+`; + +exports[`TimelineSeparator > Snapshot tests > renders the timeline separator without children 1`] = ` +
+ +
+`; diff --git a/packages/shared-components/src/message-body/TimelineSeparator/index.ts b/packages/shared-components/src/message-body/TimelineSeparator/index.ts new file mode 100644 index 0000000000..c5812abb07 --- /dev/null +++ b/packages/shared-components/src/message-body/TimelineSeparator/index.ts @@ -0,0 +1,8 @@ +/* + * Copyright 2026 Element Creations Ltd. + * + * 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. + */ + +export { default as TimelineSeparator, type TimelineSeparatorProps } from "./TimelineSeparator"; diff --git a/res/css/_components.pcss b/res/css/_components.pcss index a47fc0ac82..28458c899f 100644 --- a/res/css/_components.pcss +++ b/res/css/_components.pcss @@ -246,7 +246,6 @@ @import "./views/messages/_RedactedBody.pcss"; @import "./views/messages/_RoomAvatarEvent.pcss"; @import "./views/messages/_TextualEvent.pcss"; -@import "./views/messages/_TimelineSeparator.pcss"; @import "./views/messages/_UnknownBody.pcss"; @import "./views/messages/_ViewSourceEvent.pcss"; @import "./views/messages/_common_CryptoEvent.pcss"; diff --git a/res/css/views/messages/_TimelineSeparator.pcss b/res/css/views/messages/_TimelineSeparator.pcss deleted file mode 100644 index aab77d4e03..0000000000 --- a/res/css/views/messages/_TimelineSeparator.pcss +++ /dev/null @@ -1,23 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2017 Vector Creations Ltd - -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. -*/ - -.mx_TimelineSeparator { - clear: both; - margin: 4px 0; - display: flex; - align-items: center; - font: var(--cpd-font-body-md-regular); - color: var(--cpd-color-text-primary); -} - -.mx_TimelineSeparator > hr { - flex: 1 1 0; - height: 0; - border: none; - border-bottom: 1px solid var(--cpd-color-gray-400); -} diff --git a/src/components/structures/MessagePanel.tsx b/src/components/structures/MessagePanel.tsx index 30f9b474a6..40b69130a7 100644 --- a/src/components/structures/MessagePanel.tsx +++ b/src/components/structures/MessagePanel.tsx @@ -18,6 +18,7 @@ import { } from "matrix-js-sdk/src/matrix"; import { logger } from "matrix-js-sdk/src/logger"; import { isSupportedReceiptType } from "matrix-js-sdk/src/utils"; +import { TimelineSeparator } from "@element-hq/web-shared-components"; import shouldHideEvent from "../../shouldHideEvent"; import { formatDate, wantsDateSeparator } from "../../DateUtils"; @@ -37,7 +38,6 @@ import type LegacyCallEventGrouper from "./LegacyCallEventGrouper"; import WhoIsTypingTile from "../views/rooms/WhoIsTypingTile"; import ScrollPanel, { type IScrollState } from "./ScrollPanel"; import DateSeparator from "../views/messages/DateSeparator"; -import TimelineSeparator, { SeparatorKind } from "../views/messages/TimelineSeparator"; import ErrorBoundary from "../views/elements/ErrorBoundary"; import Spinner from "../views/elements/Spinner"; import { type RoomPermalinkCreator } from "../../utils/permalinks/Permalinks"; @@ -57,6 +57,18 @@ import { getLateEventInfo } from "./grouper/LateEventGrouper"; const CONTINUATION_MAX_INTERVAL = 5 * 60 * 1000; // 5 minutes const continuedTypes = [EventType.Sticker, EventType.RoomMessage]; +/** + * Indicates which separator (if any) should be rendered between timeline events. + */ +export const enum SeparatorKind { + /** No separator should be shown between the two events. */ + None, + /** Insert a date separator (oriented by event date boundaries). */ + Date, + /** Insert a late-event separator when events belong to different late groups. */ + LateEvent, +} + // check if there is a previous event and it has the same sender as this event // and the types are the same/is in continuedTypes and the time between them is <= CONTINUATION_MAX_INTERVAL export function shouldFormContinuation( @@ -756,7 +768,7 @@ export default class MessagePanel extends React.Component { }); ret.push(
  • - + {text}
  • , diff --git a/src/components/structures/grouper/CreationGrouper.tsx b/src/components/structures/grouper/CreationGrouper.tsx index 009f5bdc26..80c9bfedcd 100644 --- a/src/components/structures/grouper/CreationGrouper.tsx +++ b/src/components/structures/grouper/CreationGrouper.tsx @@ -11,14 +11,13 @@ import { EventType, M_BEACON_INFO, type MatrixEvent } from "matrix-js-sdk/src/ma import { KnownMembership } from "matrix-js-sdk/src/types"; import { BaseGrouper } from "./BaseGrouper"; -import { type WrappedEvent } from "../MessagePanel"; +import { SeparatorKind, type WrappedEvent } from "../MessagePanel"; import type MessagePanel from "../MessagePanel"; import DMRoomMap from "../../../utils/DMRoomMap"; import { _t } from "../../../languageHandler"; import DateSeparator from "../../views/messages/DateSeparator"; import NewRoomIntro from "../../views/rooms/NewRoomIntro"; import GenericEventListSummary from "../../views/elements/GenericEventListSummary"; -import { SeparatorKind } from "../../views/messages/TimelineSeparator"; // Wrap initial room creation events into a GenericEventListSummary // Grouping only events sent by the same user that sent the `m.room.create` and only until diff --git a/src/components/structures/grouper/MainGrouper.tsx b/src/components/structures/grouper/MainGrouper.tsx index e686f1aa81..6766f0e5b7 100644 --- a/src/components/structures/grouper/MainGrouper.tsx +++ b/src/components/structures/grouper/MainGrouper.tsx @@ -10,14 +10,13 @@ import React, { type ReactNode } from "react"; import { EventType, type MatrixEvent } from "matrix-js-sdk/src/matrix"; import type MessagePanel from "../MessagePanel"; -import type { WrappedEvent } from "../MessagePanel"; +import { SeparatorKind, type WrappedEvent } from "../MessagePanel"; import { BaseGrouper } from "./BaseGrouper"; import { hasText } from "../../../TextForEvent"; import { MatrixClientPeg } from "../../../MatrixClientPeg"; import DateSeparator from "../../views/messages/DateSeparator"; import HistoryTile from "../../views/rooms/HistoryTile"; import EventListSummary from "../../views/elements/EventListSummary"; -import { SeparatorKind } from "../../views/messages/TimelineSeparator"; const groupedStateEvents = [ EventType.RoomMember, diff --git a/src/components/views/messages/DateSeparator.tsx b/src/components/views/messages/DateSeparator.tsx index 7d49042533..061cc76204 100644 --- a/src/components/views/messages/DateSeparator.tsx +++ b/src/components/views/messages/DateSeparator.tsx @@ -12,6 +12,7 @@ import { Direction, ConnectionError, MatrixError, HTTPError } from "matrix-js-sd import { logger } from "matrix-js-sdk/src/logger"; import { capitalize } from "lodash"; import { ChevronDownIcon } from "@vector-im/compound-design-tokens/assets/web/icons"; +import { TimelineSeparator } from "@element-hq/web-shared-components"; import { _t, getUserLanguage } from "../../../languageHandler"; import { formatFullDateNoDay, formatFullDateNoTime, getDaysArray } from "../../../DateUtils"; @@ -32,7 +33,6 @@ import IconizedContextMenu, { } from "../context_menus/IconizedContextMenu"; import JumpToDatePicker from "./JumpToDatePicker"; import { type ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload"; -import TimelineSeparator from "./TimelineSeparator"; import RoomContext from "../../../contexts/RoomContext"; interface IProps { @@ -335,6 +335,10 @@ export default class DateSeparator extends React.Component { ); } - return {dateHeaderContent}; + return ( + + {dateHeaderContent} + + ); } } diff --git a/src/components/views/messages/TimelineSeparator.tsx b/src/components/views/messages/TimelineSeparator.tsx deleted file mode 100644 index 4735c8e00c..0000000000 --- a/src/components/views/messages/TimelineSeparator.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* -Copyright 2024 New Vector Ltd. -Copyright 2023 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, { type ReactNode } from "react"; - -interface Props { - label: string; - children?: ReactNode; -} - -export const enum SeparatorKind { - None, - Date, - LateEvent, -} - -/** - * Generic timeline separator component to render within a MessagePanel - * - * @param label the accessible label string describing the separator - * @param children the children to draw within the timeline separator - */ -const TimelineSeparator: React.FC = ({ label, children }) => { - // ARIA treats
    s as separators, here we abuse them slightly so manually treat this entire thing as one - return ( -
    -
    - {children} -
    -
    - ); -}; - -export default TimelineSeparator; diff --git a/test/unit-tests/components/structures/__snapshots__/MessagePanel-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/MessagePanel-test.tsx.snap index 716b0e7257..f31612ae13 100644 --- a/test/unit-tests/components/structures/__snapshots__/MessagePanel-test.tsx.snap +++ b/test/unit-tests/components/structures/__snapshots__/MessagePanel-test.tsx.snap @@ -39,8 +39,9 @@ exports[`MessagePanel should handle lots of membership events quickly 1`] = ` >