@nuclent/schema-viewer
v0.0.8
Published
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
Downloads
190
Readme
@nuclent/schema-viewer
Schema Visualizer for React
@nuclent/schema-viewer
is a comprehensive React component library designed to render interactive, customizable graph-based visualizations representing complex schemas. Built on top of React Flow, it provides a simplified API to define nodes, edges, and their interactions, making it perfect for visualizing relational data, database schemas, or any other interconnected structures.
Whether you're dealing with large datasets or intricate relationships within your data, @nuclent/schema-viewer
offers a declarative approach to constructing vivid and dynamic graphs. With features like a built-in minimap, controllable node expansion, and various stylings options, your data visualization is both functional and aesthetically pleasing.
With @nuclent/schema-viewer
, you can expect:
- Ease of Use: Simplify the process of mapping your data into a visual context.
- Flexibility: Customize the appearance and behavior of your nodes and edges to meet the specific needs of your application.
- Interactivity: Engage with your diagrams through interactive features like zooming, dragging, and event handlers.
Ideal for developers working on data analysis tools, database management systems, or any application that benefits from graph visualization, @nuclent/schema-viewer
is the go-to solution for representing data-driven insights.
Installation
npm install @nuclent/schema-viewer
or
yarn add @nuclent/schema-viewer
Usage
Quick start example:
# tsx
import React from 'react';
import { FlowWrapper } from "@nuclent/schema-viewer";
// import styles
import "@nuclent/schema-viewer/dist/style.css";
function App() {
return (
<FlowWrapper
// ...props here
/>
);
}
export default App;
API Reference
For clarifiation, each node's data field named as Field, but we can call it as a row / field - anything refer to a row in a table schema.
| Prop | Type | Default | Description | | --------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------- | | data * | SchemaData[] | [] | The nodes of the graph. | | legend | boolean | true | If true, legend information is displayed. | | containerStyle | CSSProperties | position: "relative", height: "100dvh", width: "100%", maxWidth: "100%", margin: 0, padding: 0 | Styles applied to the graph container. |
|Nodes |nodeModalRender | React.ReactNode | A Stack display that field's information | Custom React render inside Mantine modal when a Field clicked.| |nodeModalSize | MantineNumberSize number | "xs" | "sm" | "md" | "lg" | "xl" | sm| |nodeModalTitle | string | Its Field ["displayName"] property | |nodeCloseOnClickOutside | boolean | true| |color | MantineColor | white | The color of a node's header text | |bgColor |MantineColor | indigo | The background color of a node header | |shadowColor| string | "10px 10px 50px 0px rgba(166, 179, 231, 0.75)" | Node's box shadow color when selected (dragging, clicked) |Edges | edgeType | smoothstep | bezier | smoothstep | The type of edges between nodes. | |radius | number | 12 | How curve should a edge's corner be? *Note: only work if edge type is *smoothstep** | |edgeModalRender | React.ReactNode | A Stack display that edge's information | Custom React render inside Mantine modal when an Edge clicked. |edgeModalSize | MantineNumberSize number | "xs" | "sm" | "md" | "lg" | "xl" | sm| |edgeModalTitle | string | "Edge Details" | |edgeCloseOnClickOutside | boolean | true| |labelColor |MantineColor | white | The color of an edge's label text| | labelBgColor |MantineColor | indigo.4 | The background color of a edge label| | selectedLabelColor | MantineColor | blue | The background color of a edge label when selected (clicked) | |Toolbar | toolbar | boolean | true | If true, a toolbar will be displayed. | |toolbarTitle | string | "Schema Viewer Toolbar" | |toolbarPosition | PanelPositon |top-left | | toolbarBgColor |MantineColor | white | The background color of toolbar panel| |React Flow | background | BackgroundVariant | BackgroundVariant.Lines | The background variant of the app. | | minimap | boolean | true | If true, a minimap will be displayed. | |minimapNodeColor | string | gray | The fill color for nodes displayed in the minimap | |minimapMaskColor |string | #d9d9d9c7 | |minimapPosition | PanelPositon |bottom-right | controls | boolean | true | If true, React Flow controls is displayed. | |controlsPosition | PanelPositon | top-right |ELK | layoutOptions | Record<string, string | number> | undefined | Options for the graph's layout algorithm. | |Default State | collapse | boolean | false | If true, all nodes will be collapsed by default. | | hidden | boolean | false | If true, all nodes will be hidden by default. |
More detailed explanation for complex props:
layoutOptions
The layoutOptions prop allows fine-tuning of the graph's layout. It accepts an object where the key is the layout option name and the value is its setting. All reference can be found here: ELK Reference
Example:
const layoutOptions = {
"elk.algorithm": "org.eclipse.elk.layered",
"elk.direction": "RIGHT"
};
return <FlowWrapper layoutOptions={layoutOptions} />
Node / Edge Modal Render
import { CustomNodeModalRender } from "../somewhere";
return <FlowWrapper
nodeModalRender={ <CustomNodeModalRender />}
// other props ...
/>
Examples & Demo
Live & Editable demo available here: Demo Link
nFlow Data Conversion Code Sample
# tsx
import { Field, FlowWrapper, Relation } from "@nuclent/schema-viewer";
import "@nuclent/schema-visualizer/dist/style.css";
const App = () => {
return (
<FlowWrapper
nodes={nodes}
edgeModalTitle="hi everyone"
edgeModalRender={<Test />}
/>
)
}
function Test() {
return (
<div>
<p>im going to sleep</p>
</div>
);
}
const nodes = array.map((i) => {
const id = String(i.id);
return {
id,
data: {
id,
fields: mapFields(i.fields),
name: i.name,
displayName: i.displayName,
description: i.description,
relations: mapRelations(i.related, array),
},
type: "custom",
};
});
function mapFields(fields: FieldSchema[]): Field[] {
return fields.map((f) => ({
displayName: f.displayName,
name: f.name,
type: f.typeName,
subType: f.subType,
isGenerated: f.isSystemDefault,
// this is the step where user gonna convert their data so we can do smthg like this
isPrimaryKey: f.name == "guid",
isRelation: f.typeName == "relation",
isUnique: f.isUnique,
isRequired: f.isRequired,
isReadOnly: f.isReadOnly,
}));
}
function mapRelations(
related: Record<string, RelatedDataField>,
array: Schema[]
): Relation[] {
return Object.entries(related).map((r) => {
const label = r[0].split(".")[1]; // input: expenses.categories => output: categories
const { objName } = r[1]; // { objName, name }
return (
{
id: array.find((e) => e.name === objName)?.id + "",
objName,
fieldName: label,
label,
}
);
});
}