antonioru / beautiful-react-diagrams

💎 A collection of lightweight React components and hooks to build diagrams with ease 💎
https://antonioru.github.io/beautiful-react-diagrams/
MIT License
2.67k stars 175 forks source link

Typescript with custom Nodes #133

Open kresli opened 3 years ago

kresli commented 3 years ago

Describe the bug Type definition for ports doesn't extends React.DetailedReactHTMLElement which makes createSchema throw error

To Reproduce

import { createSchema } from "beautiful-react-diagrams";
import React from "react";

const CustomNode = (props: {
  inputs?: React.DetailedReactHTMLElement<any, any>[];
}) => {
  const { inputs } = props;

  return (
    <div style={{ background: "#717EC3", borderRadius: "10px" }}>
      <div style={{ padding: "10px", color: "white" }}>Custom Node</div>
      <div style={{ marginTop: "20px" }}>
        {inputs?.map((port) =>
          React.cloneElement(port, {
            style: { width: "50px", height: "25px", background: "#1B263B" }
          })
        )}
      </div>
    </div>
  );
};

createSchema({
  nodes: [
    {
      id: "node-1",
      content: "Node 1",
      coordinates: [150, 60],
      outputs: [{ id: "port-1", alignment: "right" }]
    },
    {
      id: "node-custom",
      coordinates: [250, 60],
      render: CustomNode, // <-- ERROR
      inputs: [{ id: "custom-port-1", alignment: "left" }]
    }
  ]
});

Expected behavior not to throw error

Screenshots

image

Additional context live preview: https://codesandbox.io/s/beautiful-react-diagram-ts-error-vxw5h

kresli commented 3 years ago

I guess we could do something like this?

export type Node<P> = {
  id: string;
  coordinates: NodeCoordinates;
  disableDrag?: boolean;
  content?: ReactNode;
  inputs?: Port[];
  outputs?: Port[];
  type?: "default";
  render?: NodeFunctionalComponent<P>;
  className?: string;
  data?: P;
};

interface IO<P> {
  inputs: DetailedReactHTMLElement<P, any>[];
  outputs: DetailedReactHTMLElement<P, any>[];
}

export type NodeFunctionalComponent<P> = (
  props: Omit<Node<P>, "coordinates" | "inputs" | "outputs"> & IO<P>
) => ElementType | ReactNode;

which let us type the functional component as

const CustomNode: NodeFunctionalComponent<{}> = () => <div></div>

or we could do small modification

export type NodeProps<P> = Omit<Node<P>, "coordinates" | "inputs" | "outputs"> & IO<P>;
export type NodeFunctionalComponent<P> = (
  props: NodeProps<P>
) => ElementType | ReactNode;

which let us do

const CustomNode: React.FunctionalComponent<NodeProps<{}>> = () => <div></div>
kresli commented 3 years ago

OK I see there is a PR to fix that https://github.com/beautifulinteractions/beautiful-react-diagrams/pull/91