Giter VIP home page Giter VIP logo

Comments (11)

itsMapleLeaf avatar itsMapleLeaf commented on May 18, 2024 2

I don't really feel personally motivated to implement this. Firstly because it's not documented(?), and ideologically, I feel like using this a lot would lead down an inheritance-heavy path over that favoring composition. An example in case I'm unclear:

// these are only a few classes, but imagine they're way longer, since buttons generally are
const Button = tw.button`...`
const PinkButton = tw(Button)`bg-pink`
const UnderlineButton = tw(Button)`underline`
const PinkUnderlineButton = tw(/* ??? */)` ??? `

// I'd prefer this
const pinkButtonStyle = `bg-pink`
const underlineButtonStyle = `underline`

// then apply them to any element/component
// don't have to make new styled components, or fool around with 'as' prop
<button css={pinkButtonStyle} />
<a css={underlineButtonStyle} />
<Link to="/" css={[pinkButtonStyle, underlineButtonStyle]} />

There are ways around the diamond problem I've pointed out, but with the alternate path here, it's something I don't even have to think about, and I think it aligns more with Tailwind's core philosophy.


That aside, if someone wants to pick up the mantle, I'll gladly review the PR, provided the type tests are also updated

from twin.macro.

ben-rogerson avatar ben-rogerson commented on May 18, 2024 2

Thanks for your thoughts on this Daro.
I agree with your Tailwind alignment points and thanks for alerting me to the lack of documentation on the component wrapping.
I use component wrapping on the regular and actually don't go past a single level 😮
I'm planning to create some TypeScript demos in the future and it would be great to add typescript support for the feature without the workaround.

Edit: I've now documented the wrapping in feature in the readme.

from twin.macro.

rbutera avatar rbutera commented on May 18, 2024 1

attn: @kingdaro

from twin.macro.

A-Shleifman avatar A-Shleifman commented on May 18, 2024 1

As a temporary solution we can declare a modified module:

// twin.d.ts

import { ComponentType } from 'react';
import { TwFn, TemplateFn } from 'twin.macro';

declare module 'twin.macro' {
  type TwComponentWrapper = <T extends ComponentType<any>>(component: T) => TemplateFn<T>;
  const tw: TwFn & TwComponentMap & TwComponentWrapper;
  export = tw;
}

@ben-rogerson, how about updating the type with this?

from twin.macro.

ben-rogerson avatar ben-rogerson commented on May 18, 2024 1

Thanks for looking into this - it all looks good at first glance. I'll aim to release a patch after some testing.

from twin.macro.

aaronbski avatar aaronbski commented on May 18, 2024

+1

from twin.macro.

ben-rogerson avatar ben-rogerson commented on May 18, 2024

I'm keen on adding this but not sure where to start.
Would someone like to submit a PR?

from twin.macro.

rbutera avatar rbutera commented on May 18, 2024

It appears that emotion has an issue related to this that will be fixed in v11: emotion-js/emotion#1823

Perhaps best to look at how v11 handles the types:

// Definitions by: Junyoung Clare Jang <https://github.com/Ailrun>
// TypeScript Version: 3.2

import * as React from 'react'
import { ComponentSelector, Interpolation } from '@emotion/serialize'
import { PropsOf, DistributiveOmit, Theme } from '@emotion/react'

export {
  ArrayInterpolation,
  CSSObject,
  FunctionInterpolation
} from '@emotion/serialize'

export { ComponentSelector, Interpolation }

/** Same as StyledOptions but shouldForwardProp must be a type guard */
export interface FilteringStyledOptions<
  Props,
  ForwardedProps extends keyof Props = keyof Props
> {
  label?: string
  shouldForwardProp?(propName: PropertyKey): propName is ForwardedProps
  target?: string
}

export interface StyledOptions<Props> {
  label?: string
  shouldForwardProp?(propName: PropertyKey): boolean
  target?: string
}

/**
 * @typeparam ComponentProps  Props which will be included when withComponent is called
 * @typeparam SpecificComponentProps  Props which will *not* be included when withComponent is called
 */
export interface StyledComponent<
  ComponentProps extends {},
  SpecificComponentProps extends {} = {}
