projectstorm / react-diagrams

a super simple, no-nonsense diagramming library written in react that just works
https://projectstorm.cloud/react-diagrams
MIT License
8.51k stars 1.17k forks source link

The Action typing forces consuming project to not use strict=true #863

Open rkesters opened 3 years ago

rkesters commented 3 years ago

If a consuming project uses the following from the DEMO project and that project has strict=true, then it will not compile.

export class CreateLinkState extends State<DiagramEngine> {
    sourcePort: PortModel;
    link: LinkModel;

    constructor() {
        super({ name: 'create-new-link' });

        this.registerAction(
            new Action({
                type: InputType.MOUSE_UP,
                fire: (actionEvent: ActionEvent<MouseEvent>) => {
                    const element = this.engine.getActionEventBus().getModelForEvent(actionEvent);
                    const {
                        event: { clientX, clientY }
                    } = actionEvent;
                    const ox = this.engine.getModel().getOffsetX();
                    const oy = this.engine.getModel().getOffsetY();

                    if (element instanceof PortModel && !this.sourcePort) {
                        this.sourcePort = element;

                        /* would be cool if link creating could be done somewhat like
                        const link = createLink({
                            sourcePort: this.sourcePort,
                            points: [{ x: clientX, y: clientY }, { x: clientX, y: clientY }]
                        })
                        */
                        const link = this.sourcePort.createLinkModel();
                        link.setSourcePort(this.sourcePort);
                        link.getFirstPoint().setPosition(clientX - ox, clientY - oy);
                        link.getLastPoint().setPosition(clientX - ox + 20, clientY - oy + 20);

                        this.link = this.engine.getModel().addLink(link);
                    } else if (element instanceof PortModel && this.sourcePort && element != this.sourcePort) {
                        if (this.sourcePort.canLinkToPort(element)) {
                            this.link.setTargetPort(element);
                            element.reportPosition();
                            this.clearState();
                            this.eject();
                        }
                    } else if (element === this.link.getLastPoint()) {
                        this.link.point(clientX - ox, clientY - oy, -1);
                    }

                    this.engine.repaintCanvas();
                }
            })
        );

        this.registerAction(
            new Action({
                type: InputType.MOUSE_MOVE,
                fire: (actionEvent: ActionEvent<React.MouseEvent>) => {
                    if (!this.link) return;
                    const { event } = actionEvent;
                    this.link.getLastPoint().setPosition(event.clientX, event.clientY);
                    this.engine.repaintCanvas();
                }
            })
        );

        this.registerAction(
            new Action({
                type: InputType.KEY_UP,
                fire: (actionEvent: ActionEvent<KeyboardEvent>) => {
                    // on esc press remove any started link and pop back to default state
                    if (actionEvent.event.keyCode === 27) {
                        this.link.remove();
                        this.clearState();
                        this.eject();
                        this.engine.repaintCanvas();
                    }
                }
            })
        );
    }

    clearState() {
        this.link = undefined;
        this.sourcePort = undefined;
    }
}

The problem is the way that the fire type is defined.

Changing the definition to

export interface ActionOptionsMouse{
    type: InputType.MOUSE_DOWN | InputType.MOUSE_MOVE | InputType.MOUSE_UP;
    fire: (event: ActionEvent<MouseEvent>) => void;
}
export interface ActionOptionsWheel{
    type: InputType.MOUSE_WHEEL;
    fire: (event: ActionEvent<WheelEvent>) => void;
}

export interface ActionOptionsKeyboard{
    type: InputType.KEY_DOWN | InputType.KEY_UP;
    fire: (event: ActionEvent<KeyboardEvent>) => void;
}
export interface ActionOptionsTouch{
    type: InputType.TOUCH_END | InputType.TOUCH_MOVE | InputType.TOUCH_START;
    fire: (event: ActionEvent<TouchEvent>) => void;
}

type ActionOptions = ActionOptionsMouse | ActionOptionsWheel | ActionOptionsKeyboard  | ActionOptionsTouch

Ensures that is works with strict type checking.