Shared Components Restructure, Cherry Picked | Room Timeline (#32916)

* refactor(shared-components): move room timeline tree

* refactor(web): move room timeline viewmodels

* Prettier FIx

* fix(refactor): align newer imports with room timeline paths

* test(shared-components): add room timeline visual baselines

* test(shared-components): drop stale timeline baseline paths
This commit is contained in:
Zack
2026-03-30 15:15:21 +00:00
committed by GitHub
parent 7c60752b04
commit dda9ec061b
192 changed files with 157 additions and 144 deletions
+14 -14
View File
@@ -6,34 +6,35 @@
*/
// Components
export * from "./audio/AudioPlayerView";
export * from "./audio/Clock";
export * from "./audio/PlayPauseButton";
export * from "./audio/SeekBar";
export * from "./core/avatar/AvatarWithDetails";
export * from "./composer/Banner";
export * from "./crypto/SasEmoji";
export * from "./event-tiles/EncryptionEventView";
export * from "./event-tiles/EventTileBubble";
export * from "./event-tiles/TextualEventView";
export * from "./event-tiles/UrlPreviewGroupView";
export * from "./message-body/EventContentBody";
export * from "./message-body/MediaBody";
export * from "./message-body/MessageTimestampView";
export * from "./message-body/DecryptionFailureBodyView";
export * from "./message-body/RedactedBodyView";
export * from "./message-body/FileBodyView";
export * from "./message-body/PinnedMessageBadge";
export * from "./message-body/ReactionsRowButtonTooltip";
export * from "./message-body/ReactionsRowButton";
export * from "./message-body/ReactionsRow";
export * from "./message-body/TimelineSeparator/";
export * from "./core/pill-input/Pill";
export * from "./core/pill-input/PillInput";
export * from "./room/RoomStatusBar";
export * from "./room/WidgetPip";
export * from "./profile/DisambiguatedProfile";
export * from "./room/HistoryVisibilityBadge";
export * from "./room/timeline/DateSeparatorView";
export * from "./room/timeline/TimelineSeparator";
export * from "./room/timeline/event-tile/EventTileView/DisambiguatedProfile";
export * from "./room/timeline/event-tile/EventTileView/EncryptionEventView";
export * from "./room/timeline/event-tile/EventTileView/EventTileBubble";
export * from "./room/timeline/event-tile/EventTileView/PinnedMessageBadge";
export * from "./room/timeline/event-tile/EventTileView/TextualEventView";
export * from "./room/timeline/event-tile/body/AudioPlayerView";
export * from "./room/timeline/event-tile/body/DecryptionFailureBodyView";
export * from "./room/timeline/event-tile/body/MediaBody";
export * from "./room/timeline/event-tile/reactions/ReactionsRow";
export * from "./room/timeline/event-tile/reactions/ReactionsRowButton";
export * from "./room/timeline/event-tile/reactions/ReactionsRowButtonTooltip";
export * from "./room/timeline/event-tile/timestamp/MessageTimestampView";
export * from "./core/rich-list/RichItem";
export * from "./core/rich-list/RichList";
export * from "./room-list/RoomListHeaderView";
@@ -44,7 +45,6 @@ export * from "./room-list/RoomListItemView";
export * from "./room-list/RoomListItemAccessibilityWrapper";
export * from "./room-list/RoomListPrimaryFilters";
export * from "./room-list/VirtualizedRoomListView";
export * from "./timeline/DateSeparatorView/";
export * from "./core/utils/Box";
export * from "./core/utils/Flex";
export * from "./core/utils/LinkedText";
@@ -19,7 +19,7 @@ import styles from "./FileBodyView.module.css";
import { type ViewModel } from "../../core/viewmodel/ViewModel";
import { useViewModel } from "../../core/viewmodel/useViewModel";
import { useI18n } from "../../core/i18n/i18nContext";
import { MediaBody } from "../MediaBody";
import { MediaBody } from "../../room/timeline/event-tile/body/MediaBody";
/**
* Which visual state to render for the component.
@@ -9,8 +9,8 @@ import React from "react";
import { Tooltip } from "@vector-im/compound-web";
import ChevronDownIcon from "@vector-im/compound-design-tokens/assets/web/icons/chevron-down";
import { Flex } from "../../core/utils/Flex";
import { useI18n } from "../../core/i18n/i18nContext";
import { Flex } from "../../../core/utils/Flex";
import { useI18n } from "../../../core/i18n/i18nContext";
/** Props for DateSeparatorButton. */
export interface DateSeparatorButtonProps {
@@ -9,8 +9,8 @@ import React, { type JSX, type PropsWithChildren, useRef } from "react";
import { Menu, MenuItem, Separator } from "@vector-im/compound-web";
import { capitalize } from "lodash";
import { useI18n } from "../../core/i18n/i18nContext";
import { humanizeRelativeTime } from "../../core/utils/humanize";
import { useI18n } from "../../../core/i18n/i18nContext";
import { humanizeRelativeTime } from "../../../core/utils/humanize";
import { type DateSeparatorViewModel } from "./DateSeparatorView";
import { DateSeparatorDatePickerView } from "./DateSeparatorDatePickerView";
import styles from "./DateSeparatorContextMenuView.module.css";
@@ -8,9 +8,9 @@
import React, { type JSX, useId, useRef, useState } from "react";
import { Root, Submit, Field, TextControl, MenuItem } from "@vector-im/compound-web";
import { formatDateForInput } from "../../core/utils/DateUtils";
import { useI18n } from "../../core/i18n/i18nContext";
import { useViewModel } from "../../core/viewmodel";
import { formatDateForInput } from "../../../core/utils/DateUtils";
import { useI18n } from "../../../core/i18n/i18nContext";
import { useViewModel } from "../../../core/viewmodel";
import { type DateSeparatorViewModel } from "./DateSeparatorView";
import styles from "./DateSeparatorDatePickerView.module.css";
@@ -10,8 +10,8 @@ import { expect, userEvent, within } from "storybook/test";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { DateSeparatorView, type DateSeparatorViewSnapshot, type DateSeparatorViewActions } from "./DateSeparatorView";
import { useMockedViewModel } from "../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../../.storybook/withViewDocs";
type DateSeparatorProps = DateSeparatorViewSnapshot & DateSeparatorViewActions;
@@ -12,7 +12,7 @@ import { describe, it, expect } from "vitest";
import { waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { BaseViewModel } from "../../core/viewmodel/BaseViewModel";
import { BaseViewModel } from "../../../core/viewmodel/BaseViewModel";
import { DateSeparatorView, type DateSeparatorViewModel, type DateSeparatorViewSnapshot } from "./DateSeparatorView";
import * as stories from "./DateSeparatorView.stories";
@@ -8,11 +8,11 @@
import classNames from "classnames";
import React, { type JSX, useState } from "react";
import { type ViewModel } from "../../core/viewmodel/ViewModel";
import { useViewModel } from "../../core/viewmodel/useViewModel";
import { type ViewModel } from "../../../core/viewmodel/ViewModel";
import { useViewModel } from "../../../core/viewmodel/useViewModel";
import styles from "./DateSeparatorView.module.css";
import { Flex } from "../../core/utils/Flex";
import { TimelineSeparator } from "../../message-body/TimelineSeparator";
import { Flex } from "../../../core/utils/Flex";
import { TimelineSeparator } from "../TimelineSeparator";
import { DateSeparatorContextMenuView } from "./DateSeparatorContextMenuView";
import { DateSeparatorButton } from "./DateSeparatorButton";
@@ -9,7 +9,7 @@ import React, { type PropsWithChildren } from "react";
import classNames from "classnames";
import styles from "./TimelineSeparator.module.css";
import { Flex } from "../..";
import { Flex } from "../../../core/utils/Flex";
/**
* Timeline separator props
@@ -14,8 +14,8 @@ import {
type DisambiguatedProfileViewSnapshot,
type DisambiguatedProfileViewActions,
} from "./DisambiguatedProfileView";
import { useMockedViewModel } from "../../core/viewmodel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
type DisambiguatedProfileProps = DisambiguatedProfileViewSnapshot & DisambiguatedProfileViewActions;
@@ -18,7 +18,7 @@ import {
type DisambiguatedProfileViewActions,
type DisambiguatedProfileViewSnapshot,
} from "./DisambiguatedProfileView";
import { MockViewModel } from "../../core/viewmodel/MockViewModel";
import { MockViewModel } from "../../../../../core/viewmodel/MockViewModel";
const { Default, WithMxid, WithColorClass, Emphasized, WithTooltip, FullExample } = composeStories(stories);
@@ -8,7 +8,7 @@
import React, { type JSX, type KeyboardEventHandler, type MouseEventHandler } from "react";
import classNames from "classnames";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
import styles from "./DisambiguatedProfile.module.css";
/**
@@ -9,8 +9,8 @@ import React, { type JSX } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { EncryptionEventView, EncryptionEventState, type EncryptionEventViewSnapshot } from "./EncryptionEventView";
import { useMockedViewModel } from "../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
type EncryptionEventProps = EncryptionEventViewSnapshot;
@@ -12,7 +12,7 @@ import React from "react";
import { EncryptionEventState, EncryptionEventView } from "./EncryptionEventView";
import * as stories from "./EncryptionEventView.stories";
import { MockViewModel } from "../../core/viewmodel";
import { MockViewModel } from "../../../../../core/viewmodel";
const {
Default,
@@ -9,9 +9,9 @@ import React, { type JSX } from "react";
import { LockSolidIcon, ErrorSolidIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import classNames from "classnames";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
import styles from "./EncryptionEventView.module.css";
import { useI18n } from "../../core/i18n/i18nContext";
import { useI18n } from "../../../../../core/i18n/i18nContext";
import { EventTileBubble } from "../EventTileBubble";
export enum EncryptionEventState {
@@ -10,7 +10,7 @@ import classNames from "classnames";
import PinIcon from "@vector-im/compound-design-tokens/assets/web/icons/pin-solid";
import styles from "./PinnedMessageBadge.module.css";
import { _t } from "../../core/i18n/i18n";
import { _t } from "../../../../../core/i18n/i18n";
export type PinnedMessageBadgeProps = HTMLAttributes<HTMLDivElement>;
@@ -8,7 +8,7 @@ Please see LICENSE files in the repository root for full details.
import { type Meta, type StoryObj } from "@storybook/react-vite";
import { TextualEventView as TextualEventComponent } from "./TextualEventView";
import { MockViewModel } from "../../core/viewmodel/MockViewModel";
import { MockViewModel } from "../../../../../core/viewmodel/MockViewModel";
const meta = {
title: "Event/TextualEvent",
@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
import React, { type ReactNode, type JSX } from "react";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
export type TextualEventViewSnapshot = {
content: string | ReactNode;
@@ -10,8 +10,8 @@ import { fn } from "storybook/test";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { AudioPlayerView, type AudioPlayerViewActions, type AudioPlayerViewSnapshot } from "./AudioPlayerView";
import { useMockedViewModel } from "../../core/viewmodel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
type AudioPlayerProps = AudioPlayerViewSnapshot & AudioPlayerViewActions;
const AudioPlayerViewWrapperImpl = ({
@@ -14,9 +14,9 @@ import { describe, it, vi, afterEach, expect } from "vitest";
import * as stories from "./AudioPlayerView.stories.tsx";
import { AudioPlayerView, type AudioPlayerViewActions, type AudioPlayerViewSnapshot } from "./AudioPlayerView";
import { MockViewModel } from "../../core/viewmodel/MockViewModel.ts";
import { I18nContext } from "../../core/i18n/i18nContext.ts";
import { I18nApi } from "../../index.ts";
import { MockViewModel } from "../../../../../core/viewmodel/MockViewModel.ts";
import { I18nContext } from "../../../../../core/i18n/i18nContext.ts";
import { I18nApi } from "../../../../../core/i18n/I18nApi.ts";
const { Default, NoMediaName, NoSize, HasError } = composeStories(stories);
@@ -7,16 +7,16 @@
import React, { type ChangeEventHandler, type JSX, type KeyboardEventHandler, type MouseEventHandler } from "react";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { MediaBody } from "../../message-body/MediaBody";
import { Flex } from "../../core/utils/Flex";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
import { MediaBody } from "../MediaBody";
import { Flex } from "../../../../../core/utils/Flex";
import styles from "./AudioPlayerView.module.css";
import { PlayPauseButton } from "../PlayPauseButton";
import { type PlaybackState } from "../playback";
import { useI18n } from "../../core/i18n/i18nContext";
import { formatBytes } from "../../core/utils/FormattingUtils";
import { Clock } from "../Clock";
import { SeekBar } from "../SeekBar";
import { PlayPauseButton } from "../../../../../audio/PlayPauseButton";
import { type PlaybackState } from "../../../../../audio/playback";
import { useI18n } from "../../../../../core/i18n/i18nContext";
import { formatBytes } from "../../../../../core/utils/FormattingUtils";
import { Clock } from "../../../../../audio/Clock";
import { SeekBar } from "../../../../../audio/SeekBar";
export interface AudioPlayerViewSnapshot {
/**
@@ -13,8 +13,8 @@ import {
DecryptionFailureReason,
type DecryptionFailureBodyViewSnapshot,
} from "./DecryptionFailureBodyView";
import { useMockedViewModel } from "../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
type DecryptionFailureBodyProps = DecryptionFailureBodyViewSnapshot;
@@ -10,7 +10,7 @@ import React from "react";
import { describe, it, expect } from "vitest";
import { DecryptionFailureBodyView, DecryptionFailureReason } from "./DecryptionFailureBodyView";
import { MockViewModel } from "../../core/viewmodel";
import { MockViewModel } from "../../../../../core/viewmodel";
describe("DecryptionFailureBodyView", () => {
function customRender(
@@ -10,10 +10,10 @@ import React, { type JSX } from "react";
import { BlockIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { type I18nApi } from "@element-hq/element-web-module-api";
import { type ViewModel } from "../../core/viewmodel/ViewModel";
import { useViewModel } from "../../core/viewmodel/useViewModel";
import { type ViewModel } from "../../../../../core/viewmodel/ViewModel";
import { useViewModel } from "../../../../../core/viewmodel/useViewModel";
import styles from "./DecryptionFailureBodyView.module.css";
import { useI18n } from "../../core/i18n/i18nContext";
import { useI18n } from "../../../../../core/i18n/i18nContext";
/**
* A reason code for a failure to decrypt an event.
@@ -10,7 +10,7 @@ import { fn } from "storybook/test";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { ReactionsRowButtonView } from "../ReactionsRowButton";
import { useMockedViewModel } from "../../core/viewmodel";
import { useMockedViewModel } from "../../../../../core/viewmodel";
import { ReactionsRowView, type ReactionsRowViewActions, type ReactionsRowViewSnapshot } from "./ReactionsRowView";
interface MockReactionButtonProps {
@@ -11,7 +11,7 @@ import React, { type MouseEventHandler } from "react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { MockViewModel } from "../../core/viewmodel";
import { MockViewModel } from "../../../../../core/viewmodel";
import {
ReactionsRowView,
type ReactionsRowViewActions,
@@ -10,7 +10,7 @@ import classNames from "classnames";
import { ReactionAddIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
import { Tooltip } from "@vector-im/compound-web";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
import styles from "./ReactionsRow.module.css";
export interface ReactionsRowViewSnapshot {
@@ -9,7 +9,7 @@ import React, { type JSX } from "react";
import { fn } from "storybook/test";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useMockedViewModel } from "../../core/viewmodel";
import { useMockedViewModel } from "../../../../../core/viewmodel";
import { type ReactionsRowButtonTooltipViewSnapshot } from "../ReactionsRowButtonTooltip";
import {
ReactionsRowButtonView,
@@ -8,7 +8,7 @@
import React, { type HTMLAttributes, type JSX } from "react";
import classNames from "classnames";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
import { ReactionsRowButtonTooltipView, type ReactionsRowButtonTooltipViewModel } from "../ReactionsRowButtonTooltip";
import styles from "./ReactionsRowButton.module.css";
@@ -8,8 +8,8 @@
import React, { type JSX, type PropsWithChildren } from "react";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { useMockedViewModel } from "../../core/viewmodel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
import {
ReactionsRowButtonTooltipView,
type ReactionsRowButtonTooltipViewSnapshot,
@@ -9,7 +9,7 @@ import { type PropsWithChildren, type JSX } from "react";
import React from "react";
import { Tooltip } from "@vector-im/compound-web";
import { type ViewModel, useViewModel } from "../../core/viewmodel";
import { type ViewModel, useViewModel } from "../../../../../core/viewmodel";
/**
* Snapshot interface for the ReactionsRowButtonTooltip view.
@@ -14,8 +14,8 @@ import {
type MessageTimestampViewActions,
type MessageTimestampViewSnapshot,
} from "./MessageTimestampView";
import { useMockedViewModel } from "../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../.storybook/withViewDocs";
import { useMockedViewModel } from "../../../../../core/viewmodel/useMockedViewModel";
import { withViewDocs } from "../../../../../../.storybook/withViewDocs";
type MessageTimestampProps = MessageTimestampViewSnapshot & MessageTimestampViewActions;
const MessageTimestampWrapperImpl = ({
@@ -17,9 +17,9 @@ import {
type MessageTimestampViewActions,
type MessageTimestampViewSnapshot,
} from "./MessageTimestampView";
import { MockViewModel } from "../../core/viewmodel/MockViewModel.ts";
import { I18nContext } from "../../core/i18n/i18nContext.ts";
import { I18nApi } from "../../index.ts";
import { MockViewModel } from "../../../../../core/viewmodel/MockViewModel.ts";
import { I18nContext } from "../../../../../core/i18n/i18nContext.ts";
import { I18nApi } from "../../../../../core/i18n/I18nApi.ts";
const { Default, HasHref } = composeStories(stories);
@@ -10,9 +10,9 @@ import classNames from "classnames";
import { Tooltip } from "@vector-im/compound-web";
import styles from "./MessageTimestampView.module.css";
import { type ViewModel } from "../../core/viewmodel/ViewModel";
import { useViewModel } from "../../core/viewmodel/useViewModel";
import { useI18n } from "../../core/i18n/i18nContext";
import { type ViewModel } from "../../../../../core/viewmodel/ViewModel";
import { useViewModel } from "../../../../../core/viewmodel/useViewModel";
import { useI18n } from "../../../../../core/i18n/i18nContext";
export interface MessageTimestampViewSnapshot {
/**