Community

How to add your own node

Adding your own node requires a bit of boilerplate and manual work at the moment.

Step 1: creating your own component type

Let's say you want to create your own node type called MyNode. First you need to create a file with it's own class in packages/components/src/YourNode.ts your type must extend the BaseComponent class. Here's an example declaration:

export type MyNodeValueType = number;

export class MyNode extends BaseComponent<MyNodeValueType> {}

Let's now say that your node type will have a configuration panel where you can change some attributes, for now let's say the attributes are a drop-down that let's you choose between happy and sad, and a numeric value we call joy. To be able to contain the values of these attributes you will need a data type associated to your node.

export type EmotionType = 'happy' | 'sad';

export type MyNodeData = {
	emotion: EmotionType;
	joy: number;
};

Add a constructor to your type that takes the attributes and passes them to the superclass. Like this:

constructor(private readonly data: BaseComponentData & MyNodeData) {
	super(data, 0);
}

Step 2: expose your new type in the components packages

  • Include your newly created component in the index.ts file in packages/components. This will make your new components available in the @microflow/components package, so that they can be used later in the electron app.

Step 3: create a react wrapper in the electron app

  • Create a reactflow wrapper for your node type in apps/electron-app/src/common/render/componenets/react-flow/nodes/YourNode.tsx
  • Implement here your JSX
export function MyNode(props: Props) {
	return (
		<NodeContainer {...props}>
			<Value />
			<Settings />
			<Handle type="target" position={Position.Left} id="input" />
			<Handle type="source" position={Position.Right} id="output" />
		</NodeContainer>
	);
}
  • Show how much joy you are in right now
function Value() {
    const value = useNodeValue<MyNodeValueType>(0) // Acces the nodes' internal value
    const data = useNodeData<MyNodeData>() // Access the node data

    return {
        <div>{value} / {data.joy}</div>
    }
}
  • Give the user freedom to configure the node
function Settings() {
	const { pane, settings } = useNodeSettingsPane<MyNodeData>();

	useEffect(() => {
		if (!pane) return;

		pane.addBinding(settings, 'emotion', {
			index: 0,
			view: 'list',
			label: 'validate',
			options: [
				{ value: 'happy', text: 'Happy' },
				{ value: 'sad', text: 'Sad' },
			],
		});

		pane.addBinding(settings, 'joy', {
			index: 1,
			min: 1,
			max: 100,
			step: 0.5,
		});
	}, [pane, settings]);

	return null;
}
  • And your panel data defaults.
type Props = BaseNode<MyNodeData>;
MyNode.defaultProps = {
    data: {
        group: 'flow',
        tags: ['information'],
        label: 'MyNode',
        emotion: 'happy',
        joy: 95,
    } satisfies Props['data'],
};
  • Add a reference in apps/electron-app/src/common/nodes.ts to expose your node to the app.
import { MyNode } from '../render/components/react-flow/nodes/MyNode';

export const NODE_TYPES = {
  ...
  MyNode: MyNode,
  ...
};
Previous
How to contribute