<div align="center">
	<h1><code>lincle</code>: A <i>reactive</i> React node and edge generator</h1>
</div>

<div align="center">
	<a href="https://www.npmjs.org/package/@lincle/base"><img alt="NPM Version" src="https://img.shields.io/npm/v/@lincle/base.svg" /></a>
	<a href="https://www.gnu.org/licenses/gpl-3.0.en.html"><img alt="License" src="https://img.shields.io/npm/l/@lincle/base.svg" /></a>
	<a href="https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgitlab.com%2Flincle%2Flincle?ref=badge_shield"><img alt="FOSSA Status" src="https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgitlab.com%2Flincle%2Flincle.svg?type=shield" /></a>
</div>

<div align="center">
	<a href="https://github.com/gajus/canonical"><img alt="Canonical Code Style" src="https://img.shields.io/badge/code%20style-canonical-blue.svg" /></a>
	<a href="https://commitizen.github.io/cz-cli/"><img alt="Commitizen Friendly" src="https://img.shields.io/badge/commitizen-friendly-brightgreen.svg" /></a>
	<a href="https://gitlab.com/hyper-expanse/semantic-release-gitlab#readme"><img alt="Semantic Release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg" /></a>
</div>

<div align="center">
	<a href="https://gitlab.com/lincle/lincle/commits/master"><img alt="Build Status" src="https://gitlab.com/lincle/lincle/badges/master/pipeline.svg" /></a>
	<a href="https://lincle.gitlab.io/lincle/stats/base/coverage/lcov-report/"><img alt="Coverage Report" src="https://gitlab.com/lincle/lincle/badges/master/coverage.svg" /></a>
	<a href="https://lincle.gitlab.io/lincle/stats/base/webpack/"><img alt="Build Analysis" src="https://img.shields.io/badge/webpack-stats-blue.svg" /></a>
</div>

**lincle** generates a reactive graph.

