Skip to content

jakemmarsh/react-native-diff-view

Folders and files

NameName
Last commit message
Last commit date

Latest commit

43f150e · Nov 3, 2019

History

24 Commits
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Nov 3, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019
Oct 8, 2019

Repository files navigation

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