mirror of
https://github.com/backnotprop/plannotator.git
synced 2026-09-14 14:17:26 +08:00
4bbb0f3aff
Adds components/MarkdownDiff.tsx, a theme-bridging shim over @plannotator/markdown-editor's frozen two-revision diff, mirroring the MarkdownEditor shim exactly: ThemeProvider mode bridge, plannotator.css theme import, extensions passthrough (wikiLinks composes), gridEnabled -> the same design-system card chrome. Hosts import it from @plannotator/ui/components/MarkdownDiff; AtomicDiffEditor and @plannotator/atomic-editor stay off the allowlist. Deps: @plannotator/markdown-editor ^0.4.0, @plannotator/atomic-editor ^0.8.0 (single lockfile copy each), plus @codemirror/merge — the engine's new required peer — declared directly per the CM6 single-copy discipline. Tests pin the seam end-to-end: public export surface + types, byte-exact getMarkdown()/getOriginalMarkdown() incl. CRLF/trailing-space fixtures, contenteditable="false" frozen contract, change navigation, wiki-link composition through the shim, and theme/host-class forwarding. The strict-consumer tsconfig now typechecks the new module.
61 lines
2.9 KiB
TypeScript
61 lines
2.9 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
MarkdownDiff as PackagedMarkdownDiff,
|
|
type MarkdownDiffHandle,
|
|
type MarkdownDiffProps as PackagedMarkdownDiffProps,
|
|
} from '@plannotator/markdown-editor';
|
|
import '@plannotator/markdown-editor/themes/plannotator.css';
|
|
import { useTheme } from './ThemeProvider';
|
|
|
|
export type { MarkdownDiffHandle };
|
|
|
|
/* @plannotator/ui is the single supported contract for hosts — do NOT import
|
|
AtomicDiffEditor or @plannotator/atomic-editor directly (both are outside
|
|
the import allowlist). Extension builders (wikiLinks, slashCommands,
|
|
selectionToolbar) are re-exported from ./MarkdownEditor; build them there
|
|
and pass the result through the `extensions` prop below — the frozen diff
|
|
view composes them the same way the editor does. */
|
|
|
|
/* Grid-mode card utilities mirror components/MarkdownEditor.tsx exactly, so a
|
|
host toggling editor <-> diff keeps identical card chrome. They stay here
|
|
(not in the package) because they're Plannotator design-system Tailwind
|
|
classes and this file is @source-scanned. */
|
|
const GRID_CARD_CLASSES = 'px-5 md:px-8 lg:px-10 xl:px-12 shadow-xl border border-border/50';
|
|
|
|
export interface MarkdownDiffProps
|
|
extends Omit<PackagedMarkdownDiffProps, 'mode' | 'cardClassName'> {
|
|
/** Mirrors MarkdownEditor's grid card chrome so editor <-> diff doesn't jump. */
|
|
gridEnabled?: boolean;
|
|
/** Theme color mode. Defaults to the ThemeProvider's resolved mode (Plannotator
|
|
passes nothing); a host without ThemeProvider can supply it directly. */
|
|
mode?: PackagedMarkdownDiffProps['mode'];
|
|
}
|
|
|
|
/* Theme-bridging shim around @plannotator/markdown-editor's MarkdownDiff — the
|
|
frozen two-revision comparison surface (newer revision as the real document,
|
|
deletions projected struck-through in place). Same pattern as the
|
|
MarkdownEditor shim: resolve the color mode from ThemeProvider beneath the
|
|
host's provider and pass it down as a prop.
|
|
|
|
The byte contract lives on `editorHandleRef`: getMarkdown() returns the
|
|
exact `modifiedMarkdown` supplied, getOriginalMarkdown() the exact
|
|
`originalMarkdown` — both byte-identical to the inputs. The surface itself
|
|
is frozen: document-changing transactions are rejected at the state and
|
|
view boundaries, and the content DOM is contenteditable="false".
|
|
|
|
`extensions` follows the editor's calling convention: CAPTURED ONCE per
|
|
mounted comparison (keyed on `documentId` + both document strings) — pass a
|
|
stable array and feed changing data through callbacks that close over live
|
|
state. Build extensions against YOUR copy of the `@codemirror/*` packages;
|
|
two live copies of `@codemirror/state` break the view. */
|
|
export const MarkdownDiff: React.FC<MarkdownDiffProps> = ({ gridEnabled, mode, ...props }) => {
|
|
const { resolvedMode } = useTheme();
|
|
return (
|
|
<PackagedMarkdownDiff
|
|
{...props}
|
|
mode={mode ?? resolvedMode}
|
|
cardClassName={gridEnabled ? GRID_CARD_CLASSES : undefined}
|
|
/>
|
|
);
|
|
};
|