import React from 'react'; import { MergeProps, RemoveNulls } from './mergeProps'; import { Model } from './models'; /** * Adds the `as` to the style interface to support `as` in styled components */ export type StyledType = { as?: React.ElementType; }; type Constructor = new (...args: any[]) => T; /** * Extract a Ref from T if it exists * This will return the following: * * - `undefined` => `never` * - `'button'` => `React.Ref` * - `ElementComponent<'button', ButtonProps>` => `React.Ref` */ type ExtractRef = T extends undefined ? never : T extends Constructor ? React.LegacyRef : React.Ref ? U extends keyof ElementTagNameMap ? ElementTagNameMap[U] : U : T extends React.FC<{ ref?: infer R; }> ? R extends React.RefObject ? E : never : T>; /** * Generic component props with "as" prop * @template P Additional props * @template ElementType React component or string element */ export type PropsWithoutAs = P & Omit, 'as' | 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; }; /** * 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 & React.ButtonHTMLAttributes * ExtractHTMLAttributes // React.HTMLButtonAttributes */ type ExtractHTMLAttributes> = T extends React.DetailedHTMLProps ? P : T; /** * Extract props from any component that was created using `createComponent`. It will return the * HTML attribute interface of the default element used with `createComponent`. If you use `as`, the * HTML attribute interface can change, so you can use an override to the element you wish to use. * You can also disable the HTML attribute by passing `never`: * * - `ExtractProps`: `CardProps & React.HTMLAttributes` * - `ExtractProps`: `CardProps & React.HTMLAttributes` * - `ExtractProps`: `CardProps` * * @template TComponent The component you wish to extract props from. Needs 'typeof` in front: * `typeof Card` * @template TElement An optional override of the element that will be used. Define this if you use * an `as` on the component * * @example * interface MyProps extends ExtractProps {} * * ExtractProps; // CardProps & React.HTMLAttributes * ExtractProps; // CardProps & React.HTMLAttributes * ExtractProps; // CardProps */ export type ExtractProps | Component | React.ComponentType | undefined | never = undefined> = ExtractMaybeModel : P & ExtractProps : TElement extends keyof JSX.IntrinsicElements ? P & ExtractHTMLAttributes : P & ExtractProps : TComponent extends { __props: infer P; } ? P : TComponent extends React.ComponentType ? P : {}>; type ExtractMaybeModel = TComponent extends { __model: infer M; } ? P & PropsWithModel : P; /** * `PropsWithModel` adds the `model` and `elemPropsHook` props. If a model-based component has an * `as` referencing another model-based component, the `model` of the `as` component should win. */ export type PropsWithModel = { /** * Optional model to pass to the component. This will override the default model created for the * component. This can be useful if you want to access to the state and events of the model, or if * you have nested components of the same type and you need to override the model provided by * React Context. */ model?: ElementType extends { __model: infer M; } ? M : TModel; /** * Optional hook that receives the model and all props to be applied to the element. If you use * this, it is your responsibility to return props, merging as appropriate. For example, returning * an empty object will disable all elemProps hooks associated with this component. This allows * finer control over a component without creating a new one. */ elemPropsHook?: (model: TModel, elemProps: TProps) => any; }; /** * 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 = { displayName?: string; (props: PropsWithoutAs & { /** * Optional override of the default element used by the component. Any valid tag or Component. * If you provided a Component, this component should forward the ref using `React.forwardRef` * and spread extra props to a root element. */ as: ElementType; }): JSX.Element; (props: PropsWithoutAs): JSX.Element; as(as: E): ElementComponent; /** @private Only used internally to hold the element type for extraction */ __element: E; /** @private Only used internally to hold the element type for extraction */ __props: 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. * Same as `ElementComponent`, but adds a model to the interface. */ export type ElementComponentM = { displayName?: string; (props: PropsWithoutAs & PropsWithModel & { /** * Optional override of the default element used by the component. Any valid tag or Component. * If you provided a Component, this component should forward the ref using `React.forwardRef` * and spread extra props to a root element. */ as: ElementType; }): JSX.Element; (props: PropsWithoutAs & PropsWithModel): JSX.Element; as(as: E): ElementComponentM; /** @private Only used internally to hold the element type for extraction */ __element: E; /** @private Only used internally to hold the element type for extraction */ __props: P; /** @private Only used internally to hold the element type for extraction */ __model: TModel; }; export type ComponentM = { displayName?: string; (props: P & PropsWithModel): JSX.Element; /** @private Only used internally to hold the element type for extraction */ __props: P; /** @private Only used internally to hold the element type for extraction */ __model: TModel; }; export type Component

