diff --git a/CHANGELOG.md b/CHANGELOG.md index 0e06957..b529fbe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on Keep a Changelog, and this project follows Semantic Versi ## [Unreleased] +### Added + +- Introduced API tiering with a new minimal `SimpleDiffViewer` export for common use cases, while keeping `DiffViewer` (and `AdvancedDiffViewer` alias) for advanced customization scenarios. +- Added `docs/api-tiering.md` with persona-oriented guidance and three practical examples: basic diff, large-file virtualization, and commentable line embedding. +- Added TypeScript JSDoc examples for advanced API types (`DiffViewerProps`, `RenderContent`, and `DiffViewerHandle`). + +### Changed + +- Updated README (EN/ZH), package README, and `llms.txt` to document minimal-vs-advanced API tiers and recommended adoption path. + ### Docs - Reorganized root README files for clearer scanning (quick overview + positioning block), clarified the purpose of `docs/positioning.md`, and aligned `packages/react/README.md` so npm package docs reflect the same positioning updates. diff --git a/README.md b/README.md index 6402945..0fffc27 100644 --- a/README.md +++ b/README.md @@ -51,14 +51,14 @@ pnpm add react-virtualized-diff ## Quick Start ```tsx -import { DiffViewer } from 'react-virtualized-diff'; +import { SimpleDiffViewer } from 'react-virtualized-diff'; const original = `line 1\nline 2\nline 3`; const modified = `line 1\nline 2 changed\nline 3\nline 4`; export function App() { return ( - ` | - | 高亮指定行(如 `L-3`、`R-5`、`L-10-15`) | +| `onLineNumberClick` | `(lineId) => void` | - | 点击行号回调 | +| `renderContent` | `(line: string) => ReactNode` | - | 自定义行内容渲染(语法高亮等) | +| `compareMethod` | `"CHARS" \| "WORDS" \| "WORDS_WITH_SPACE" \| "LINES" \| "TRIMMED_LINES" \| "SENTENCES" \| "CSS"` | `"LINES"` | Diff 比较策略 | +| `disableWordDiff` | `boolean` | `false` | 关闭词级高亮 | +| `leftTitle` | `ReactNode` | - | 左侧标题(并排模式) | +| `rightTitle` | `ReactNode` | - | 右侧标题(并排模式) | +| `linesOffset` | `number` | `0` | 行号显示偏移量 | +| `useDarkTheme` | `boolean` | `false` | 内置暗色主题 | +| `styles` | `Partial` | - | 样式槽位覆盖 | +| `codeFoldMessageRenderer` | `({ hiddenCount, expanded }) => ReactNode` | - | 自定义折叠按钮文案渲染 | | `height` | `number \| string` | `500` | 虚拟列表可视区域高度 | | `locale` | `DiffViewerLocale` | - | 组件文案本地化 | | `language` | `string` | - | 预留字段(未来语言相关扩展) | diff --git a/docs/api-tiering.md b/docs/api-tiering.md new file mode 100644 index 0000000..2216479 --- /dev/null +++ b/docs/api-tiering.md @@ -0,0 +1,129 @@ +# API Tiering Guide + +This document groups `react-virtualized-diff` APIs into usage tiers so teams can pick the right abstraction level quickly. + +## Tier 1: Minimal API (`SimpleDiffViewer`) + +**Best for** + +- Product teams that need a reliable diff view fast. +- Typical PR/MR preview pages. +- Apps where defaults are good enough and maintainability matters more than customization. + +**Use this when** + +- You only need to pass two texts and a few basic display options. +- You want the smallest cognitive load for contributors. + +**Primary API** + +- `original` +- `modified` +- `height` +- `splitView` +- `showDiffOnly` +- `contextLines` +- `hideLineNumbers` +- `useDarkTheme` +- `locale` + +### Minimal example 1: 基础对比 + +```tsx +import { SimpleDiffViewer } from 'react-virtualized-diff'; + +export function BasicDiffExample() { + return ( + + ); +} +``` + +### Minimal example 2: 大文件虚拟化 + +```tsx +import { SimpleDiffViewer } from 'react-virtualized-diff'; + +function buildLargeText(size: number, changedAt: number) { + return Array.from({ length: size }, (_, i) => + i === changedAt ? `line ${i + 1} (changed)` : `line ${i + 1}`, + ).join('\n'); +} + +export function VirtualizedLargeFileExample() { + const original = buildLargeText(50000, -1); + const modified = buildLargeText(50000, 24567); + + return ( + + ); +} +``` + +## Tier 2: Advanced API (`DiffViewer` / `AdvancedDiffViewer`) + +**Best for** + +- Code review platforms with domain-specific behaviors. +- Teams needing tight design-system integration. +- Scenarios requiring interaction hooks and custom rendering. + +**Use this when** + +- You need custom line rendering (syntax highlighting, inline widgets). +- You need line-number gutter interactions. +- You need custom fold/collapse messaging or styling. + +**Primary advanced extension points** + +- 自定义行渲染: `renderContent` +- 语法高亮集成: `renderContent` +- 行号 gutter 交互: `onLineNumberClick`, `highlightLines`, `linesOffset` +- 折叠策略: `showDiffOnly`, `contextLines`, `extraLinesSurroundingDiff`, `codeFoldMessageRenderer` +- 深度样式定制: `styles`, `useDarkTheme` + +### Minimal example 3: 可评论行组件嵌入 + +```tsx +import { DiffViewer } from 'react-virtualized-diff'; + +function CommentableLine({ line }: { line: string }) { + return ( + + {line} + + + ); +} + +export function CommentableDiffExample() { + return ( + } + onLineNumberClick={(lineId) => { + // open comment panel by line id + console.log('comment target:', lineId); + }} + height={420} + /> + ); +} +``` + +## Recommendation matrix + +- Start with `SimpleDiffViewer` for most application pages. +- Move to `DiffViewer` (`AdvancedDiffViewer`) only after a concrete customization requirement appears. +- Keep one internal wrapper in your codebase if your product repeatedly uses the same advanced options. diff --git a/llms.txt b/llms.txt index 9354370..fb995c5 100644 --- a/llms.txt +++ b/llms.txt @@ -31,13 +31,19 @@ npm install react-virtualized-diff ## Minimum usage ```jsx -import { DiffViewer } from 'react-virtualized-diff'; +import { SimpleDiffViewer } from 'react-virtualized-diff'; - + ``` Two strings are the complete minimum API. This produces a side-by-side diff with collapsed unchanged blocks and virtualized scrolling. +## API tiers + +- **Tier 1 (recommended):** `SimpleDiffViewer` for most product pages. Minimal props: `original`, `modified`, `height`, `splitView`, `showDiffOnly`, `contextLines`, `hideLineNumbers`, `useDarkTheme`, `locale`. +- **Tier 2 (advanced):** `DiffViewer` (also exported as `AdvancedDiffViewer`) when you need deep customization such as `renderContent`, line-gutter interactions, fold-message customization, and style slot overrides. +- See tiering guide: `docs/api-tiering.md`. + ## Commonly used props - `original` (string): base/left content — new API name diff --git a/packages/react/README.md b/packages/react/README.md index d633d2d..b236dff 100644 --- a/packages/react/README.md +++ b/packages/react/README.md @@ -31,11 +31,11 @@ pnpm add react-virtualized-diff ## Usage ```tsx -import { DiffViewer } from 'react-virtualized-diff'; +import { SimpleDiffViewer } from 'react-virtualized-diff'; export function App() { return ( - + * ``` + */ +export interface SimpleDiffViewerProps { + /** Original text content (left side). */ + original: string; + /** Modified text content (right side). */ + modified: string; + /** + * Virtualized viewport height. + * @default 500 + */ + height?: number | string; + /** + * Side-by-side (split) or unified (inline) view. + * @default true + */ + splitView?: boolean; + /** + * Show only changed blocks with unchanged context collapsed. + * @default true + */ + showDiffOnly?: boolean; + /** + * Number of unchanged lines to keep around each change block. + * @default 2 + */ + contextLines?: number; + /** + * Hide line number columns. + * @default false + */ + hideLineNumbers?: boolean; + /** + * Use built-in dark color palette. + * @default false + */ + useDarkTheme?: boolean; + /** Localized text labels. */ + locale?: DiffViewerLocale; +} + +/** + * Recommended entry for 80% of scenarios. + * Keeps the API intentionally small while still using the same rendering engine. + */ +export const SimpleDiffViewer = React.forwardRef( + function SimpleDiffViewer( + { + original, + modified, + height, + splitView, + showDiffOnly, + contextLines, + hideLineNumbers, + useDarkTheme, + locale, + }, + ref, + ): React.JSX.Element { + return ( + + ); + }, +); diff --git a/packages/react/src/index.ts b/packages/react/src/index.ts index eda73d4..018bf2a 100644 --- a/packages/react/src/index.ts +++ b/packages/react/src/index.ts @@ -1,2 +1,5 @@ -export * from './DiffViewer'; +export { DiffViewer } from './DiffViewer'; +export { DiffViewer as AdvancedDiffViewer } from './DiffViewer'; +export { SimpleDiffViewer } from './SimpleDiffViewer'; +export type { SimpleDiffViewerProps } from './SimpleDiffViewer'; export * from './types'; diff --git a/packages/react/src/types.ts b/packages/react/src/types.ts index 691fa9f..3f1cc86 100644 --- a/packages/react/src/types.ts +++ b/packages/react/src/types.ts @@ -1,5 +1,8 @@ import type React from 'react'; +/** + * Diff line kind in rendered output. + */ export type DiffType = 'added' | 'removed' | 'unchanged'; export type CompareMethod = @@ -57,9 +60,32 @@ export type LineId = `L-${number}` | `R-${number}`; export type HighlightToken = LineId | `${LineId}-${number}`; +/** + * Render hook for custom line content (for example syntax-highlighted HTML/React nodes). + * + * @example + * ```tsx + * {line}} + * /> + * ``` + */ export type RenderContent = (source: string) => React.ReactNode; - +/** + * Imperative methods exposed via `ref`. + * + * @example + * ```tsx + * const ref = useRef(null); + * + * + * + * ref.current?.resetCodeBlocks(); + * ``` + */ export interface DiffViewerHandle { resetCodeBlocks: () => void; } @@ -69,6 +95,20 @@ export type CodeFoldMessageRenderer = (params: { expanded: boolean; }) => React.ReactNode; +/** + * Full-featured API for deep customization (advanced tier). + * + * @example + * ```tsx + * } + * onLineNumberClick={(lineId) => console.log(lineId)} + * codeFoldMessageRenderer={({ hiddenCount }) => } + * /> + * ``` + */ export interface DiffViewerProps { original?: string; modified?: string;