Home > OS >  No overload matches for this call, extra custom prop of styled component
No overload matches for this call, extra custom prop of styled component

Time:02-01

No overload matches for this call

For props x, y in StyledContainer, it's throwing "No overload matches for this call".

Here is the main error throwing on build

import React from "react";
import styled, { css } from "styled-components";

interface Props {
  onDragStart?: () => void;
  onDragEnd?: () => void;
  children: React.ReactNode;
  isDragging: boolean;
  x?: number;
  y?: number;
  onDrag?: (position: { translateX: number; translateY: number }) => void;
}
interface State {
  originalX: number;
  originalY: number;
  lastTranslateX: number;
  lastTranslateY: number;
  translateX: number;
  translateY: number;
  isDragging: boolean;
}
export default class EventRecap extends React.Component<Props, State> {
  state = {
    isDragging: false,

    originalX: 0,
    originalY: 0,

    translateX: 0,
    translateY: 0,

    lastTranslateX: 0,
    lastTranslateY: 0,
  };

  componentWillUnmount() {
    window.removeEventListener("mousemove", this.handleMouseMove);
    window.removeEventListener("mouseup", this.handleMouseUp);
  }

  handleMouseDown = ({
    clientX,
    clientY,
  }: {
    clientX: number;
    clientY: number;
  }) => {
    window.addEventListener("mousemove", this.handleMouseMove);
    window.addEventListener("mouseup", this.handleMouseUp);

    if (this.props.onDragStart) {
      this.props.onDragStart();
    }

    this.setState({
      originalX: clientX,
      originalY: clientY,
      isDragging: true,
    });
  };

  handleMouseMove = ({
    clientX,
    clientY,
  }: {
    clientX: number;
    clientY: number;
  }) => {
    const { isDragging } = this.state;
    const { onDrag } = this.props;

    if (!isDragging) {
      return;
    }

    this.setState(
      (prevState) => ({
        translateX: clientX - prevState.originalX   prevState.lastTranslateX,
        translateY: clientY - prevState.originalY   prevState.lastTranslateY,
      }),
      () => {
        if (onDrag) {
          onDrag({
            translateX: this.state.translateX,
            translateY: this.state.translateY,
          });
        }
      },
    );
  };

  handleMouseUp = () => {
    window.removeEventListener("mousemove", this.handleMouseMove);
    window.removeEventListener("mouseup", this.handleMouseUp);

    this.setState(
      {
        originalX: 0,
        originalY: 0,
        lastTranslateX: this.state.translateX,
        lastTranslateY: this.state.translateY,

        isDragging: false,
      },
      () => {
        if (this.props.onDragEnd) {
          this.props.onDragEnd();
        }
      },
    );
  };

  render() {
    const { children } = this.props;
    const { translateX, translateY, isDragging } = this.state;
    return (
      <StyledContainer
        x={translateX}
        y={translateY}
        isDragging={isDragging}
        onm ouseDown={this.handleMouseDown}
      >
       {children}
  
      </StyledContainer>
    );
  }
}

const StyledContainer = styled.div.attrs<Props>((props) => ({
  style: { transform: `translate(${props.x}px, ${props.y}px)` },
}))`
  cursor: grab;
  ${({ isDragging }: { isDragging: boolean }) =>
    isDragging &&
    css`
      opacity: 0.8;
      cursor: grabbing;
    `};
`;

CodePudding user response:

Instead of using attributes merging with styled.div.attrs<Props>, directly use custom props so that they are exposed as the styled component props definition as well:

// Add the custom Props as a TypeScript type argument to styled.div
// https://styled-components.com/docs/api#using-custom-props
const StyledContainer2 = styled.div<Props>`
  cursor: grab;
  /* Directly adapt style based on props, instead of merging attributes
  https://styled-components.com/docs/basics#adapting-based-on-props */
  transform: ${(props) => css`translate(${props.x}px, ${props.y}px)`};
  ${({
    // No need to redefine type, it is directly taken from the custom props type argument of styled.div
    isDragging
  }) =>
    isDragging
      ? css`
          opacity: 0.8;
          cursor: grabbing;
        `
      : ""};
`;

Then you can use these props directly inside the style block and adapt style based on props (instead of the attributes merging).

Another advantage is that the props typing is directly available when you interpolate your function, so there is no need to redefine the props type.

Demo: https://codesandbox.io/s/laughing-rgb-oomc6n?file=/src/App.tsx:330-972

  • Related