emotion icon indicating copy to clipboard operation
emotion copied to clipboard

How to set global shouldForwardProp?

Open Enivia opened this issue 1 year ago • 1 comments

The problem

I want to pass some common props(such as dynamic class prefix) to styled component through an HOC, and those props are also passed to dom element.

Proposed solution

Can I have a global shouldForwardProp config or just ignore some props with special charactor prefix?

Alternative solutions

write shouldForwardProp everytime

const EmotionButton = withCommonProps(styled('div', {
  shouldForwardProp: (propName) => propName !== '$prefixCls',
})<WithCommonProps>`
  .${(p) => p.$prefixCls}-error-text {
    color: red;
  }
`)

or put props in theme

function withCommonProps<
  ComponentProps extends {} = {},
  SpecificComponentProps extends {} = {},
  JSXProps extends {} = {}
>(Component: StyledComponent<ComponentProps, SpecificComponentProps, JSXProps>) {
  return forwardRef((props, ref) => {
    const { prefixCls } = useContext(ConfigContext)
    return <Component {...props} ref={ref} theme={{ $prefixCls: prefixCls }} />
  }) as ExoticComponent<ComponentProps & SpecificComponentProps & JSXProps>
}

Additional context

Enivia avatar Aug 14 '23 02:08 Enivia

@Enivia We ended up exporting and using a wrapped version of the styled.

import { default as emotionStyled } from '@emotion/styled';

import { CreateStyled } from '@emotion/styled';

/**
 * Emotion doesn't give the ability to strip out props on convention.
 * Add the behavior back in https://github.com/emotion-js/emotion/issues/2193.
 */

export const styled: CreateStyled = ((...args: Parameters<CreateStyled>) =>
  emotionStyled(args[0], {
    shouldForwardProp: (propName: string) => {
      /** Because we are overriding the `shouldForwardProp` to not forward `$` props,
       * we have to re-implement the default behavior.
       * https://github.com/emotion-js/emotion/blob/b0014b4edc6be047e0a94d8c627d4e52ecccd371/packages/styled/src/utils.js#L40-L47
       * This check retains the default emotion behavior for the 'as' prop, using it for html tags and forwarding it for components.
       * https://emotion.sh/docs/styled#as-prop
       */
      if (propName === 'as') {
        return typeof args[0] === 'string' ? false : true;
      }
// Removing transient props
      return !propName.startsWith('$');
    },
    ...args[1],
  })) as unknown as CreateStyled;

adamdiestelkamp avatar Feb 02 '24 19:02 adamdiestelkamp