> extends React.FC<ComponentProps & SpecificComponentProps>, ComponentSelector {
  withComponent<C extends React.ComponentType<React.ComponentProps<C>>>(
    component: C
  ): StyledComponent<ComponentProps & PropsOf<C>>
  withComponent<Tag extends keyof JSX.IntrinsicElements>(
    tag: Tag
  ): StyledComponent<ComponentProps, JSX.IntrinsicElements[Tag]>
}

/**
 * @typeparam ComponentProps  Props which will be included when withComponent is called
 * @typeparam SpecificComponentProps  Props which will *not* be included when withComponent is called
 */
export interface CreateStyledComponent<
  ComponentProps extends {},
  SpecificComponentProps extends {} = {}
> {
  /**
   * @typeparam AdditionalProps  Additional props to add to your styled component
   */
  <AdditionalProps extends {} = {}>(
    ...styles: Array<
      Interpolation<
        ComponentProps &
          SpecificComponentProps &
          AdditionalProps & { theme: Theme }
      >
    >
  ): StyledComponent<ComponentProps & AdditionalProps, SpecificComponentProps>

  (
    template: TemplateStringsArray,
    ...styles: Array<
      Interpolation<ComponentProps & SpecificComponentProps & { theme: Theme }>
    >
  ): StyledComponent<ComponentProps, SpecificComponentProps>

  /**
   * @typeparam AdditionalProps  Additional props to add to your styled component
   */
  <AdditionalProps extends {}>(
    template: TemplateStringsArray,
    ...styles: Array<
      Interpolation<
        ComponentProps &
          SpecificComponentProps &
          AdditionalProps & { theme: Theme }
      >
    >
  ): StyledComponent<ComponentProps & AdditionalProps, SpecificComponentProps>
}

/**
 * @desc
 * This function accepts a React component or tag ('div', 'a' etc).
 *
 * @example styled(MyComponent)({ width: 100 })
 * @example styled(MyComponent)(myComponentProps => ({ width: myComponentProps.width })
 * @example styled('div')({ width: 100 })
 * @example styled('div')<Props>(props => ({ width: props.width })
 */
export interface CreateStyled {
  <
    C extends React.ComponentType<React.ComponentProps<C>>,
    ForwardedProps extends keyof React.ComponentProps<
      C
    > = keyof React.ComponentProps<C>
  >(
    component: C,
    options: FilteringStyledOptions<PropsOf<C>, ForwardedProps>
  ): CreateStyledComponent<Pick<PropsOf<C>, ForwardedProps> & { theme?: Theme }>

  <C extends React.ComponentType<React.ComponentProps<C>>>(
    component: C,
    options?: StyledOptions<PropsOf<C>>
  ): CreateStyledComponent<PropsOf<C> & { theme?: Theme }>

  <
    Tag extends keyof JSX.IntrinsicElements,
    ForwardedProps extends keyof JSX.IntrinsicElements[Tag] = keyof JSX.IntrinsicElements[Tag]
  >(
    tag: Tag,
    options: FilteringStyledOptions<JSX.IntrinsicElements[Tag], ForwardedProps>
  ): CreateStyledComponent<
    { theme?: Theme },
    Pick<JSX.IntrinsicElements[Tag], ForwardedProps>
  >

  <Tag extends keyof JSX.IntrinsicElements>(
    tag: Tag,
    options?: StyledOptions<JSX.IntrinsicElements[Tag]>
  ): CreateStyledComponent<{ theme?: Theme }, JSX.IntrinsicElements[Tag]>
}

declare const styled: CreateStyled
export default styled

from twin.macro.

Vinlock avatar Vinlock commented on May 18, 2024

As a temporary solution we can declare a modified module:

// twin.d.ts

import { ComponentType } from 'react';
import { TwFn, TemplateFn } from 'twin.macro';

declare module 'twin.macro' {
  type TwComponentWrapper = <T extends ComponentType<any>>(component: T) => TemplateFn<T>;
  const tw: TwFn & TwComponentMap & TwComponentWrapper;
  export = tw;
}

@ben-rogerson, how about updating the type with this?

Works great for me so far! Thanks!

from twin.macro.

ben-rogerson avatar ben-rogerson commented on May 18, 2024

I've put up a PR if anyone wants to take a squiz before I merge.

from twin.macro.

ben-rogerson avatar ben-rogerson commented on May 18, 2024

Update to 1.6.0 and all should be good now 🎉

from twin.macro.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.