= { displayName?: string; (props: P): JSX.Element; /** @private Only used internally to hold the element type for extraction */ __props: P; }; interface RefForwardingComponent { (props: React.PropsWithChildren

, /** * A ref to be forwarded. Pass it along to the root element. If no element was passed, this * will result in a `never` */ ref: ExtractRef, /** * 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: T extends undefined ? never : T): JSX.Element | null; } export declare const createContainer: | React.ComponentType<{}> | ElementComponentM | undefined = undefined>(as?: E | undefined) => Model) & { Context?: React.Context | undefined; } & { defaultConfig?: Record | undefined; }, TDefaultContext extends Model, TElemPropsHook, SubComponents = {}>({ displayName, modelHook, elemPropsHook, defaultContext, subComponents, }: { displayName?: string | undefined; modelHook: TModelHook; elemPropsHook?: TElemPropsHook | undefined; defaultContext?: TDefaultContext | undefined; subComponents?: SubComponents | undefined; }) => (Component: (props: CompoundProps, Element: E extends undefined ? never : E, model: TModelHook extends (config: infer TConfig) => infer TModel ? TModel : never) => JSX.Element | null) => (TModelHook extends (config: infer TConfig_1) => infer TModel_1 ? E extends undefined ? ComponentM : ElementComponentM : E, Props & TConfig_1, TModel_1> : never) & SubComponents; /** * If elemProps returns `null` for a prop, that prop is to be removed from the prop * list. This is useful for passing props to an elemProp hook that should not be exposed * to the DOM element */ type RemoveNull = { [K in keyof T]: Exclude; }; /** * Props for the compound component based on props, elemPropsHook, and element. It will * return a prop interface according to all these inputs. The following will be added to * the passed in `Props` type: * - The prop interface returned by the `elemPropsHook` function * - if there is no detected `ref` in the `Props` interface, a `ref` will be added based on the element type E * - if there is no detected `children` in the `Props` interface, `children` will be added based on `ReactNode` */ type CompoundProps = Props & (TElemPropsHook extends (...args: any[]) => infer TProps ? RemoveNull & { ref: ExtractRef; }> : { ref: ExtractRef; }) & (Props extends { children: any; } ? {} : { children?: React.ReactNode; }); export declare const createSubcomponent: | React.ComponentType<{}> | ElementComponentM | undefined = undefined>(as?: E | undefined) => Model) & { Context?: React.Context | undefined; }, SubComponents = {}>({ displayName, modelHook, elemPropsHook, subComponents, }: { /** @deprecated ⚠️ `displayName` has been deprecated and will be removed in a future major version. You no longer need to use `displayName`. A `displayName` will be automatically added if it belongs to a container. */ displayName?: string | undefined; modelHook: TModelHook; elemPropsHook?: TElemPropsHook | undefined; subComponents?: SubComponents | undefined; }) => (Component: (props: CompoundProps, Element: E extends undefined ? never : E, model: TModelHook extends (...args: any[]) => infer TModel ? TModel : never) => JSX.Element | null) => (TModelHook extends (...args: any[]) => infer TModel_1 ? ElementComponentM : E, Props, TModel_1> : never) & SubComponents; /** * 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` which looks like `Component<'div', Props>` which is a * clean interface that tells you the default element that is used. */ export declare const createComponent: | React.ComponentType<{}> | undefined = undefined>(as?: E | undefined) => ({ displayName, Component, subComponents, }: { /** This is what the component will look like in the React dev tools. Encouraged to more easily * understand the component tree */ displayName?: string | undefined; /** The component function. The function looks like: * @example * Component: ({children}, ref, Element) { * // `Element` is what's passed to the `as` of your component. If no `as` was defined, it * // will be the default element. It will be 'div' or even a another Component! * return ( * {children} * ) * } * * @example * Component: ({children}, ref, Element) { * // `Element` can be passed via `as` to the next component * return ( * {children} * ) * } */ Component: RefForwardingComponent; /** * Used in container components */ subComponents?: SubComponents | undefined; }) => (E extends undefined ? Component

: ElementComponent : E, P>) & SubComponents; /** * An `elemPropsHook` is a React hook that takes a model, ref, and elemProps and returns props and * attributes to be spread to an element or component. * * ```tsx * const useMyHook = createElemPropsHook(useMyModel)((model) => { * return { * id: model.state.id * } * }) * ``` * * **Note:** If your hook needs to use a ref, it must be forked using `useLocalRef` or `useForkRef` * and return the forked ref: * * ```tsx * const useMyHook = createElemPropsHook(useMyModel)((model, ref, elemProps) => { * const {localRef, elementRef} = useLocalRef(ref); * * React.useLayoutEffect(() => { * console.log('element', localRef.current) // logs the DOM element * }, []) * * return { * ref: elementRef * } * }) * ``` */ export declare const createElemPropsHook: Model>(modelHook: TModelHook) => (fn: (model: TModelHook extends (config: any) => infer TModel ? TModel : Model, ref?: React.Ref, elemProps?: PI | undefined) => PO) => BehaviorHook infer TModel_1 ? TModel_1 : Model, PO>; /** * Factory function to crate a behavior hook with correct generic types. It takes a function that * return props and returns a function that will also require `elemProps` and will call `mergeProps` for * you. If your hook makes use of the `ref`, you will have to also use `useLocalRef` to properly fork * the ref. * * @example * const useMyHook = createHook((model: MyModel, ref) => { * const { localRef, elementRef } = useLocalRef(ref); * // do whatever with `localRef` which is a RefObject * * return { * onClick: model.events.doSomething, * ref: elementRef, * }; * }); * * // Equivalent to: * const useMyHook =

( * model: MyModel, * elemProps: P, * ref: React.Ref * ) => { * const { localRef, elementRef } = useLocalRef(ref); * // do whatever with `localRef` which is a RefObject * * return mergeProps({ * onClick: model.events.doSomething, * ref: elementRef, * }, elemProps); * }; * * @param fn Function that takes a model and optional ref and returns props */ export declare const createHook: , PO extends {}, PI extends {}>(fn: (model: M, ref?: React.Ref, elemProps?: PI | undefined) => PO) => BehaviorHook; /** * @deprecated ⚠️ `subModelHook` has been deprecated and will be removed in a future major version. Please use `createSubModelElemPropsHook` instead. */ export declare const subModelHook: , SM extends Model, O extends {}>(fn: (model: M) => SM, hook: BehaviorHook) => BehaviorHook; /** * Creates an elemPropsHook that returns the elemProps from another hook that is meant for a * subModel. Usually only used when composing elemProps hooks. * * For example: * * ```tsx * const useMySubModel = () => {} * * const useMyModel = () => { * const subModel = useMySubModel() * * return { * state, * events, * subModel, * } * } * * const useMyComponent = composeHook( * createElemPropsHook(useMyModel)(model => ({ id: '' })), * createSubModelElemPropsHook(useMyModel)(m => m.subModel, useSomeOtherComponent) * ) * ``` */ export declare function createSubModelElemPropsHook Model>(modelHook: M): , O extends {}>(fn: (model: ReturnType) => SM, elemPropsHook: BehaviorHook) => BehaviorHook, O>; /** Simplify and speed up inference by capturing types in the signature itself */ interface BaseHook, O extends {}> { /** * Capture the model type in TypeScript only. Do not use in runtime! * * @private */ __model: M; /** * Capture the hook's output type in TypeScript only. Do not use in runtime! This is used to cache * and speed up the output types during inference * * @private */ __output: O; } /** * A BehaviorHook is a React hook that takes a model, elemProps, and a ref and returns props and * attributes to apply to an element or component. */ export interface BehaviorHook, O extends {}> extends BaseHook {

(model: M, elemProps?: P, ref?: React.Ref): O & P; } /** * This function will create a new forked ref out of two input Refs. This is useful for components * that use `React.forwardRef`, but also need internal access to a Ref. * * This function is inspired by https://www.npmjs.com/package/@rooks/use-fork-ref * * @example * React.forwardRef((props, ref) => { * // Returns a RefObject with a `current` property * const myRef = React.useRef(ref) * * // Returns a forked Ref function to pass to an element. * // This forked ref will update both `myRef` and `ref` when React updates the element ref * const elementRef = useForkRef(ref, myRef) * * useEffect(() => { * console.log(myRef.current) // `current` is the DOM instance * // `ref` might be null since it depends on if someone passed a `ref` to your component * // `elementRef` is a function and we cannot get a current value out of it * }) * * return

* }) */ export declare function useForkRef(ref1?: React.Ref, ref2?: React.Ref): React.RefCallback; /** * This functions handles the common use case where a component needs a local ref and needs to * forward a ref to an element. * @param ref The React ref passed from the `createComponent` factory function * * @example * const MyComponent = ({children, ...elemProps}: MyProps, ref, Element) => { * const { localRef, elementRef } = useLocalRef(ref); * * // do something with `localRef` which is a `RefObject` with a `current` property * * return * } */ export declare function useLocalRef(ref?: React.Ref): { localRef: React.RefObject; elementRef: (instance: T | null) => void; }; /** * Returns a model, or calls the model hook with config. Clever way around the conditional React * hook ESLint rule. * @param model A model, if provided * @param config Config for a model * @param modelHook A model hook that takes valid config * @example * const ContainerComponent = ({children, model, ...config}: ContainerProps) => { * const value = useDefaultModel(model, config, useContainerModel); * * // ... * } */ export declare function useDefaultModel(model: T | undefined, config: C, modelHook: (config: C) => T, as?: React.ElementType): T; /** * Returns a model, or returns a model context. Clever way around the conditional React hook ESLint * rule * @param model A model, if provided * @param context The context of a model * @example * const SubComponent = ({children, model, ...elemProps}: SubComponentProps, ref, Element) => { * const {state, events} = useModelContext(model, SubComponentModelContext, Element); * * // ... * } */ export declare function useModelContext(context: React.Context, model?: T, as?: React.ElementType): T; /** * Compose many hooks together. Each hook should make a call to `mergeProps` which is automatically * done by `createElemPropsHook` and `createHook. Returns a function that will receive a model and * return props to be applied to a component. Hooks run from last to first, but props override from * first to last. This means the last hook will run first, passing `elemProps` to the next last * hook. There is a special exception, which is `null`. `null` means "remove this prop" and the null * handling takes precedence to the first. Take care when using `null` as it will remove props * passed in even from the developer. It can be useful when passing data between composed hooks or * then redirecting a prop somewhere else. * * For example: * * ```ts * const useHook1 = createElemPropsHook(useMyModel)((model, ref, elemProps) => { * console.log('useHook1', elemProps) * return { * a: 'useHook1', * c: 'useHook1', * d: null, // remove the `d` prop * } * }) * * const useHook2 = createElemPropsHook(useMyModel)((model, ref, elemProps) => { * console.log('useHook2', elemProps) * return { * b: 'useHook2', * c: 'useHook2', * d: 'useHook2', * } * }) * * const useHook3 = composeHooks( * useHook1, // run last, will have access to `useHook2`'s elemProps, but can remove a prop with `null` * useHook2 // run first and will override all of `useHook1`'s props * ) * const props = useHook3(model, { c: 'props', d: 'props' }) * console.log('props', props) * ``` * * The output would be: * * ```ts * useHook2 {c: 'props', d: 'props'} * useHook1 {b: 'useHook2', c: 'props', d: 'props'} * props {a: 'useHook1', b: 'useHook2', c: 'props', d: null} * ``` */ export declare function composeHooks

, H2 extends BaseHook, H3 extends BaseHook, H4 extends BaseHook, H5 extends BaseHook, H6 extends BaseHook, H7 extends BaseHook>(hook1: H1, hook2: H2, hook3?: H3, hook4?: H4, hook5?: H5, hook6?: H6, hook7?: H7, ...hooks: BehaviorHook[]): H1 extends BaseHook ? H2 extends BaseHook ? H3 extends BaseHook ? H4 extends BaseHook ? H5 extends BaseHook ? H6 extends BaseHook ? H7 extends BaseHook ? BehaviorHook>>>>>>> : never : never : never : never : never : never : never; export {}; //# sourceMappingURL=components.d.ts.map