Skip to content
A React Native module for parsing and displaying git diffs.
TypeScript JavaScript Shell
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
hooks
src
.eslintrc
.gitignore
.npmignore
.prettierignore
.prettierrc
.travis.yml
LICENSE
README.md
babel.config.js
example.png
jest.config.js
package-lock.json
package.json
tsconfig.json

README.md

react-native-diff-view Build Status David

A React Native module for parsing and displaying git diffs. This library was heavily inspired by, and borrows code from, react-diff-view.

Overview

The purpose of this library is to parse and render a unified diff view for any provided diff(s). The flexible widget system also allows for rendering of custom elements on a per-line (or "change") basis. The end result will look something like this:

Example diff with a comment widget

Getting Started

npm install --save react-native-diff-view

Usage

Parsing Diffs

The top-level parseDiff(diff: string): IFile[] export is a wrapper around gitdiff-parser, but strongly typed and with some extra options:

  • nearbySequence: 'zip' | undefined — the action to take when nearby sequences are encountered.

Rendering Diff Hunks

The top-level Diff export is a component to be used for rendering a single diff. Here's a simple example:

import React from 'react';
import { View, ScrollView } from 'react-native';
import { parseDiff, Diff, Hunk } from 'react-native-diff-view';

const App = ({ diffText }) => {
    const files = parseDiff(diffText);

    const renderFile = ({ oldRevision, newRevision, type, hunks }) => (
      <ScrollView key={oldRevision + '-' + newRevision} horizontal={true} bounces={false}>
        <Diff diffType={type} hunks={hunks}>
            {(hunks) => hunks.map((hunk) => <Hunk key={hunk.content} hunk={hunk} />)}
        </Diff>
      </ScrollView>
    );

    return (
      <View>
        {files.map(renderFile)}
      </View>
    );
};

props.children, in this case, is a function that takes an array of IHunk and returns the rendered element(s). This is optional, and if not provided the hunks will be rendered as default <Hunk/ > components.

Wrapping Hunks in Decorations

A decoration is a way to wrap a <Hunk /> component with customized content.

A <Decoration /> component is a simple passthrough of props.children, which can be either a single element or an array of two:

  • A single element: this will be rendered in the entire row.
  • An array containing two elements: The first element will be rendered in gutter position, the second will be rendered in code position.

A very simple use case of Decoration is to provide a summary infomation of hunk:

import React from 'react';
import { Diff, Hunk, Decoration } from 'react-native-diff-view';

const renderHunk = (hunk) => [
  <Decoration key={'decoration-' + hunk.content}>
      {hunk.content}
  </Decoration>,
  <Hunk key={'hunk-' + hunk.content}> hunk={hunk} />,
];

const DiffFile = ({ diffType, hunks }) => (
  <Diff diffType={diffType}>
      {hunks.map(renderHunk)}
  </Diff>
);

Rendering Widgets

As mentioned above, widgets can be used to render custom element(s) on a per-change, or per-line, basis. These will be rendered immediately below their corresponding line. Only the first match will be rendered.

Here's a basic example that adds a warning on long lines:

import React from 'react';
import { Text } from 'react-native';
import { parseDiff, getChangeKey, Diff } from 'react-native-diff-view';

const getWidgets = (hunks) => {
    const changes = hunks.reduce((result, {changes}) => [...result, ...changes], []);
    const longLines = changes.filter(({content}) => content.length > 120);

    return longLines.reduce(
      (widgets, change) => {
        const changeKey = getChangeKey(change);

        return {
          ...widgets,
          [changeKey]: <Text>Line too long</Text>
        };
      },
      {},
    );
};

const App = ({diffText}) => {
    const files = parseDiff(diffText);

    return (
        <div>
            {files.map(({hunks}, i) => <Diff key={i} hunks={hunks} widgets={getWidgets(hunks)} viewType="split" />)}
        </div>
    );
};

Styling

The following props are supported but optional on the top-level <Diff /> component:

  • style: ViewStyle — styling to be applied to the top-level Diff view.
  • lineStyle: ViewStyle — styling to be applied on each individual change line.
  • gutterStyle: ViewStyle — styling to be applied on the gutter of each individual change.
  • contentStyle: ViewStyle — styling to be applied to the code content of each individual change.

Events

The following events are supported but optional on the top-level <Diff /> component:

  • onChangePress(change: IChange) => any — if provided, this will be triggered any time a user presses on a specific line or change in a diff.

Contributing

🎊 Thanks for considering contributing! Issue reports and pull requests are always welcome.

To get started:

  1. git clone https://github.com/jakemmarsh/react-native-diff-view.git
  2. cd react-native-diff-view
  3. npm install

To test your changes before opening a PR:

npm test

You can’t perform that action at this time.