Please see the various testing [demos](https://lincle.gitlab.io/lincle/) for examples.

If you require an interactive diagram, checkout [`@lincle/interactive`](https://www.npmjs.com/package/react-yad).

## Installation & Setup

Install `@lincle/base` and the peer dependencies `react`, `react-dom`:

```
npm install react react-dom @lincle/base
```

Also include the provided styles file. For example:

```
import '@lincle/base/dist/main.min.css';
```

## Simple Example

The following example will generate this diagram:

<div align="center">
	<a href="https://gitlab.com/lincle/lincle/-/raw/master/static/simple.png">
		<img src="https://gitlab.com/lincle/lincle/-/raw/master/static/simple.png" alt="resulting screenshot of simple example" style="max-width:100%;">
	</a>
</div>

> [<h3>CodeSandbox</h4>](https://codesandbox.io/s/react-ag-simple-example-8p38n)

```css
/* styles.css */

.App {
	position: absolute;
	overflow: hidden;
	width: 100%;
	height: 100%;
}

.node {
	display: flex;
	align-items: center;
	justify-content: center;
	width: calc(100% - 2px);
	height: calc(100% - 2px);
	border: 1px solid black;
	background-color: white;
	box-shadow: 0 3px 6px rgba(0, 0, 0, 0.16), 0 3px 6px rgba(0, 0, 0, 0.23);
}

.node-oval {
	border-radius: 50%;
}
```

```ts
import React, { FunctionComponent, ReactElement } from "react";
import { Edge, Edges, Graph, Node, Nodes } from "@lincle/base";
import "@lincle/base/dist/main.min.css";
import "./styles.css";

const App: FunctionComponent = (): ReactElement => {
  return (
    <div className="App">
      <Graph id="SimpleDiagram" key="1" nodeHeight={50} nodeWidth={50}>
        <Nodes>
          <Node id={1} key={1} x={50} y={50}>
            <div className="node">Node 1</div>
          </Node>
          <Node
            height={100}
            id={2}
            key={2}
            shape="oval"
            width={200}
            x={100}
            y={150}
          >
            <div className="node node-oval">Node 2</div>
          </Node>
          <Node id={3} key={3} shape="oval" x={150} y={350}>
            <div className="node node-oval">Node 3</div>
          </Node>
        </Nodes>
        <Edges>
          <Edge id={1} key={1} sourceId={1} targetId={2}>
            <circle fill="white" r="3" stroke="black" strokeWidth={2}>
              <title>Bridge</title>
            </circle>
          </Edge>
          <Edge id={2} key={2} line="direct" sourceId={2} targetId={3} />
        </Edges>
      </Graph>
    </div>
  );
};

export default App;

```

## Component API's

**\***  *bolded parameters are required*

### `<Graph>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| **`id`** | `string \| number` | | The unique ID of the graph |
| edgeFrequency | `number` | `16` | Frequency of edge updates during node movements (in ms) |
| grid | `false \| [number, number] ` | `[16, 16]` | The background grid space; false to disable. |
| line | `"curve" \| "direct" \| "step"` | `"step"` | The default curve for the edges |
| nodeFrequency | `number` | `500` | Frequency of node movements reported (in ms, aside from edges) |
| nodeHeight | `number` | `50` | The default height for nodes (in px) |
| nodeWidth | `number` | `50` | The default width for nodes (in px) |
| shape | `"oval" \| "rectangle"` | `"rectangle"` | The default shape for nodes |

### `<Nodes>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| *none* |

### `<Node>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| **`id`** | `string \| number` | | The unique ID of the node |
| x | `number` | `0` | The initial `x` coordinate of the node |
| y | `number` | `0` | The initial `y` coordinate of the node |
| <td colspan="3">*The following override the defaults provided by `<Graph />`* |
| height | `number` | `50` | The node height |
| shape | `'oval' \| 'rectangle'` | `rectangle` | The shape of the node |
| width | `number` | `50` | The node width |

### `<Edges>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| dash | `boolean \| undefined` | `undefined` | Whether dash should be enabled. Defaults to hover only. |

### `<Edge>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| **`id`** | `string \| number` | | The unique ID for the edge |
| dash | `boolean \| undefined` | `undefined` | Whether dash should be enabled. Defaults to hover only. |
| line | `'curve' \| 'direct' \| 'step'` | `direct` | The line shape (overrides default) and not applicable if custom path generator is used. |
| markerEnd | `string` | | Passed to the default path generated `<path>` SVG |
| markerStart | `string` | | Passed to the default path generated `<path>` SVG |
| path | *path `function` - see below* | | Use to generate a custom path component. |
| **`sourceId`** | `string \| number` | | ID for the source node |
| **`targetId`** | `string \| number` | | ID for the target node |

> ***Note**: The child of `<Edge />` is intended to be an element at the center of the path. The child will be inside an `<SVG />` element and should be an SVG type or wrapped in a `<foreignObject />` element. See examples for details.*

### Path `function`

Instead of using the `@lincle/base` provided edges (`curve`, `line`, & `step`), you may opt to generate your own path component:

```ts
(
	source: {
		height: number,
		id: string | number,
		shape: 'oval' | 'rectangle',
		width: number,
		x: number,
		y: number
	},
	target: {
		height: number,
		id: string | number,
		shape: 'oval' | 'rectangle',
		width: number,
		x: number,
		y: number
	},
	children?: ReactNode
) => Component<SVG type>
```

### `<Grid>`

| Parameters | Type | Default | Description |
|---|---|---|---|
| children | `SVG` | `<circle>` | The repeated SVG |
| scale | `number` | `1` | Scales the grid |
| xOffset | `number` | `0` | Translates the grid left/right |
| yOffset | `number` | `0` | Translates the grid up/down |

### Contexts

`<Context>`'s can be taken advantage of to extend the functionality of `@lincle/base`:

| Context | Provides | Description |
|---|---|---|
| `<GraphContext>` | `{diagramId: ReactText, nodePosition: NodePositions, edgeSubscriber: EdgeSubscriber, defaultSettings: DefaultSettings}` | Provides the current diagramId and default settings along with classes to subscribe to `<Node>` and `<Edge>` events. |
| `<GridContext>` | `[number, number]` | Provides the current grid dimensions. |
