import React from 'react' ; import { mergeProps } from './mergeProps' ; import { Model } from './models' ; /**
 * Adds the `as` to the style interface to support `as` in styled components
 * This type and usage should be removed with Emotion 11
 */ export type StyledType = { as ? : React . ElementType ; } ; /**
 * Extract a Ref from T if it exists
 * This will return the following:
 *
 * - `undefined` => `never`
 * - `'button'` => `React.Ref<HTMLButtonElement>`
 * - `ElementComponent<'button', ButtonProps>` => `React.Ref<HTMLButtonElement>`
 */ type ExtractRef < T > = T extends undefined ? never : React . Ref < T extends keyof ElementTagNameMap ? ElementTagNameMap [ T ] : T extends ElementComponent < infer U , any > ? U extends keyof ElementTagNameMap ? ElementTagNameMap [ U ] : U : T > ; template P template ElementType export type PropsWithAs < P , ElementType extends React . ElementType > = P & Omit < React . ComponentProps < ElementType > , 'as' | 'state' | keyof P > & { /**
     * Optional ref. If the component represents an element, this ref will be a reference to the
     * real DOM element of the component. If `as` is set to an element, it will be that element.
     * If `as` is a component, the reference will be to that component (or element if the component
     * uses `React.forwardRef`).
     */ ref ? : ExtractRef < ElementType > ; } ; /**
 * Extracts only the HTML attribute interface from `JSX.IntrinsicElements[E]`. This effectively removes `ref` and `key`
 * without using `Omit` which makes the returned type more difficult to understand.
 *
 * For example:
 * JSX.IntrinsicElements['button'] // React.ClassAttributes<HTMLButtonElement> & React.ButtonHTMLAttributes<HTMLButtonElement>
 * ExtractHTMLAttributes<JSX.IntrinsicElements['button']> // React.HTMLButtonAttributes<HTMLButtonElement>
 */ type ExtractHTMLAttributes < T extends React . DetailedHTMLProps < any , any > > = T extends React . DetailedHTMLProps < infer P , any > ? P : T ; template TComponent template TElement example export type ExtractProps < TComponent , TElement extends keyof JSX . IntrinsicElements | ElementComponent < any , any > | Component < any > | React . ComponentType < any > | undefined | never = undefined > = TComponent extends ElementComponent < infer E , infer P > ? [ TElement ] extends [ never ] ? P : TElement extends undefined ? E extends keyof JSX . IntrinsicElements ? P & ExtractHTMLAttributes < JSX . IntrinsicElements [ E ] > : P & ExtractPropsFromComponent < E > : TElement extends keyof JSX . IntrinsicElements ? P & ExtractHTMLAttributes < JSX . IntrinsicElements [ TElement ] > : P & ExtractPropsFromComponent < TElement > : ExtractPropsFromComponent < TComponent > ; type ExtractPropsFromComponent < TComponent > = TComponent extends ElementComponent < infer E , infer P > ? E extends keyof JSX . IntrinsicElements ? P & ExtractHTMLAttributes < JSX . IntrinsicElements [ E ] > : P : TComponent extends Component < infer P > ? P : TComponent extends React . ComponentType < infer P > ? P : { } ; /**
 * Component type that allows for `as` to change the element or component type.
 * Passing `as` will correctly change the allowed interface of the JSX element
 */ export type ElementComponent < T extends React . ElementType , P > = { __type : 'ElementComponent' ; < ElementType extends React . ElementType > ( props ) : JSX . Element ; ( props ) : JSX . Element ; displayName ? : string ; as < E extends React . ElementType > ( as ) : ElementComponent < E , P > ; } ; export type Component < P > = { __type : 'Component' ; ( props ) : JSX . Element ; displayName ? : string ; } ; interface RefForwardingComponent < T , P = { } > { ( props , /**
     * A ref to be forwarded. Pass it along to the root element. If no element was passed, this
     * will result in a `never`
     */ ref , /**
     * An element - either a JSX element or a `ElementComponent`. This should be passed as an `as`
     * to a root element or be the root element. If no element was passed, this will result in a
     * `never`
     */ Element ) : React . ReactElement | null ; } /**
 * Factory function that creates components to be exported. It enforces React ref forwarding, `as`
 * prop, display name, and sub-components, and handles proper typing without much boiler plate. The
 * return type is `Component<element, Props>` which looks like `Component<'div', Props>` which is a
 * clean interface that tells you the default element that is used.
 */ export const createComponent = < E extends keyof JSX . IntrinsicElements | React . ComponentType | ElementComponent < any , any > | undefined = undefined > ( as ? ) => < P , SubComponents = { } > ( { displayName , Component , subComponents , } ) : ( E extends undefined ? Component < P > : ElementComponent < E extends undefined ? React . FC : E , P > ) & SubComponents => { const ReturnedComponent = React . forwardRef < E , P & { as ? : React . ElementType ; } > ( ( { as : asOverride , ... props } , ref ) => { return Component ( props as P , ref as ExtractRef < E > , ( asOverride || as ) as any ) ; } ) ; Object . keys ( subComponents || { } ) . forEach ( key => { ( ReturnedComponent as Record < string , any > ) [ key ] = ( subComponents as Record < string , any > ) [ key ] ; } ) ; ReturnedComponent . displayName = displayName ; ( ReturnedComponent as any ) . as = ( as ) => createComponent ( as ) ( { displayName , Component , subComponents } ) ; return ReturnedComponent as any ; } ; example param fn export const createHook = < M extends Model < any , any > , PO extends { } , PI extends { } > ( fn ) : BehaviorHook < M , PO > => { return ( model , elemProps , ref ) => { const props = mergeProps ( fn ( model , ref , elemProps || ( { } as any ) ) , elemProps || ( { } as any ) ) ; if ( ! props . hasOwnProperty ( 'ref' ) && ref ) { props . ref = ref ; } return props ; } ; } ; export const subModelHook = < M extends Model < any , any > , SM extends Model < any , any > , O extends { } > ( fn , hook ) : BehaviorHook < M , O > => { return ( model , props , ref ) => { return hook ( fn ( model ) , props , ref ) ; } ; } ; export type BehaviorHook < M extends Model < any , any > , O extends { } > = { bivarianceHack < P extends { } , R > ( model , elemProps ? , ref ? ) : O & P & ( R extends HTMLOrSVGElement ? { ref : React . Ref < R > ; } : { } ) ; } [ 'bivarianceHack' ] ; function setRef < T > ( ref , value ) { if ( ref ) { if ( typeof ref === 'function' ) { ref ( value ) ; } else { ( ref as React . MutableRefObject < T > ) . current = value ; } } } example export function useForkRef < T > ( ref1 ? , ref2 ? ) { return ( value ) => { setRef ( ref1 , value ) ; setRef ( ref2 , value ) ; } ; } param ref example export function useLocalRef < T > ( ref ? ) { const localRef = React . useRef < T > ( null ) ; const elementRef = useForkRef ( ref , localRef ) ; return { localRef , elementRef } ; } param model param config param modelHook example export function useDefaultModel < T , C > ( model , config , modelHook ) { return model || modelHook ( config ) ; } param model param context example export function useModelContext < T > ( context , model ? ) { return model || React . useContext ( context ) ; } example export function composeHooks < M extends Model < any , any > , O1 extends { } , O2 extends { } > ( hook1 , hook2 ) ; export function composeHooks < M extends Model < any , any > , R , P extends { } , O1 extends { } , O2 extends { } , O3 extends { } > ( hook1 , hook2 , hook3 ) ; export function composeHooks < M extends Model < any , any > , R , P extends { } , O1 extends { } , O2 extends { } , O3 extends { } , O4 extends { } > ( hook1 , hook2 , hook3 , hook4 ) ; export function composeHooks < M extends Model < any , any > , R , P extends { } , O1 extends { } , O2 extends { } , O3 extends { } , O4 extends { } , O5 extends { } > ( hook1 , hook2 , hook3 , hook4 , hook5 ) ; export function composeHooks < M extends Model < any , any > , R , P extends { } , O extends { } > ( ... hooks ) { return ( model , props , ref ) => { const returnProps = [ ... hooks ] . reverse ( ) . reduce ( ( props , hook ) => { return hook ( model , props , props . ref || ref ) ; } , props ) ; if ( ! returnProps . hasOwnProperty ( 'ref' ) && ref ) { returnProps . ref = ref ; } return returnProps ; } ; }