Files
outline/app/scenes/Document/components/RevisionViewer.tsx
T
Tom Moor 4387f3ced7 fix: Resolve console warnings for rtl DOM attribute and untracked MobX read (#12284)
- Use transient `$rtl` prop on Meta styled component so it isn't forwarded to the DOM
- Wrap ActionButton in observer so action visibility checks read MobX computed values inside a reactive context

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-06 20:48:13 -04:00

111 lines
3.6 KiB
TypeScript

import { observer } from "mobx-react";
import * as React from "react";
import { colorPalette } from "@shared/utils/collections";
import type Document from "~/models/Document";
import type Revision from "~/models/Revision";
import type { Props as EditorProps } from "~/components/Editor";
import Flex from "~/components/Flex";
import { documentPath } from "~/utils/routeHelpers";
import { Meta as DocumentMeta } from "./DocumentMeta";
import DocumentTitle from "./DocumentTitle";
import Editor from "~/components/Editor";
import { richExtensions, withComments } from "@shared/editor/nodes";
import Diff from "@shared/editor/extensions/Diff";
import { RevisionHelper } from "@shared/utils/RevisionHelper";
import useQuery from "~/hooks/useQuery";
import useStores from "~/hooks/useStores";
import { type Editor as TEditor } from "~/editor";
import { ChangesetHelper } from "@shared/editor/lib/ChangesetHelper";
type Props = Omit<EditorProps, "extensions"> & {
/** The ID of the revision */
id: string;
/** The current document */
document: Document;
/** The revision to display */
revision: Revision;
/** Whether to show changes from the previous revision */
showChanges?: boolean;
children?: React.ReactNode;
};
/**
* Displays a revision with diff highlighting showing changes from the previous revision.
*
* This component shows the content of a specific revision with visual diff indicators
* that highlight what changed compared to the revision that came before it. Insertions
* are shown with a highlight background, and deletions are shown with strikethrough.
*
* @param props - Component props including the revision to display and current document
*/
function RevisionViewer(props: Props, ref: React.Ref<TEditor>) {
const { document, children, revision } = props;
const { revisions } = useStores();
const query = useQuery();
const showChanges = props.showChanges ?? query.has("changes");
const compareToParam = query.get("compareTo");
const compareToRevisionId = React.useMemo(() => {
if (!compareToParam) {
return undefined;
}
return compareToParam === "latest"
? RevisionHelper.latestId(revision.documentId)
: compareToParam;
}, [compareToParam, revision.documentId]);
const compareToRevision = compareToRevisionId
? revisions.get(compareToRevisionId)
: undefined;
const comparisonData = compareToRevisionId
? compareToRevision?.data
: revision.before?.data;
/**
* Create editor extensions with the Diff extension configured to render
* the calculated changes as decorations in the editor.
*/
const extensions = React.useMemo(() => {
const changeset = ChangesetHelper.getChangeset(
revision.data,
comparisonData
);
return [
...withComments(richExtensions),
...(showChanges && changeset?.changes
? [new Diff({ changes: changeset?.changes })]
: []),
];
}, [revision.data, comparisonData, showChanges]);
return (
<Flex auto column>
<DocumentTitle
documentId={revision.documentId}
title={revision.title}
icon={revision.icon}
color={revision.color ?? colorPalette[0]}
readOnly
/>
<DocumentMeta
document={document}
revision={revision}
to={documentPath(document)}
$rtl={revision.rtl}
/>
<Editor
key={compareToRevisionId}
ref={ref}
defaultValue={revision.data}
extensions={extensions}
dir={revision.dir}
readOnly
/>
{children}
</Flex>
);
}
export default observer(React.forwardRef(RevisionViewer));