import { ComponentType , createElement , forwardRef , ForwardRefExoticComponent , Fragment , PropsWithChildren , PropsWithoutRef , PropsWithRef , Ref , RefAttributes , useCallback , useContext , useMemo , } from 'react' ; import { isElementLikeType , StyledElementLike } from './apply-class-name' ; import { SECRET_GLITZ_PROPERTY } from './constants' ; import { isElementType , StyledElement , StyledElementProps } from './predefined' ; import useGlitz , { DirtyStyle , sanitizeStyle } from './use-glitz' ; import { ComposeContext , emptyComposeContext , GlitzContext , StreamContext } from '../components/context' ; import { isForwardStyleType , StyledForwardStyle , WithoutCompose } from './forward-style' ; export interface StyledComponent < TProps > extends ForwardRefExoticComponent < ExternalProps < TProps > > { [ SECRET_GLITZ_PROPERTY ] ( style ? ) : StyledComponent < TProps > ; } export interface StyledComponentWithRef < TProps , TInstance > extends ForwardRefExoticComponent < WithRefProp < ExternalProps < TProps > , TInstance > > { [ SECRET_GLITZ_PROPERTY ] ( style ? ) : StyledComponentWithRef < TProps , TInstance > ; } export type WithRefProp < TProps , TInstance > = PropsWithoutRef < TProps > & RefAttributes < TInstance > ; export type WithoutRefProp < TProps > = TProps extends PropsWithRef < TProps > ? PropsWithoutRef < TProps > : TProps ; export type ExternalProps < TProps > = PropsWithChildren < TProps & { css ? : DirtyStyle ; } > ; export default function createComponent < TProps > ( type , statics ) ; export default function createComponent < TProps , TInstance > ( type , statics ) { return isStyledComponent < TProps , TInstance > ( type ) ? type [ SECRET_GLITZ_PROPERTY ] ( statics ) : factory ( type , statics ) ; } export function factory < TProps , TInstance > ( type , statics ) { const Component = isElementType ( type ) || isElementLikeType < TProps , TInstance > ( type ) ? forwardRef ( ( { css : dynamic , ... restProps } , ref ) => { const composed = useContext ( ComposeContext ) ; const className = combineClassNames ( ( restProps as any ) . className , useGlitz ( [ statics , dynamic , composed ] ) ) ; let node = createElement < any > ( type . value , { ... restProps , className , ref , } ) ; if ( composed && restProps . children ) { node = createElement ( ComposeContext . Provider , emptyComposeContext , node ) ; } const stream = useContext ( StreamContext ) ; const glitz = useContext ( GlitzContext ) ; if ( stream && glitz && 'getStyle' in glitz ) { const style = glitz . getStyle ( false , true ) ; if ( style ) { node = createElement ( Fragment , null , createElement ( 'style' , { [ `data-${ glitz . identifier }` ] : '' , dangerouslySetInnerHTML : { __html : style } , } ) , node ) ; } } return node ; } ) : isForwardStyleType < TProps , TInstance > ( type ) ? forwardRef ( ( { css : dynamic , ... restProps } , ref ) => { const composed = useContext ( ComposeContext ) ; const compose = useCallback ( additional => sanitizeStyle ( [ additional , statics , dynamic , composed ] ) , [ composed , dynamic ] ) ; let node = createElement < any > ( type . value , { ... restProps , compose , ref } ) ; if ( composed && restProps . children ) { node = createElement ( ComposeContext . Provider , emptyComposeContext , node ) ; } return node ; } ) : forwardRef ( ( { css : dynamic , ... restProps } , ref ) => { const composed = useContext ( ComposeContext ) ; const style = sanitizeStyle ( [ statics , dynamic , composed ] ) ; let node = createElement < any > ( type , { ... restProps , ref } ) ; if ( style . length > 0 ) { node = createElement ( ComposeContext . Provider , useMemo ( ( ) => ( { value : style } ) , [ statics , dynamic , composed ] ) , node ) ; } return node ; } ) ; const Styled = Object . assign ( Component , { [ SECRET_GLITZ_PROPERTY ] ( additionals ? ) { const NewStyled = factory ( type , [ statics , additionals ] ) ; if ( Component . defaultProps ) { NewStyled . defaultProps = { } ; for ( const name in Component . defaultProps ) { ( NewStyled . defaultProps as any ) [ name ] = ( Component . defaultProps as any ) [ name ] ; } } if ( process . env . NODE_ENV !== 'production' ) { NewStyled . displayName = Component . displayName ; } return NewStyled ; } , } ) as any ; if ( process . env . NODE_ENV !== 'production' ) { if ( ! isForwardStyleType < TProps , TInstance > ( type ) ) { const inner = isElementType ( type ) || isElementLikeType < TProps , TInstance > ( type ) ? type . value : type ; Styled . displayName = `Styled(${ typeof inner === 'string' ? inner : inner . displayName || inner . name || 'Unknown' })` ; } } return Styled ; } function combineClassNames ( a , b ) { return a && b ? `${ a } ${ b }` : a ? a : b ; } export function isStyledComponent < TProps , TInstance > ( type ) { return typeof type [ SECRET_GLITZ_PROPERTY ] === 'function' ; }