Comments (11)
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.
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.
attn: @kingdaro
from twin.macro.
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.
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.
+1
from twin.macro.
I'm keen on adding this but not sure where to start.
Would someone like to submit a PR?
from twin.macro.
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.
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.
I've put up a PR if anyone wants to take a squiz before I merge.
from twin.macro.
Update to 1.6.0 and all should be good now 🎉
from twin.macro.
Related Issues (20)
- `group-x` classes containing `/` aren't working correctly
- Support for @headlessui/tailwindcss prefixes in inner classes HOT 2
- the name `_GlobalStyles` is defined multiple times HOT 1
- Unable to clone and style existing components with Stitches using standard syntax HOT 3
- Doesn't work with CodeSandbox React template HOT 1
- Error when passing props to the css attribute in solid/stitches HOT 3
- CSS `calc` with more than 2 `theme` keywords HOT 1
- Can't resolve 'v8' (Twin + Next.js + Styled Components) HOT 9
- Twin Macro Doesn't Work With Next.js (A Working Example Would Solve This) HOT 6
- Dynamic is not working as expected in next-emotion-typescript HOT 2
- Module not found: Can't resolve 'v8' HOT 3
- Property 'cs' is missing in type.... HOT 2
- Next 14 layout shift (maybe css load after render) HOT 2
- Jest testing (typescript) - twin_macro_1.theme is not a function HOT 2
- Errors in vite 5.0.0 HOT 1
- TypeScript type error with TwImportComponent in jest-testing-typescript
- CSS fallback values from Tailwind config `extend` are missing HOT 2
- Props don't get passed down when composing components HOT 5
- Custom Tailwind Properties in Twin.macro not working HOT 1
- Storybook v8 not working in combination with Styled Components and twin.macro HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from twin.macro.