import { Meta } from '@storybook/blocks';
import { getAPIDocumentationLink, getAPIPropsLink } from './utils/get-api-documentation-link';

<Meta title="Introduction" />

# Introduction to @joint/react

**@joint/react** is a React wrapper for [JointJS](https://www.jointjs.com/), designed to make creating and managing interactive diagrams and graphs in React applications simple and intuitive. It provides React components, hooks, and utilities to efficiently manage nodes, links, and user interactions.

## 📌 Core Components

### 1. {getAPIDocumentationLink('GraphProvider')}
The `GraphProvider` component manages a shared [JointJS Graph instance](https://docs.jointjs.com/api/dia/Graph/) to handle the state of your diagram. Wrap it around any components that interact with the graph.

```tsx
import { GraphProvider } from '@joint/react';

<GraphProvider>
  {/* Components like Paper for rendering nodes and edges */}
</GraphProvider>
```

### 2. {getAPIDocumentationLink('Paper', 'variables')}
The `Paper` component wraps [JointJS Paper](https://docs.jointjs.com/learn/quickstart/paper/) to render nodes and links. Use the {getAPIPropsLink('Paper', 'renderElement')} prop to define how nodes are displayed.

```tsx
import { Paper } from '@joint/react';

const renderElement = (element) => (
  <rect width={element.size().width} height={element.size().height} fill="cyan" />
);

<Paper width={800} height={600} renderElement={renderElement} />
```

### 3. **Embedding HTML in SVG Nodes**
While JointJS primarily uses SVG, you can embed HTML content inside nodes using SVG's `<foreignObject>`:

```tsx
const renderElement = ({ width, height }) => (
  <foreignObject width={width} height={height}>
    <div style={{ background: 'lightgray' }}>
      HTML Content here
    </div>
  </foreignObject>
);
```

## 🛠️ Core Hooks and Utilities

### 🔹 Accessing Elements
- {getAPIDocumentationLink('useElements')}: Retrieve all diagram elements (requires `GraphProvider` context).
- {getAPIDocumentationLink('useElement')}: Retrieve individual element data, typically used within `renderElement`.

### 🔹 Modifying Elements
- {getAPIDocumentationLink('useUpdateElement')}: Update existing elements in the diagram.

### 🔹 Graph and Paper Instances
- {getAPIDocumentationLink('useGraph')}: Access the JointJS [Graph instance](https://docs.jointjs.com/api/dia/Graph/) directly.
- {getAPIDocumentationLink('usePaper')}: Access the JointJS [Paper instance](https://docs.jointjs.com/learn/quickstart/paper/) directly.

### 🔹 Creating Nodes and Links
- {getAPIDocumentationLink('createElements')}: Utility for creating nodes.

```ts
import { createElements } from '@joint/react';

const initialElements = createElements([
  { id: '1', type: 'rect', x: 10, y: 10, width: 100, height: 100 },
]);
```

- {getAPIDocumentationLink('createLinks')}: Utility for creating links between nodes.

```ts
import { createLinks } from '@joint/react';

const initialLinks = createLinks([
  { source: '1', target: '2', id: '1-2' },
]);
```

---

## How It Works
Under the hood, **@joint/react** listens to changes in the `dia.Graph`, which acts as the single source of truth. When you update the graph—such as adding or modifying cells—the React components automatically observe and react to these changes, keeping the UI in sync.

Hooks like `useUpdateElement` provide a convenient way to update the graph, but you can also directly access the graph using `useGraph()` and call methods like `graph.setCells()`.

---

## Known Issues

### Avoid Certain CSS Properties in `<foreignObject>`
Some CSS properties can cause rendering issues in Safari when used inside an SVG `<foreignObject>`. To ensure compatibility, avoid the following properties:

- `position` (other than `static`)
- `-webkit-transform-style`
- `-webkit-backface-visibility`
- `transition`
- `transform`

### Recommended Workaround
If you need to use HTML inside an SVG with cross-browser support:

- Use minimal CSS inside `<foreignObject>`.
- Stick to static positioning and avoid CSS transforms.
- Consider overlaying HTML outside the SVG using absolute positioning.

### Flickering
React's asynchronous rendering can cause flickering when dynamically adding ports or resizing elements. We are aware of this issue and are working on a fix.

### Controlled Mode
Currently, **@joint/react** uses `useSyncExternalStore` to listen to graph changes. The graph is the source of truth, so `initialElements` and `initialLinks` are only used during initialization. To modify the state, update the graph directly using hooks like `useGraph`, `useUpdateElement`, or `useCreateElement`. A fully controlled mode is under development.
