web-dev-qa-db-fra.com

Comment envelopper Ant Design avec Styled Components et TypeScript?

Je veux emballer mes composants ant-design avec des composants stylés, je sais que cela est possible ( https://Gist.github.com/samuelcastro/0ff7db4fd54ce2b80cd1c34a85b40c08 ) mais j'ai des difficultés à faire de même avec TypeScript.

C'est ce que j'ai jusqu'ici:

import { Button as AntButton } from 'antd';
import { ButtonProps } from 'antd/lib/button/button';
import styledComponents from 'styled-components';

interface IButtonProps extends ButtonProps {
   customProp: string;
}

export const Button = styledComponents<IButtonProps>(AntButton)`
  // any custom style here
`;

Comme vous pouvez le constater, je définis mon bouton ant-design avec as any afin de le faire fonctionner, sinon je reçois des types incompatibles tels que:

Argument of type 'typeof Button' is not assignable to parameter of
type 'ComponentType<IButtonProps>'.

Type 'typeof Button' is not assignable to type
'StatelessComponent<IButtonProps>'.

Types of property 'propTypes' are incompatible.

 Property 'customProp' is missing in type '{ 
    type: Requireable<string>; 
    shape: Requireable<string>; 
    size: Requireable<string>; 
    htmlType: Requireable<string>; 
    onClick: ...
    etc
 }

Je vous remercie.

Solution:

import { Button as AntButton } from 'antd';
import { NativeButtonProps } from 'antd/lib/button/button';
import * as React from 'react';
import styledComponents from 'styled-components';

export const Button = styledComponents<NativeButtonProps>(props => <AntButton {...props} />)`
    // custom-props
`;
4
Samuel Castro

Les solutions ci-dessus n'ont pas fonctionné pour moi, cela a résolu le problème.

const Button = styled((props: NativeButtonProps) => <AntButton {...props} />)``;
1
Webber

La racine du problème semble être que styled-components s'attend à ce que le composant interne (AntButton) accepte tous les accessoires de l'interface spécifiée (IButtonProps), mais AntButton n'accepte pas customProp. Pour résoudre ce problème, suivez le dernier exemple dans this section de la documentation et utilisez un composant de fonction sans état pour supprimer customProp avant d'appeler AntButton.

export const Button = styledComponents<IButtonProps>(
  ({ customProp, ...rest }) => <AntButton {...rest} />)`
  // any custom style here
`;
1
Matt McCutchen

index.tsx (composant de bouton)

import { Button as AntButton } from 'antd'
import { NativeButtonProps } from 'antd/lib/button/button'
import 'antd/lib/button/style/css'
import * as React from 'react'
import styledComponents from 'styled-components'
import * as colours from '../colours'

const getColour = (props: any) =>
  props.status === 'green'
    ? colours.STATUS_GREEN
    : props.status === 'red'
      ? colours.STATUS_RED
      : props.type === 'primary'
        ? colours.PRIMARY
        : colours.WHITE

export interface ButtonProps extends NativeButtonProps {
  status?: string
}

export default styledComponents((props: ButtonProps) => <AntButton {...props} />)`
  &:focus,
  &:hover
  & {
    background-color: ${getColour};
    border-color: ${getColour};
  }
`
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>

import React from 'react'
import Button, { ButtonProps } from './index'

interface ButtonAsyncSingleSuccessProps extends ButtonProps {
  clickFunc: any, // (...args: any[]) => Promise<any>
  labelLoading: string,
  labelReady: string,
  labelSuccess: string,
}

interface ButtonAsyncSingleSuccessState {
  label: string,
  loading: boolean,
  status: string
}

export default class ButtonAsyncSingleSuccess extends React.Component<
  ButtonAsyncSingleSuccessProps,
  ButtonAsyncSingleSuccessState
> {
  constructor (props: any) {
    super(props)
    this.state = {
      label: props.labelReady,
      loading: false,
      status: ''
    }
  }
  public clickHandler (event: any) {
    const { labelLoading, labelReady, labelSuccess, clickFunc } = this.props
    this.setState({
      label: labelLoading,
      loading: true,
      status: ''
    })
    clickFunc(event)
      .then(() => {
        this.setState({
          label: labelSuccess,
          loading: false,
          status: 'green'
        })
      })
      .catch(() => {
        this.setState({
          label: labelReady,
          loading: false,
          status: 'red'
        })
      })
  }
  public render () {
    const {
      labelLoading,
      labelReady,
      labelSuccess,
      clickFunc,
      ...props
    } = this.props
    const { label, loading, status } = this.state
    if (status === 'red') {
      setTimeout(() => this.setState({ status: '' }), 1000) // flash red
    }
    return (
      <Button
        {...props}
        loading={loading}
        status={status}
        onClick={(e) => this.clickHandler(e)}
      >
        {label}
      </Button>
    )
  }
}

0
Alvin Smith